シェルスクリプトで ctrl + C を押して中断したときのクリーンアップ処理を書くのはそこそこ大変です(頑張ればできますが)。今回は zx を使った、クリーンアップ処理を含むコードの書き方を紹介します。
そもそも zx とは?
alt シェルスクリプト的なものです。JS ファイル内にシェルスクリプトを書くことができます。
import { $ } from 'zx'; const has = (command) => $`type "${command}" > /dev/null 2>&1`.then(() => true, () => false) if (await has('rbenv')) { await $`rbenv init -`; }
…まあ上のコードが読みやすいかはともかく、 async/await が使えたり、JS の各種メソッドが使えるので非常に便利です。
zx を使って SIGINT を捌いてみる
この processWithCleanup という関数を使ってコードを書いていきます。
import { $ } from 'zx'; import process from 'process'; const processWithCleanup = async (f, cleanup) => { process.on('SIGINT', () => {}); try { await f(); } catch (e) { await cleanup(); throw e; } };
この関数は、受け取った関数 f を実行し、SIGINT を受信したら cleanup を実行します(SIGINT かどうか判別してないですが)。cleanup 後に throw e しているので、このあとどう処理するか任せることができます。
実例
const main = async () => { await processWithCleanup( async () => { await $`git stash`; await $`docker build -t hoge ./`; }, () => $`git stash pop` ); $`git stash pop`; await $`docker push hoge`; await $`deploy`; }; main().catch(console.error);
この例ではビルドして Docker Hub へプッシュし、最後にデプロイコマンドを実行します。ビルド中にエラーが起きたらデプロイは走りません。