mizdra's blog

ぽよぐらみんぐ

chezmoi を使って VSCode devcontainer 対応 dotfiles を作る

趣味開発で使っている dotfiles をリニューアルした。

github.com

以前までの dotfiles では適切なパスへの設定ファイルの配置や、onetime script の実行タイミングの管理に ansible を使っていた。冪等性を確保するために色々な機能が用意されていて、便利ではあったのだけど、ファイルの配置をするだけで色々なおまじないが必要だったりと、若干冗長だなと感じていた。

あと ansible 自体のインストールにそこそこ時間が掛かるという問題がある。GitHub Actions 上でインストールに掛かる時間を測ったところ、2分くらい掛かっていた。

dotfiles そんなにインストールする機会無いので、今まではそう困ることはなかったけど、VSCode devcontainer との相性が悪くて困っていた。コンテナ起動時にユーザごとの dotfiles を自動でインストールする機能があるのだけど、現行の dotfiles をインストールしようとすると、brew install ansible に 2 分待たされてしまう *1。開発環境はサクッと立ち上がってほしい。

qiita.com

code.visualstudio.com

リニューアル後の dotfiles

まず先に結論、リニューアル後の dotfiles を貼っておく。

github.com

以下はリニューアルにあたっての方針とか、使ったツールの感想について書いていく。

リニューアルにあたっての方針 / chezmoi について

前述の課題を踏まえて、まず ansible をやめることにした。とはいえ ansible でやっていたような設定ファイルの配置や onetime script の実行制御はやはり何かしらのツールに任せたい。軽く調べたところ、 chezmoi というツールが良さそうだったので、これを使うことにした。

www.chezmoi.io

使い方とかは公式ドキュメントに丁寧に書かれているので、ここでは省略する。日本語だと以下の記事でも軽く使い方が紹介されている。

zenn.dev

chezmoi、色々良いところはあるけど、シングルバイナリであることがまず良い。バイナリファイルを DL してくるだけで良いので、インストール時間が短い。GitHub Actions 上だと 2 秒で chezmoi のインストールが完了した *2

あと template 機能がよく出来ている。dot_zshrc.tmpl みたいなファイルを作成すると、テンプレートを使って環境ごとに異なる設定を持つ .zshrc を書くことができる。テンプレートエンジンには text/template が使われているので、{{ if eq .chezmoi.os "darwin" }} みたいに条件分岐したり、{{ template "part.tmpl" . }} みたいに他のテンプレートを展開したりできる。テンプレートは dotfiles をインストールする時 (chezmoi apply) に評価される。

# dot_zshrc.tmpl
{{ if eq .chezmoi.os "darwin" }}
# darwin
export EDITOR="code --wait" # vscode
{{ else if eq .chezmoi.os "linux" }}
# linux
export EDITOR="vim"
{{ else }}
# other operating system
export EDITOR="vi"
{{ end }}

sprig で提供されている関数も使えるので、env で環境変数を参照したりもできる。

# dot_zshrc.tmpl

# devcontainer では anyenv を使わないので、devcontainer 以外でだけ anyenv を初期化する。
# devcontainer では REMOTE_CONTAINERS 環境変数に true が設定されているので、これを使い判定する。
{{- if ne (env "REMOTE_CONTAINERS") "true" }}
eval "$(anyenv init - zsh)"
{{- end }}

こういう形で、環境ごとの違いを上手い具合に吸収できて中々良い。

あと scripts 機能も用意されていて、run_once_ という prefix の付いたファイルを用意すると、今まで実行していないマシンで chezmoi apply した時にだけ実行される script (onetime script) が作れる。もちろんこの機能も template と組み合わせられる。

www.chezmoi.io

VSCode devcontainer 対応

devcontainer では公式が提供している image のほとんどが debian ベースなので、debian に対して対応するつもりで dotfiles を書けば良い。具体的には darwin(macOS) だったら依存パッケージをインストールするのに brew を使うけど、debian だったら apt を使う、みたいなことを template で表現してやれば良い。

github.com

あと devcontainer に dotfiles をインストールするには settings.jsondotfiles.* 系の設定を書く必要がある。設定の名前を見る限りは dotfiles.installCommandsh -c "$(curl -fsLS chezmoi.io/get)" -- init --apply mizdra を設定するだけで良さそうに見えるけど、どうやらここには任意のコマンドは渡せなくて、実行ファイルのパスを書かないといけないらしい。仕方がないので install.sh というシェルスクリプトを用意して、それを dotfiles.installCommand に設定している。dotfiles.repositorydotfiles.targetPath も指定しないといけなかったので、それも指定した。

{
  "dotfiles.repository": "mizdra/dotfiles",
  "dotfiles.targetPath": "~/dotfiles",
  "dotfiles.installCommand": "~/dotfiles/install.sh",
}

github.com

それと、devcontainer ではホストマシンにある .gitconfig がコンテナ内の ~/.gitconfig に自動でコピーされた状態でコンテナが起動されるので、dotfiles で ~/.gitconfig インストールしようとすると、コンフリクトしてコケてしまう。どうしたものかと困っていたけど、.chezmoiignore.gitconfig を書けば ~/.gitconfig のインストールをスキップするよう制御できたので、これで回避した。.chezmoiignore は template として扱われるので、REMOTE_CONTAINERS 環境変数を見つつ、devcontainer の時だけ ~/.gitconfig のインストールをスキップするようにしている。本当にかゆいところに手が届く。

{{- if eq (env "REMOTE_CONTAINERS") "true" }}
# devcontainer は自動でホストの .gitconfig をコンテナ内にコピーするため、chezmoi aplly の対象から外す
/.gitconfig
{{- end }}

github.com

実際に devcontainer + dotfiles 使い始めてみたけど、爆速で開発環境が立ち上がって、かつ普段使っているようなプロンプト (starship) や alias がそのまま使えて、快適に過ごせている。devcontainer を本格的に使える環境が整ったので、引き続き使いつつ、dotfiles を育てていければなと思う。

f:id:mizdra:20220222021608p:plain

*1:CI 上で 2 分だったので、local で動いている docker 上ならもう少し速度出ると思うけど

*2:https://github.com/mizdra/dotfiles/runs/5265645131?check_suite_focus=true の raw logs より

ポケットモンスター・ポケモン・Pokémon・は任天堂・クリーチャーズ・ゲームフリークの登録商標です.

当ブログは @mizdra 個人により運営されており, 株式会社ポケモン及びその関連会社とは一切関係ありません.