Hudson CLIの内部構造

id:masanobuimaiさんがHudson CLIの仕組みを調べてくださったので、ここで仕組みをちょっと解説しようかな、と。


CLIは、まずHudsonに2つのHTTPリクエストをします。片方はサーバからCLIにバイト列を送るために使い、もう片方はCLIからサーバにバイト列を送るために使います。(なのでCLIはサーバ上では2つもスレッドを消費するのですが、それはそれ。)


この双方向バイトストリームの上にリモーティングインフラ(hudson.remoting.*)を載せて、これで分散処理環境が出来上がります。ここまで出来たらCLIはコマンドの引数を全部サーバに渡します。この時、stdin/stdout/stderrもサーバに渡します。

なので、見てのとおり、CLI側にはコマンドの知識は何も埋め込まれていません。

Channel channel = ...;
CliEntryPoint cli = (CliEntryPoint)channel.waitForRemoteProperty(CliEntryPoint.class.getName());

r = cli.main(args, Locale.getDefault(),
             new RemoteInputStream(System.in),
             new RemoteOutputStream(System.out),
             new RemoteOutputStream(System.err));
...
System.exit(r);

このcliオブジェクトはサーバへのstubなので「cli.main」はサーバ側で実行されます。サーバ側からは折り返しCLI側へクロージャを送って実行することも出来るので、当然ローカルからリモートへのファイルコピーや、あるいはもっと複雑なことも出来ます。


これらの送られてきたクロージャを実行することで、CLIは万能CLIとなるわけです。


Groovyshではリモーティングの事を考えていない既存のコードをリモート対応させないといけないのでトリッキーですが、例えばloadコマンドの実装を交換してCLI側からファイルをロードする、といった程度であれば非常に簡単に出来ます。