dotfilesの管理は永遠につきまとう課題です。 今まではitamaeを用いて管理し、さらにServerspecによるテストも記述していました。
当時は構成管理を学習していて、実践するためのちょうどいい題材がdotfilesだったという経緯なのですが、dotfiles管理としてはだいぶ重たい構成です。 ライブラリのバージョンなども古くなっていたため、この機会に一新することにしました。
今回はchezmoiを採用しました。 itamaeではERBテンプレートやgitリポジトリ管理の機能を活用しており、類似の機能があることと、ドキュメントも充実していることから選びました。
ちなみに/ʃeɪ mwa/(シェモア、フランス語で「私の家」)と発音するそうです。チェズモイって読んでた……。
導入
任意の方法でchezmoiをインストールし、Quick startの通りに進めていけばOKです。
chezmoi initを実行すると、~/.local/share/chezmoiにchezmoiの管理ディレクトリ(リポジトリ)が作成されます。
chezmoi addでファイルを管理対象に追加し、編集したらchezmoi applyで変更を適用します。
リポジトリへのコミットやプッシュは通常のgitコマンドを利用します。
別のマシンに導入するときは、chezmoi initにリモートリポジトリのURLを与えます。
# ~/.local/share/chezmoiに指定したリポジトリをcloneする
$ chezmoi init https://github.com/shimoju/dotfiles.git
$ chezmoi apply
リモートリポジトリの変更を取り込むには、chezmoi updateが便利です。
$ chezmoi update
# 以下のコマンドと同等
$ cd ~/.local/share/chezmoi
$ git pull
$ chezmoi apply
chezmoiの規約
ファイル名・ディレクトリ名は実際の.foobarではなく、dot_foobarとプリフィックスを用いて管理されます。
パーミッションやシンボリックリンクもプリフィックスとして表現されます。
| 実際のファイル | chezmoiでの表現 |
|---|---|
~/.gitconfig | /dot_gitconfig |
~/.config/starship.toml | /dot_config/starship.toml |
~/.ssh/config(パーミッション600) | /private_dot_ssh/private_config |
~/.symboliclink(シンボリックリンク) | /symlink_dot_symboliclink |
この規約があることからファイルをそのままコピーしてくることはできず、常にchezmoi addを使う必要があります。
もちろん手で規約に沿ったファイル名にすることはできますが、ここは好みの分かれる点かもしれません。
テンプレート
環境によってファイルの内容を変更するためのテンプレートがサポートされています。
ファイルの拡張子として.tmplをつけるとテンプレートとして解釈されます。
たとえば、OSによる分岐は以下のように記述します。
{{ if eq .chezmoi.os "darwin" }}
# macOS
{{ else if eq .chezmoi.os "linux" }}
# Linux
{{ else }}
# その他のOS
{{ end }}
gitリポジトリ管理
Preztoやanyenvといった、git cloneして利用するツールの管理にはchezmoiexternal.tomlを利用します。
以下のように書くことで、chezmoi apply実行時に外部のソースを取り込んでくれます。
gitリポジトリ以外に、URLからのダウンロードにも対応しています。
# ~/.config/zsh/.zpreztoにcloneする
[".config/zsh/.zprezto"]
type = "git-repo"
url = "https://github.com/sorin-ionescu/prezto.git"
refreshPeriod = "168h"
clone.args = ["--recursive"]
# ~/.anyenvにcloneする
[".anyenv"]
type = "git-repo"
url = "https://github.com/anyenv/anyenv.git"
refreshPeriod = "168h"
applyすると毎回ダウンロードされるわけではなく、refreshPeriodで指定した期間が経過していたら再ダウンロードされます。サーバーに余計な負荷をかけずエコですね。
スクリプト
chezmoi apply実行時に任意のスクリプトを実行できる仕組みがあります。
run_プリフィックスがついたファイルがスクリプトとして解釈されます。プリフィックスによってスクリプトの挙動が変わります。
| プリフィックス | 挙動 |
|---|---|
run_ | applyのたびに実行される |
run_onchange_ | 前回の実行時から内容が変化したときに実行される |
run_once_ | ファイルのハッシュ値をもとに一度だけ実行される |
run_once_はファイルのハッシュ値ごとに一度だけ実行します。そのため、以下のように操作したとき、3番目のapplyではハッシュ値が同一となるためスクリプトは実行されません。
run_onchange_であれば実行されます。
- 内容Aでapply:スクリプトが実行される
- 内容Bに変更してapply:スクリプトが実行される
- 内容Aに戻してapply:スクリプトが実行されない
この機能を用いて、brew bundleでパッケージのインストールを実行するようにしました。
run_once_install_homebrew.sh.tmplのように、スクリプトでも拡張子を.tmplとすることでテンプレートが利用できます。
#!/bin/bash
set -e
{{ if eq .chezmoi.os "darwin" }}
read -p 'Install homebrew:'
if [[ ! -x "/opt/homebrew/bin/brew" ]]; then
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
brew bundle --file="$HOME/.Brewfile"
{{ end }}
ファイルの除外
リポジトリには含めたいが適用したくないファイルは、.chezmoiignoreで除外できます。
GitHub用にREADME.mdを配置しつつ、適用対象からは除外するようにしています。
まとめ
これらの機能を活用し、itamae時代とほぼ同等のdotfilesを、より簡潔に構築できました。 完成したリポジトリはshimoju/dotfilesにあります。
他にもパスワードマネージャー経由で秘匿情報を取得し、テンプレートに埋め込む機能もあります。 これを使えば秘匿情報を含むファイルも管理できるので、今度試してみたいです。
これはSmartHR Advent Calendar 2025(シリーズ 1)の7日目の記事です。
6日目はhakoedaさんの「SmartHRに開発組織のイネーブリングユニット「DevEnable」を新設しました」でした。 他の記事もぜひご覧ください!