Hiratake Web ロゴ

chezmoiでdotfilesを管理する

投稿した日
更新した日
書いたひと
icon
ひらたけ

.zshrc.bashrc など、ホームディレクトリに存在している ドットから始まるファイル群を管理するリポジトリ として「dotfiles」というものがあります。毎日使うターミナルの設定などを記述したファイルをぶち込んで GitHub 等に置いておくことで パソコンを買い替えたり増やしたりしたときに自分用にカスタマイズした環境を素早く構築できる ようにするものです。

世界中のエンジニアが様々な dotfiles を公開しており、それらを参考にしながら、また時代の変化や自分自身の興味関心、そして成長などに合わせて 世界にひとつだけの自分専用オリジナル dotfiles を育てていきます。そんな dotfiles を管理するためのツールとして chezmoi というもの があり、こちらを利用して dotfiles を作ったので、備忘録的な感じで書いていこうと思います。

作ったもの

macOS と Windows Subsystem for Linux(以下 WSL)で利用できる dotfiles を作りました。

README に記載しているインストール用コマンドを実行すると、.zshrc.bashrc などのドットから始まるファイル群がホームディレクトリに配置されます。また、Volta 経由で普段のフロントエンド開発などで使用する Node.js をインストールしたり、macOS の場合は LimaDocker を使えるように環境をいい感じにしたりと、ファイルを配置するだけでなく必要なツールのインストールやセットアップもやります。

dotfiles を作る

さっそく chezmoi を使って dotfiles を作っていきます。

chezmoi をインストールする

ドキュメント に記載されているコマンドを実行して chezmoi をインストールします。Windows なら winget や scoop、macOS なら brew コマンドでもインストールが可能ですが、今回は「One-line binary install」にあるコマンドを実行してインストールしました。

sh -c "$(curl -fsLS get.chezmoi.io)"

インストール後、chezmoi --version コマンド等を実行して、コマンドが動作するかを確認します。

dotfiles リポジトリを作成する

まずは chezmoi で管理する dotfiles リポジトリを作成します。以下コマンドを実行して、新しい Git リポジトリを作成します。

chezmoi init

コマンドを実行すると、~/.local/share/chezmoi にリポジトリ(以下「dotfiles リポジトリ」)が作成されます。このディレクトリに .zshrc.bashrc といった複数のマシンで共有したいファイルを追加 していきます。

ファイルを追加する

dotfiles リポジトリへファイルを追加する方法は 2 種類あります。ひとつは既にマシン上に存在する .zshrc.bashrc などのファイルを dotfiles リポジトリ へ追加するコマンドを実行する方法。もうひとつは、直接 dotfiles リポジトリを編集する方法です。

まずは前者について。たとえば、現在使っているマシンにある ~/.zshrc ファイルをそのまま他のマシンでも使用できるようにしたい場合は、以下のコマンドを実行すると ~/.zshrc が dotfiles リポジトリにコピーされます。

chezmoi add ~/.zshrc

ドットから始まるファイルを追加した場合は自動的に .dot_ へと置き換えられ、.zshrc の場合はファイル名が dot_zshrc となります。追加したファイルを編集する場合は以下コマンドを実行します。

chezmoi edit ~/.zshrc

続いて後者の直接 dotfiles リポジトリを編集する方法。~/.local/share/chezmoi にある dotfiles リポジトリを VSCode などのエディタで直接開いてファイルを追加したり編集したりします。今回は基本的にはこちらの方法で編集を行います。

リポジトリを開き、複数のマシンで共有したいファイルを追加していきます。新しいファイルやディレクトリを作成する際、コマンドでのファイル追加でコピーされるファイルと同様に、ドットから始まるファイルやディレクトリの場合は 先頭の .dot_ に置き換えて作成 する必要があります。

作成するファイルやその内容については、人それぞれ内容が異なるので割愛。作成する際に利用できる便利な機能について、以下にいくつか紹介します。

ルートディレクトリを変更する

dotfiles リポジトリを GitHub 上で公開する場合、dotfiles リポジトリのルートに README.md ファイルを作成するなどしたくなります。他にも、エディタの設定ファイルなどを置くことがあるかもしれません。

