pure mrubyで実装されたItamae「itamae-mruby」を作った
itamae-goを作り直してitamae-mrubyを作った
先週Goからmrubyを使ってRubyなしでItamaeレシピを実行できる「itamae-go」を作ったんだけど、全く同じコンセプトの、RubyなしでItamaeレシピを実行できる「itamae-mruby」を作った。
itamae-goの問題点
mrubyは組み込み言語だしこれは本来想定された使い方であり、go-mrubyの実用的な例として普通に作ってよかったと思っているけど、ことItamaeを実装することに関しては以下のような問題があった。
- レシピを読む部分以外をGoで実装していたので、specinfraのコードの移植に手間がかかる
- 主にstandaloneなバイナリを吐く目的にGoが使われているが、mruby-cliでもできるのでGoを使っているメリットがそれほどなく、2つの言語をブリッジするコードを書く労力に見合わない
僕としてはRubyなしで動くItamaeは環境構築の用途にやっぱり欲しいし、ちゃんとメンテし続けたいので保守がしやすいように作り直した。
mruby-cliとは
Goと違ってmruby自体には自分が書いたスクリプトをstandaloneなバイナリにする手段はない(多分)。そこで、mrubyのC APIを使ってmrubyで書いたコードの__main__
メソッドにargvを渡して呼び出すCのコードと、それをクロスコンパイルするDocker環境を提供しているのがmruby-cliである。 なので、mruby-cliを使えばRubyの存在に依存しないバイナリをRubyで書くことができる。
itamae-mrubyの現状
- 現時点で基本的な機能はitamae-goのスーパーセット
- mruby-yamlのクロスコンパイルがうまくいかないので一旦
--node-yaml
は外している
- mruby-yamlのクロスコンパイルがうまくいかないので一旦
- OSX, Arch, Debian, Ubuntuに加えCentOS, Gentooとかもサポートするようにした
- 多分動くけどまだちゃんと検証できてない
- core mrbgemのバグを踏み、eachの中だとresourceが動かなかった
itamae-mrubyの設計
ryotaraiさんがmrubyで実装した奴をItamae 2にしようとか言ってたので微妙に手間をかけて作っている。まあそんな簡単には置き替えられないと思うけど。
- resourceからresourceを実行する部分を分離し役割を減らしている
- ryotaraiさんのアイデアで、actionを実行するのではなく事前状態と事後状態を受けて適用するようにしてみている
- specinfraは移植しやすいよう完全にそのまま
mrubyだけでCLIを実装した知見
mrubyはまだまだ未整備な部分が多くフロンティア感がある。普通にRubyで実装するのとはいろいろ違うところがあったので、そのへんの感想を書いておく。
Rubyにはあるがmrubyに存在しなかったもの
rubygemsが使えないというのがやっぱり大きい。そして標準ライブラリは大体ないし、本家だと言語機能になっている部分がないこともあり、やっていく必要がある。以下に私のやっていきにより生まれたものを書いておく。
mruby-hashie
ItamaeはHashie::Mash
をガッツリ使っているし、社内のレシピでも使われてるのでmrbgemにしておいた。元のコードがMIT Licenseなので、ライセンス表記やauthorsとともに実装をいただいたらほとんどそのまま *1 で動いた。なお、Hashie::Mash
しかない。
@k0kubun ないぞ
— r7kamura (@r7kamura) 2016年7月30日
mruby-shellwords
標準ライブラリ。かなりコマンドをガチャガチャやるので普通に必要だった。Itamaeで必要だったメソッドはそのままのコードで動いた。
mruby-open3
標準ライブラリなんだけど、これを作るのはコピペでは全然動かないし結構大変。まず既存のmrbgemにspawn
がないので、それを自分で書く必要がある。spawn
は本来mruby-processとかで実装すべきだけど、spawn
のオプションをいろいろサポートするのは実装するのは割と大変なので、outとerrオプションを必ずredirectするインチキspawnを内蔵している。
意外とmrubyにも存在したもの
Rubyに比べてしまうともの足りなく感じるけど、mrbgem自体は結構ある。個人的にはmruby-threadとかmruby-tempfileがあるのが助かった。
GitHub - mruby/mgem-list: A list of all GEMs for mruby to be managed by mgem
ファイル名順にソースが読み込まれる
Dir.glob("#{dir}/mrblib/**/*.rb").sort
の順に読まれるので、主に継承が必要な時にファイル名の先頭に数字をつけるみたいなことをやる必要がある。
mruby-requireを使うと綺麗に書けるんだけど、実行時にファイルを探しにいくのでワンバイナリを作る用途では使えなそう。
bundle gemコマンドみたいな奴
あった。便利。
まとめ
Rubyなしで実行したいコマンド作る用途にもmrubyは便利なので、この知見を参考にmrubyを使う人が増えてmrubyのエコシステムがよりよくなってほしい。あとitamae-mrubyもよろしくね
*1:&:sym でto_procする奴がなんか動かなかった。mirbでは動くので多分サポートはされてるんだけどmrbgemの中だとなぜか…。あとでちゃんと調査する