実用性はともかく曲芸として個人的に面白かったので共有しておきます。
社内向けのツール、その名もtools
を下記のような要件で配布したくなりました。
- CLI
- gemとして配布
- gem server無し
- バージョンを表示できる
まず、
- gemとして配布
- gem server無し
これは https://github.com/rdp/specific_install を使うとできる。
$ gem install specific_install
$ gem install git@github.com:your-company/tools.git
次に
- バージョンを表示できる
これを実現するにはいくつか課題がある。
-
Tools::VERSION
を更新する- どうせ頻繁に更新されるんだし、いちいちインクリメントするのが面倒くさい。絶対忘れる。
- Gitのcommit hashを出力する
- 当然コミット毎に一意に定まるので頻繁に更新されるツールのバージョニングとしては悪くない。
-
$ tools --sha
で$ git log --pretty="%h" -1
の結果を出せばいいのでは? - gemは
tools.pkg
にファイルをまとめた形で配布される。これはGitリポジトリではないので、git
コマンドは使えない。
ということで、試行錯誤の末、gemspec
の中でTools::VERSION
にcommit hashを文字列リテラルとして更新するコードを生成するという方法で実現しました。gemspec
はRubyのDSLとして実行されるので、その途中でファイルを書くことは可能なのです。
さらに、specific_install
は一時ディレクトリでgit clone
してrake install
しているので、git
コマンドが使える。
下記、具体的な手順です。
元となるファイルはこんな感じでコミットしておく。
lib/tools/sha.rb
module Tools
SHA = "undefined"
end
tools.gemspec
Gem::Specification.new do |spec|
# Update sha.rb
sha = `git log --pretty="%h" -1`.chomp
sha_rb = <<SHA
module Tools
SHA = "#{sha}"
end
SHA
File.open(File.expand_path('./lib/tools/sha.rb'), 'w') { |f| f << sha_rb }
# 以下略
これで$ gem build tools.gemspec
すると
module Tools
SHA = "cd570fa"
end
というふうに最新のcommit hashを代入するコードが生成され、それがGemとしてパッケージングされる。
バージョンを表示するには、このTools::SHA
を適宜出力すればよい。
以上です。もうちょっとまともな方法がある気がするので、妙案があれば是非教えてください。