タスクランナーを作る
背景
タスクランナーとビルドツールとの混交
伝統的なビルドツールといえばMakeだが、きょうびのウェッブエンジニアリングでは専らタスクランナーをさせられている零落したかわいそうな子
おまえらは単純なコマンドも覚えられずに楽をしたがる
それはただのエイリアス
おまえらはたまに依存関係を要求する
ようやくMakeの仕事になるが、成果物レベルの依存関係ではなくタスクレベルの依存関係だったりするし、それでいてnpmなんかを使っている
主張
あらゆるタスクランナーは最終的にチューリング完全汎用プログラミング言語を再発明するか、または、ホスト言語の表現力不足により使えない
人類は分岐して繰り返ししたくなる
ゆえに、最初からプログラミング言語にしておいたほうがよっぽどマシ
TOMLで書けます!みたいなのは失敗する運命にある。それだと簡潔に書けないじゃないかというのはホスト言語の表現能力の問題であって、複雑なタスクは記述も複雑になるに決まっている。その複雑性を受け入れられない言語なのが悪い
能力を制限した言語は、つまるところ木構造でしかない。木構造以上のものをやろうとした瞬間にそれはプログラミング言語になる。そして実業務におけるビルドプロセスやタスクが単純な木構造になった試しなどない、もしくはそのあまりの平坦さに人間が耐えられないのである
条件付きビルドがやりたくなるから
並列実行したくなるから
同じ構造を延々と書くハメになるから
タスクと言っているがお前らが定義しているのはプロセスであって、それをタスクと言って単純化しているのが間違い
しかし、わざわざプログラミング言語は設計したくない
作者「ダルい」
おまえら「覚えらんねーよ」
しかし、わざわざスクリプトは書きたくない
正確には、それに必要なツールキットの用意(shellどうやって起動するよ)や、プログラムの実行環境の構築がダルいという話
強い静的型付け言語のeDSLとしてタスク記述言語を実装する
eDSLにすることで
静的に型がつく
安心安全
強い型推論能力があれば便利
先行事例: Chisel
まともな挙動になることの責任を言語開発チームに押し付けられる
エラーメッセージの出力などを任せられる
問題
eDSLにしたところでその言語の実行環境はどうするの
Scalaだとコンパイラを同梱してそいつにその場でコンパイルさせられる
餅は餅屋、EPFL謹製の最強のコンパイラを見せてやれ
Javaはまぁそこにあるでしょ
Rustの環境作るのと変わんねぇよ
タスクランナー自体はFat Jarにすればいい
コンパイルしたやつを実行するということは、動的にロードして呼び出しをする、すなわちリフレクションするので、GraalVMにするのはダルそうだし、そもそもコンパイラ自体がNative対応してない気がする
タスク定義ファイルとかのhashを覚えておけばインクリメンタルになんとかなるでしょ(適当)
本当に動くのか?
汎用言語なので、要するにまともなwrapper、Prelude libraryを書けるかにかかっている
いかに直交した機能を提供できるかがミソ
困ったらScala 3のコードに逃げられる、というのが大事。脱出ハッチあります
タスクランナーとして最低限必要そうなもの
シェルを起動する機能
素朴にos-libを利用すれば大抵のことはできる
出力をミュートするとか、そういうカスタマイズはメソッドチェインでできればいい
終了コードみたいな特殊変数って本当に必要?
val result = ...みたいにしてresult.codeみたいにしたほうが良いのでは・・・
特殊変数は文脈を作ってしまうし、AIに向かない
一方で、名前が消えるのでコピペはしやすい
文脈といえば、そのコマンドが失敗したらタスクを中止しないといけないので、いずれにせよ文脈はある
sh"ls -l" | stdoutみたいにフィルタみたいにすると良いのかしら
良い抽象化が欲しいところ
フィルタ+結果が入るスロット
そもそもコマンドを呼び出すということ自体、外界に対する副作用を求めてやっている
CLIから呼び出せる
依存性を定義する機能
名前をつける機能
簡単に定義できたい
成果物依存
あったらうれしいね
並行/並列実行
階層型タスク
サブディレクトリのタスクを自動認識する
キャッシュ