そのまま置いてしまうと、他のマシンで chezmoi を使って dotfiles を展開した際に、そのマシンのホームディレクトリに README.md ファイルなども一緒にコピーされてしまうことになります。邪魔です。

その場合、dotfiles リポジトリのルートに .chezmoiroothome/ ディレクトリ(名前は任意)を新たに作成し、.chezmoiroothome と書いておくことでルートディレクトリを変更することができます。

home

上記の例の場合、これまでは ~/.local/share/chezmoi/dot_zshrc~/.zshrc に相当するファイルでしたが、これが ~/.local/share/chezmoi/home/dot_zshrc に変更されます。dotfiles リポジトリのルートにファイルがズラズラと並んでいるのが見づらくて嫌だという場合にも便利です。

テンプレートを使う

chezmoi にはテンプレート機能というものが用意されており、これを利用することで マシンの OS に応じて設定内容を出し分けるなどの条件分岐が可能 になります。

テンプレートの機能を利用するには ファイルの拡張子を .tmpl へと変更 します。たとえば dot_zshrc なら dot_zshrc.tmpl へと変更する、といった感じです。これでファイル内でテンプレートの機能が利用可能となります。

テンプレートは機能が豊富すぎて私も全容を把握できていないのですが、たとえば OS が macOS か Linux かで内容を変えたい場合には以下のように記述することで実現が可能です。

{{ if eq .chezmoi.os "darwin" }}
# macOS
{{ else if eq .chezmoi.os "linux" }}
# Linux
{{ else }}
# Other
{{ end }}

.chezmoi.os は chezmoi が用意している 変数 で、OS の情報が代入されています。他にも様々な情報を取得することができる変数や、便利な関数などが用意されているのでドキュメントを参照してください。

インタラクティブな入力をする

たとえば、自宅のパソコンと職場のパソコンで同じ dotfiles を使いたいとします。dotfiles リポジトリに Git の設定を記述した .dot_config/git/config ファイルを作成し、dotfiles を展開した際に ~/.config/git/config に配置されるように設定すると、たしかに Git の設定を異なるマシンの間で揃えることができるのですが、困ることがあります。

そのままだと、Git の設定にある user.emailuser.name が同じ値になってしまい、SNS で使っているハンドルネームが職場に大公開されてしまう…なんてことが起きてしまうかもしれません。

chezmoi では dotfiles を適用するときに「ユーザ名を入力してください」のように入力を要求 し、それをファイルへ出力することも可能です。これを使えば、自宅のパソコンで使用するときには Git の user.name にハンドルネームを、職場のパソコンでは本名を指定する、といったことが実現できます。

まずは dotfiles リポジトリのルート(もしくは .chezmoiroot で指定した場所)に .chezmoi.yaml.tmpl ファイルを作成します。今回は YAML 形式で作成しましたが、JSON 形式や TOML 形式でも記述が可能です。

このファイルの使い方としては 全体で共通して使用する変数を定義 したり、今回のように ユーザに入力を要求して入力された値を変数として呼び出せるようにする のに使用できます。以下のように記述すると、.tmpl ファイル内で入力されたメールアドレスを .email という変数で使用することができるようになります。

{{ $email := promptStringOnce . "email" "What is your email address" -}}

data:
  email: {{ $email | quote }}

$hoge のように変数を定義し、最後の data に含めたものが他のファイルで変数として呼び出せるような感じです。これを利用して、.dot_config/git/config.tmpl に以下のように書いておけば、マシンごとに異なるメールアドレスと名前で Git のコミットができるようになります。

[user]
  # Specify the email address of the author/committer.
  email = "{{ .email }}"

  # Specify the username of the author/committer.
  name = "{{ .name }}"

スクリプトを書く

.zshrc.bashrc などの必要なファイルが作成できたら、dotfiles のリポジトリとしてはほぼ完成となります。GitHub などに push して、他のマシンから呼び出せば、同じ .zshrc.bashrc がホームディレクトリに作成されます。

