dotfilesの構成メモ
dotfilesとは端末環境を構成する設定ファイルをリモートリポジトリに集約管理することで環境の再現性を高めるものであり、その概念に基づいて各個人・グループで運用されているリポジトリの総称。dot(.)という名称を冠してはいるが、設定ファイルが隠しファイルの属性を持っている傾向にあるというだけでdot(.)ファイルであることが本質ではない。端末に設定ファイルをインストールする自前のスクリプトや特定の設定復元に特化したOSSツールとセットで運用することで復元を自動化している例も多く見られる。
それらの先例に倣いつつ、以下のコマンドを仮想端末(ターミナル)から実行すると設定を自動復元するdotfilesのスクリプトと設定ファイルの構成について整理してみた。
bash -c "$(curl -L https://raw.githubusercontent.com/takyshu98/dotfiles/master/install.sh)"
前提
- macOS、Linux、WindowsのマルチOSを想定した例もあるが、macOS端末専用の構成とする
- macOS端末にCommand Line Toolsがインストール済みである
スクリプトの構成
個別実行を考慮して設定ドメインを意識した責務分割を行う。
makeコマンドを利用した構成例も見られるが、さほど依存関係は複雑でないため採用は見送る。
install.sh
├──> scripts/defaults.sh
├──> scripts/symlink.sh
├──> brew bundle
└──> mackup restore
install.sh
依存関係の頂点としてHomebrewのインストールとdotfilesのgit cloneおよび各設定ドメイン単位の復元スクリプト(コマンド)をキックする。
#!//bin/bash
set -eu
readonly ARCH_TYPE="$(arch)"
readonly DOTPATH="${HOME}/share/dotfiles"
echo -e "\nInstallation has started...\n"
echo -e "My architecture: ${ARCH_TYPE}\n"
# Install Rosetta 2 for Apple silicon
if [ "${ARCH_TYPE}" = "arm64" ]; then
softwareupdate --install-rosetta --agree-to-license
echo
fi
# Install Homebrew
if ! command -v brew >/dev/null 2>&1; then
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo
fi
# Export brew path to Homebrew Bundle
if [ "${ARCH_TYPE}" = "i386" ]; then
export PATH="/usr/local/bin:${PATH}" # for Intel
elif [ "${ARCH_TYPE}" = "arm64" ]; then
export PATH="/opt/homebrew/bin:${PATH}" # for Apple silicon
fi
# Clone repository
if [ ! -d "${DOTPATH}" ]; then
git clone https://github.com/takyshu98/dotfiles.git "${DOTPATH}"
else
echo "Already downloaded: ${DOTPATH}"
echo "Stash local changes and updating..."
git -C "${DOTPATH}" stash
git -C "${DOTPATH}" switch master
git -C "${DOTPATH}" pull origin master
echo
fi
# Restore macOS settings
"${DOTPATH}/scripts/defaults.sh"
echo
# Make symbolic links and directories
"${DOTPATH}/scripts/symlink.sh"
echo
# Install command line tools and applications
brew bundle --file "${DOTPATH}/Brewfile"
echo
# Restore application settings
mackup -v restore
echo
echo "Installation completed!"
Homebrewのインストール
Homebrewは端末のチップ(Apple シリコン or Intel プロセッサ)によってPATHの通し方が異なるため制御を入れる。(どちらも所有しているため。将来的にはApple シリコンに統一したい)
dotfilesのgit clone
個人運用かつ日常利用は1台のみなので複数端末間の同期性はそこまで求めないが、形式的にリモートリポジトリのmasterブランチをSSOTとする。(mainブランチへ移行予定)
scripts/defaults.sh
macOSのシステム設定をdefaults
コマンドを利用して復元する。
defaults
コマンドのパラメータは公式には公開されておらず名前空間の見通しも良くないため、細かく設定し過ぎるとメンテンナンス性に不安が残るので必要最小限でスタートする方針を取る。(正直なくても良いかもしれないが操作系は即効性があるので採用した)
#!/bin/bash
set -e
echo "==> Configuring Trackpad options..."
# Change cursor speed faster
defaults write -g com.apple.trackpad.scaling -int 3
# Activate tap to click
defaults write com.apple.AppleMultitouchTrackpad Clicking -bool true
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true
defaults -currentHost write -g com.apple.mouse.tapBehavior -bool true
# Activate three finger drag
defaults write com.apple.AppleMultitouchTrackpad TrackpadThreeFingerDrag -bool true
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad TrackpadThreeFingerDrag -bool true
# Activate four finger app expose
defaults write com.apple.dock showMissionControlGestureEnabled -bool true
defaults write com.apple.dock showAppExposeGestureEnabled -bool true
echo "==> Configuring Mouse options..."
# Change cursor speed faster
defaults write -g com.apple.mouse.scaling 3
# Change scroll speed faster
defaults write -g com.apple.scrollwheel.scaling 1
echo "==> Configuring Other options..."
# Deactivate auto capitalization
defaults write NSGlobalDomain NSAutomaticCapitalizationEnabled -bool "false"
# Deactivate auto spell correction
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool "false"
scripts/symlink.sh
${HOME}/share/配下にgit cloneしたdotfiles各設定ファイルへのシンボリックリンク作成および独自ディレクトリの作成を行う。
#!/bin/bash
set -eu
readonly DOTHOME="${HOME}/share/dotfiles/home"
if [ ! -e "${DOTHOME}" ]; then
echo "Error: Directory does not exist: ${DOTHOME}"
exit 1
fi
# Make symbolic links from ~/.* to ~/share/dotfiles/home/.*
for file_path in "${DOTHOME}"/.??*; do
file_name="$(basename "${file_path}")"
if [[ "${file_name}" =~ ^(\.DS_Store|\.config|\.git|\.github|\.gitignore)$ ]]; then
continue
fi
ln -fvns "${DOTHOME}/${file_name}" "${HOME}/${file_name}"
done
# Make symbolic links based on XDG Base Directory specification
[[ -z "${XDG_CONFIG_HOME}" ]] && XDG_CONFIG_HOME="${HOME}/.config"
[[ -z "${XDG_CACHE_HOME}" ]] && XDG_CACHE_HOME="${HOME}/.cache"
[[ -z "${XDG_DATA_HOME}" ]] && XDG_DATA_HOME="${HOME}/.local/share"
[[ -z "${XDG_STATE_HOME}" ]] && XDG_STATE_HOME="${HOME}/.local/state"
mkdir -p "${XDG_CONFIG_HOME}"
mkdir -p "${XDG_CACHE_HOME}"
mkdir -p "${XDG_DATA_HOME}"
mkdir -p "${XDG_STATE_HOME}"
find "${DOTHOME}/.config" -maxdepth 1 ! -name '.config' ! -name '.DS_Store' -exec ln -fvns {} "${XDG_CONFIG_HOME}" \;
# Make directories with reference to Filesystem Hierarchy Standard
mkdir -p "${HOME}/bin" # for original commands
mkdir -p "${HOME}/src" # for code repositories
mkdir -p "${HOME}/tmp" # for temporary workspace
XDG Base Directory Specification
設定ファイルはデフォルトで${HOME}ディレクトリ直下への配置を定められていることが多く、煩雑になる傾向にある。XDG Base Directory Specificationに対応したツールの場合は、${XDG_CONFIG_HOME}(≒ ${HOME}/.config)直下のツール名称に準拠したディレクトリまたはファイル名でそれぞれ配置することができるため見通しが良くなる。
Filesystem Hierarchy Standard
コードリポジトリの格納先をはじめとして、macOSデフォルトのディレクトリ構成ではリソースの収まりの悪さを感じるため、Filesystem Hierarchy Standardに一定の根拠を求めて運用する。
ディレクトリ名 | 用途 |
---|---|
${HOME}/bin | 独自ツールの格納先 |
${HOME}/src | コードリポジトリの格納先 |
brew bundle
AppおよびCLIをHomebrew Bundleを利用してBrewfile
からインストールすることで復元する。
App StoreからDLする必要があるAppについてはmas-cliを利用する。
機械的なメンテナンス性は低下するがbrew bundle dump
の出力結果にコメントを追記することで用途を一定備忘する運用とする。
Brewfileは記載省略
mackup restore
エクスポート・インポートに手動操作が絡むAppの設定をmackupを利用して復元する。
設定はiCloud等のクラウドストレージに保存することも可能であるが、dotfilesで一元管理したいためengine = file_system
を選択してdotfiles内にエクスポートするようにしている。
当初はiTerm2の設定復元を主な導入目的としていたが、XDGで設定管理できるWezTermに乗り換えたため、それほど必要ではなくなった。
# @file ~/.mackup.cfg
# ref:
# https://github.com/lra/mackup/tree/master/doc
[storage]
engine = file_system
path = share/dotfiles
directory = home
[applications_to_sync]
# iTerm2
karabiner-elements
設定ファイルの構成
dotfiles/homeディレクトリを端末の${HOME}ディレクトリと対称関係に位置付けることで設定ファイルと直接関係のないインストール用途のファイル群との区別を明確にする。
dotfiles
└── home
├── .config
│ ├── xxx
│ └── zsh
│ └── .zshrc
├── .xxx
└── .zshenv
ログインシェル(zsh)の設定
前述の${ZDOTIDIR}やプラグイン管理で分割が発生するため個別に整理する。
ログインシェルに求める設定をおおまかにカテゴライズし、ライフサイクルを考慮したうえでどの設定ファイルに定義を振り分けるかを記載した。
プラグイン管理にはXDG Base Directory Specificationに対応しており、かつ起動が高速であると評判のsheldonを採用した。
設定カテゴリ | 設定ファイル | プラグイン名 |
---|---|---|
ロケール | ${HOME}/.zshenv | - |
PATH | ${HOME}/.zshenv | - |
プラグイン管理アクティベート | ${HOME}/.config/zsh/.zshrc | - |
入力補完 | ${HOME}/.config/zsh/.zshrc | - |
↑↑↑ | ${HOME}/.config/sheldon/plugins.toml | zsh-users/zsh-completions |
↑↑↑ | ${HOME}/.config/sheldon/plugins.toml | zsh-users/zsh-syntax-highlighting |
↑↑↑ | ${HOME}/.config/sheldon/plugins.toml | zsh-users/zsh-autosuggestions |
ディレクトリ移動補助 | ${HOME}/.config/sheldon/plugins.toml | b4b4r07/enhancd |
エイリアス | ${HOME}/.config/sheldon/plugins.toml | olets/zsh-abbr |
プロンプト | ${HOME}/.config/sheldon/plugins.toml | starship |
コマンド履歴管理 | ${HOME}/.config/zsh/.zshrc | - |
仮想環境アクティベート | ${HOME}/.config/zsh/.zshrc | - |
全体の構成
総合するとdotfiles全体の構成は以下の通りとなった。
dotfiles
├── home
│ ├── .config
│ │ ├── git
│ │ │ └── config
│ │ ├── karabiner
│ │ │ ├── assets
│ │ │ ├── automatic_backups
│ │ │ └── karabiner.json
│ │ ├── mise
│ │ │ ├── config.toml
│ │ │ └── settings.toml
│ │ ├── sheldon
│ │ │ └── plugins.toml
│ │ ├── starship.toml
│ │ ├── tmux
│ │ │ └── tmux.conf
│ │ ├── wezterm
│ │ │ └── wezterm.lua
│ │ └── zsh
│ │ └── .zshrc
│ ├── .mackup.cfg
│ └── .zshenv
│
├── install.sh
├── scripts
│ ├── defaults.sh
│ └── symlink.sh
└── Brewfile
Discussion