μログ

ゆるく日常と技術について書きたい

devcontainerにStarshipをインストールするメモ

 devcontainer環境でもStarshipを使いたかったのですが、シェル・ワンライナーへの理解が乏しくてインストールに苦戦したのでメモを書き残しておきます。

TL;DR

devcontainerのDockerfileに以下のコマンドを書くことでインストール可能です。

RUN curl -sS https://starship.rs/install.sh | sh -s -- --yes

なんで苦戦したか

 通常、LinuxStarshipをインストールするには以下のワンライナーを実行するのですが、インストールの過程でインタラクティブな入力が求められます(よくパッケージのインストール時に[y/N]が表示されて続行するにはyを入力する必要があるヤツ)。

starship.rs

curl -sS https://starship.rs/install.sh | sh

 今回の場合、devcontainerのビルド中、つまりdocker buildの実行中にインタラクティブな入力が求められるため、自動でyを入力してくれるようにする必要がありました。aptyumといったパッケージマネージャーを使ったインストールの場合は、-yをオプションとして指定することでインタラクティブな入力を求められずに済みます。

今回も同じようにオプションを指定したかったのですが、上記のワンライナーではStarshipのインストールスクリプトcurlで取得して、shに標準入力として渡して実行しています。インストールスクリプトのソースを見てみると、実行時にオプションで-f, -y, --force, --yesのいずれかを渡すとインタラクティブな入力がスキップされると書かれています。

https://github.com/starship/starship/blob/c40f0e7722dc4cf23dac4f19061d1342e4792002/install/install.sh#L142

なるほどと思い、以下のようにDockerfileに記載してdevcontainerを起動したのですがエラーになりました。

RUN curl -sS https://starship.rs/install.sh | sh --yes

この指定ではインストールスクリプトではなくshコマンドのオプションとして-yが渡されてしまうためです。

sh: 0: Illegal option -y

解決

 適当に「devcontainer starship」で検索したら、以下のコードを発見しました。

https://gist.github.com/jarrodldavis/928c90036273a557848f4c73d5d4e701#file-vscode-devcontainer-sh-L35

Dockerfileではないですが、ファイル名的にdevcontainerにStarshipをインストールするスクリプトのようだったので、bash -s -- --yesの意味を調べてみました。man bashを見ると以下のことが書いてあります(一部抜粋)。

--        -- はオプションの終わりを示し、それ以降のオプション処理を行いません。 -- 以降の引き数は全て、ファイル名や引き数として扱われます。 引き数 - は -- と同じです。
-s        -s オプションが指定された場合と、 オプションを全て処理した後に引き数が残っていなかった場合には、 コマンドは標準入力から読み込まれます。 このオプションを使うと、 対話的シェルを起動するときに 位置パラメータを設定できます。

 どうやら、-- --yes--yesをオプションではなく引数として扱うという意味で、-s -- --yesとすることで引数--yesを標準入力として読み込むという意味だと思われます。これにより、Starshipのインストールスクリプトのオプションとして--yesを渡すことができているという認識です(間違っていたらコメントいただけるとうれしいです)。

Starshipの公式インストールワンライナーではbashではなくshで実行するようになっていたのでそこだけ変更して実行するとうまくいきました(shコマンドでもオプションの意味は同じです)。

RUN curl -sS https://starship.rs/install.sh | sh -s -- --yes

最後に

 今回はDockerfileにStarshipのインストールを定義して不変的なイメージにしたかったので苦戦しましたが、devcontainerにStarshipをインストールして使うだけであれば、devcontainerの起動後にStarshipのインストールスクリプトを実行すれば問題ないです。また、devcontainerのpostCreateCommandを使うとコンテナビルド時の初回のみインストールスクリプトが実行されます。