本記事では、単一シェルスクリプトのタスクランナー makesure を紹介します。
インストールは wget 1回で完了し、/bin/sh と awk さえあれば動きます。依存ゼロ・単一ファイルなので、リポジトリルートに makesure と Makesurefile を置くだけで動作します。
makesureとは
makesure は、sh と awk で実装されたタスクランナーです。make に似た構文で、@goal(タスク)の依存関係を自動解決します。
最大の特徴は @reached_if ディレクティブによる冪等性チェックです。条件が満たされていれば、そのタスクの実行をスキップします。
| ディレクティブ | 役割 |
|---|---|
@goal |
タスク(ゴール)を定義する |
@depends_on |
依存するゴールを指定する(宣言的、1回だけ実行) |
@calls |
依存するゴールを指定する(命令的、実行時に評価) |
@reached_if |
達成済みか判定する条件を書く |
@define |
変数を定義する(環境変数のデフォルト値として使える) |
@lib / @use_lib
|
関数をゴール間で共有する |
@doc |
ゴールの説明文を付ける(--list に表示される) |
@options |
timing などの実行オプションを指定する |
@shell |
ゴール本体を実行するシェルを指定する(bash/sh) |
インストール
wget https://raw.githubusercontent.com/xonixx/makesure/main/makesure
chmod +x makesure
リポジトリのルートに makesure を置き、./makesure として実行します。
以下、makesure を使ってタスクを定義・実行する様子を実例で示します。
Hello World で動かす
Makesurefile という名前でファイルを作ります。
@goal hello
echo "Hello, makesure!"
@goal setup
@reached_if [ -f /tmp/done.txt ]
echo "setup を実行中..."
touch /tmp/done.txt
echo "done"
実行します。
./makesure hello
goal 'hello' ...
Hello, makesure!
@reached_if の動作を確認します。1回目は実行され、2回目はスキップされます。
./makesure setup
goal 'setup' ...
setup を実行中...
done
./makesure setup # 2回目
goal 'setup' [already satisfied].
ゴール一覧は --list で確認できます。
./makesure --list
Available goals:
hello
setup
実用例: 初期設定リポジトリでマシンをbootstrapする
新しいマシンに makesure と Makesurefile の2ファイルだけを置き、./makesure を実行すると環境構築が完了する、というbootstrapを作ります。流れは次のとおりです。
- eget を入手する(GitHub Release からバイナリを取得するツール。使い方はこちら)
- eget で mitamae と gix を入れる
- gix で初期設定リポジトリをクローンし、mitamae で設定を適用する
mitamae は mruby 組み込みの構成管理ツールで、Ruby で書いた設定を単一バイナリで適用できます(詳細は)。gix は Rust 製の Git 実装で、単一バイナリで git clone できます。設定(default.rb)を書いた初期設定リポジトリを用意しておけば、あとはmitamaeがデプロイ作業を実施します。
ツールはすべてカレントディレクトリに置きます。各ツール取得ゴールは @private にして、ユーザーが直接呼ぶ setup ゴールだけ一覧に見せます。URL は自分の初期設定リポジトリに置き換えてください。
@define URL "${URL:-https://github.com/USER/setup}"
@lib
fetch() { ./eget "$@" --to .; }
@goal eget @private
@reached_if [ -x ./eget ]
V=$(curl -fsSI https://github.com/zyedidia/eget/releases/latest \
| sed -nE 's#.*/tag/v?([^ ]+).*#\1#p' | tr -d '\r')
O=$(uname -s | tr A-Z a-z)
A=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
curl -fsSL "https://github.com/zyedidia/eget/releases/download/v$V/eget-$V-${O}_$A.tar.gz" \
| tar xzO '*/eget' > ./eget && chmod +x ./eget
@goal mitamae @private
@depends_on eget
@use_lib
@reached_if [ -x ./mitamae ]
fetch itamae-kitchen/mitamae --asset mitamae --asset ^debug
@goal gix @private
@depends_on eget
@use_lib
@reached_if [ -x ./gix ]
fetch GitoxideLabs/gitoxide --asset lean --asset ^universal --file gix
@goal setup
@depends_on mitamae gix
M="$PWD/mitamae"
rm -rf setup
./gix clone "$URL" setup
cd setup && "$M" local default.rb
@goal default
@depends_on setup
makesure と Makesurefile だけがある状態から実行すると、設定が適用されます。
URL=https://github.com/自分のユーザー名/setup ./makesure
まとめ
-
wget1回でインストール完了、/bin/shとawkのみで動く -
@reached_ifによる冪等性チェックがmakeとの最大の違い -
@lib/@use_libで関数を共有し、@defineで環境変数のデフォルトを管理できる