必要なファイルを新しい環境に素早く用意できるだけでも非常に便利なのですが、楽をしたがる生き物であるエンジニアは「どうせなら開発環境の構築もまとめてやってしまいたい」「Node.js のインストールや Docker 環境の構築なんかもコマンドひとつで終わらせたい」みたいなことになりがち。そんなときに便利なのが スクリプトの機能 です。

簡単に説明すると、chezmoi でファイルを展開する際に 任意のスクリプトを実行できる というもの。dotfiles リポジトリ内に run_run_once_ といった名前から始まるスクリプトを置いておくと、自動的に実行してくれます。

run_ は dotfiles を適用する度に実行され、run_once_ は初回の実行かスクリプトの内容を変更した場合に実行されます。複数のファイルを置いた場合には、ファイルの名前順で実行されます。また、run_before_ のように before_ を付けた場合には各 dot_ ファイルがホームディレクトリに配置される前、after_ を付けた場合にはホームディレクトリに配置された後に実行されます。

dotfiles リポジトリ内の他のファイルと同じ階層に配置しても良いのですが、.chezmoiscripts/ というディレクトリを作成してまとめることも可能なので、今回はこちらの方式を採用しました。

macOS で Homebrew をインストールする

スクリプトの例として、macOS で dotfiles を展開した際に Homebrew をインストールするスクリプトを用意してみます。.chezmoiscripts/ 内に run_after_darwin.sh.tmpl というファイルを作成してシェルスクリプトを記述します。

このファイルは run_ なので、初回に限らず dotfiles を適用する度に実行され、after_ なのでホームディレクトリには既に .zshrc.bashrc などのファイルが存在している状態です。

#!/bin/bash

# macOS の場合のみ実行する
# {{- if eq .chezmoi.os "darwin" }}

if command -v brew >/dev/null 2>&1; then
  printf -- "%sHomebrew already installed, skipping.%s\n"
else
  /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

  # {{- if eq .chezmoi.arch "arm64" }}
  eval "$(/opt/homebrew/bin/brew shellenv)"
  # {{- else }}
  eval "$(/usr/local/bin/brew shellenv)"
  # {{- end }}
fi

# {{- end }}

上記のスクリプトでは、{{- if eq .chezmoi.os "darwin" }}{{- end }} で囲むことで、macOS の場合のみスクリプトが実行されるようにしています。

ファイル名が run_ から始まる場合は dotfiles の適用の度に毎回実行されることになるので、brew コマンドが存在しなければ Homebrew のインストールを実行、既にコマンドがあればスキップしています。この部分は好みに応じてファイル名を run_once_ にするなどの検討をしても良いでしょう。

Homebrew では、Apple Silicon CPU か Intel CPU かによってインストール後に必要なコマンドが微妙に異なります。なので、.chezmoi.arch から CPU のアーキテクチャを取得して分岐させています。

dotfiles を使用する

作成した dotfiles を使用する場合は、以下のようなコマンドを実行します。Hiratake となっている箇所にはリポジトリを作成した GitHub のユーザ名を指定します。

sh -c "$(curl -fsSL get.chezmoi.io)" -- init --apply Hiratake

実行すると、ホームディレクトリにドットから始まるファイル群が配置され、各種ツールのインストールやセットアップのコマンドが実行され、あっという間に自分だけのターミナル環境が整います🎉


chezmoi のおかげで、いい感じの dotfiles を整備できて良かったです。使用する OS によって実行する内容を分けたり、ファイル内の記述を出し分けたりするのは、シェルスクリプトなんもわからんな私には難しいので、そういった部分をやってくれるのは非常に助かります。

dotfiles は一度作ったらそれでおしまい、というものではありません。時代の変化によって使うツールが別のものになったり、新たなプログラミング言語が登場してその環境を整備することになったり、エンジニアとして成長して過去の自分が書いた dotfiles のコードよりも良いコードを書けるようになったり。

そんな様々な変化に応じて、育てていく。そういうものだと思うので、私も世界にひとつだけの dotfiles を育て続けていきたいと思います。