今の進捗↓
- コマンドの実行を実装
- 変数を利用できるようにした
- cmd1 && cmd2 と cmd1 || cmd2を実装
- if/unless/while/until/for文を実装
- コマンド履歴機能を有効化
- Rust 1.56.0 / 2021 editionを使うようにした
最低限の機能を実装したので少しはシェルっぽくなってきた。
ここらへんの実装は今まで作ってきた機能の組み合わせになってくるので作っていてとても楽しい。
パイプやバックグラウンド実行、各構文のリダイレクト機能は めんどうでまだ実装になっている。
コミット
- 8372810 Implimented And/Or connecter
- 74dd516 Implement for command
- d184632 Handle variables
- ad9f0c7 Enable command history
- e9bfb97 Rename command to exec
- e925af8 Bump up to rust 2021 edition
- cce7e36 Remove libc
- 294bf4a Improve syscall test
- 8d831b1 Rename wrapper to syscall
- 6629dbd Implement if/unless/while/until command
- 50b4f70 Improve error handling
システムコールのテスト
コマンドを実行するときのfork/waitpid/execveや、リダイレクトの処理をするopen/dup2/closeなどシステムコールをする部分がある。 これらをテストするのは副作用があるため非常に大変である。 色々考えた結果mockallを使ってモックすることにした。
通常のコードとモックコードを使い分けするためにWrapperという構造体を一枚噛ませている。 cfg(test)のときはこのWrapperはMockSysCallWrapperのaliasとしている。 このMockSysCallWrapperはコード上には定義がないがmockallが自動的に定義する構造体になっている。
Rust 1.56.0 / 2021 edition
10/21にRust 1.56.0がリリースされた 🎉
reddish-shellも早速Rust 1.56.0 / 2021 editionを使うように変更した。 幸い影響を受けるようなコードを書いてはいなかったのですんなりアップデートできた。
次の実装
簡単なコマンドの実装ができたので、パイプやシェル構文のリダイレクト、バックグラウンド実行とジョブコントロールあたりを実装しようかと思っている。
パイプの実装はパイプをつなげているコマンドの実行順序に気をつければすんなり実装できるはず・・・はず。
これを実装すると副次的にコマンド置換(command
とか $(command))とかも実装できるはず。
シェル構文のリダイレクトは少しめんどくさくて、通常のコマンドのリダイレクトはforkしているので設定したリダイレクトのあとのことを考える必要がないのだけど、シェルの構文の場合シェルと同じプロセス内で実行するのでリダイレクト処理をするとそのまま残ってしまい後続の処理に影響がでてしまう。 なので、構文の実行が終わったらリダイレクト処理を元に戻すかなにかしないといけない。
バックグラウンド実行はwaitpidしなければいいだけの話なのだけど、そうなるとゾンビプロセスになってしまう。 waitpidにWNOHANGをつけてチェックするか、スレッドなりでwaitpidするのが良いのかなぁっと思う。 そうなってくると、それらのスレッドを管理するジョブコントローラーが必要になってくる。 ついに、Rustで非同期処理を書く必要がでてくるという感じ。