読者です 読者をやめる 読者になる 読者になる

OTOBANK Engineering Blog

オトバンクはコンテンツが大好きなエンジニアを募集しています!

dotfilesの設定を自動化する

勉強会

おはこんばんちは!! 尾藤 a.k.a. BTO です。

Unixライクシステムで環境設定に使われる dotfiles。 みなさんはどのように管理しているでしょうか。 dotfiles は単に $HOME に置けば終わりではなくて、外部からとってくるツール類のセットアップもしないといけません。

やり方はいろいろあるかと思いますが、個人的には dotfiles の設定はほとんど自動化しています。 今回は dotfiles 関連のタスクを、どのように自動化しているのか紹介したいと思います。

リポジトリ

リポジトリは、こちらで公開しています。

https://github.com/bto/dotfiles

初期化

dotfiles の初期化は git clone して、make を実行するだけです。 それで dotfiles の設定と、必要なソフトウェアのインストールを行います。

% git clone git@github.com:bto/dotfiles.git
% cd dotfiles
% make

install

スクリーンキャストを見ていただくとわかりますが、dotfiles を $HOME に symlink を張るだけでなく、oh-my-zsh や *env 系のツールのセットアップをしています。 全ての作業を自動化しています。

アップデート

アップデートは make update を実行するだけです。

% make update

update

コマンド一発で、利用している外部ツールが最新の状態になるようにしています。

(GNU)Makeでタスク管理

タスクは全て Make を使っています。 Make を使うのは環境依存性の排除を重視してのことです。 dotfiles のセットアップ時は、環境が整っていない状態なので、なるべくツールの依存関係を少なくしないといけません。 Make であれば、だいたいのUnixライクシステムでは入っていますし、インストールも簡単です。

GNU Autotools の時でもやりましたが、環境依存性を少なくするために、Bourne Shell, Make を使うのは王道です。

Makefile

こちらがタスク管理で使用している Makefile です。

TOP_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
BIN_DIR = $(TOP_DIR)/bin
CONFIG_DIR = $(TOP_DIR)/config
DATA_DIR = $(TOP_DIR)/data
RC_DIR = $(TOP_DIR)/rc
TEST_DIR = $(TOP_DIR)/test
VAR_DIR = $(TOP_DIR)/var

ALL_TARGETS += build
BUILD_TARGETS += initialize
CHECK_TARGETS +=
CLEAN_TARGETS +=
DISTCLEAN_TARGETS += clean
INITIALIZE_TARGETS += install
INSTALL_TARGETS +=
TEST_TARGETS +=
UPDATE_TARGETS +=

include config/Makefile.d/*/var.mk
-include config/var.mk


.PHONY: all
all: $(ALL_TARGETS)

.PHONY: build
build: $(BUILD_TARGETS)

.PHONY: check
check: $(CHECK_TARGETS)

.PHONY: clean
clean: $(CLEAN_TARGETS)

.PHONY: distclean
distclean: $(DISTCLEAN_TARGETS)
  rm -rf $(VAR_DIR)/*

.PHONY: initialize
initialize: $(INITIALIZE_TARGETS)

.PHONY: install
install: $(INSTALL_TARGETS)

.PHONY: test
test: $(TEST_TARGETS)

.PHONY: update
update: $(UPDATE_TARGETS)

include config/Makefile.d/*/task.mk
-include config/task.mk

Makefile

大元の Makefile では具体的なタスクは記述していません。 共通の基本的なタスクの記述のみにとどめて、具体的なタスクは別ファイルから include する形式をとっています。

include config/Makefile.d/*/var.mk
-include config/var.mk
include config/Makefile.d/*/task.mk
-include config/task.mk

上記 Makefile で重要なのは、include している部分です。 config/Makefile.d にある .mk ファイルを自動的に読み込むようになっています。

また config/var.mk, config/taks.mk が存在すれば読み込むようになっていて、何かあったときに、個別の環境で上書きができるようにしてあります。 この2つのファイルは gitignore に追加して、コミットしないようにしています。

config/Makefile.d

config/Makefile.d

config/Makefile.d には、用途単位で個別のディレクトリを作って管理しています。 こうしておくと用途毎に完全にファイルが分かれているので、追加・編集・削除がし易くなります。

config/Makefile.d/oh-my-zsh

config/Makefile.d/oh-my-zsh

例として oh-my-zsh をあげてみます。

OH_MY_ZSH_DIR = ~/.oh-my-zsh
OH_MY_ZSH_REPO = git://github.com/robbyrussell/oh-my-zsh.git

INSTALL_TARGETS += oh-my-zsh-install
UPDATE_TARGETS += oh-my-zsh-update

var.mk

最初の2行で oh-my-zsh の定数の定義をしています。

次の2行で、install, update それぞれのタスクに oh-my-zsh のタスクを登録しています。

* 
.PHONY: oh-my-zsh-install
oh-my-zsh-install: $(OH_MY_ZSH_DIR)

.PHONY: oh-my-zsh-update
oh-my-zsh-update: $(OH_MY_ZSH_DIR)
  cd $< && git fetch -p && git pull

$(OH_MY_ZSH_DIR):
  git clone $(OH_MY_ZSH_REPO) $@

task.mk

task.mk で先ほどの oh-my-zsh-instal, oh-my-zsh-update のタスクを定義しています。

rc

rc ディレクトリには、dotfiles 自体が入っています。 先頭の "." を外したファイル名で管理をしています。

rc ディレクトリを管理するタスクは、config/Makefile.d/rc に登録しています。

結論

オトバンクの近くにはランチがおいしいお店がいっぱいあります。