git-nowをhomebrew本家にpull-requestした、それFormulaについてあれ
たまゆらにでてくるスイーツが毎回おいそうで固唾を飲んでいる今日このごろです。
id:sinsokuさんに許可をいただいて、サブコマンドほげほげしたgit-nowをhomebrewに追加すべくpull-requestを送りました。
https://github.com/mxcl/homebrew/pull/8169
それで当然Formulaを書いたんですが、色々try and errorがあったのでここに書きます。
Formula自体は最終的に以下のようにしました。*1
require 'formula' class GitNow < Formula url 'https://github.com/iwata/git-now.git', :tag => 'v0.1.0.6' version '0.1.0.6' head 'https://github.com/iwata/git-now.git', :branch => 'develop' homepage 'https://github.com/iwata/git-now' def options [ ['--gnu-getopt', "Link a gnu-getopt formula"], ['--zsh-completion', "copy zsh completion function file to $fpath"] ] end # for longopt if ARGV.include? '--gnu-getopt' depends_on 'gnu-getopt' end def install system "make", "prefix=#{prefix}", "install" if ARGV.include? '--gnu-getopt' system "brew ln gnu-getopt" end if ARGV.include?('--zsh-completion') && ENV.include?('FPATH') ENV['FPATH'].split(':').find do |path| system "cp etc/_git-now #{path}" if File.directory? path end end end end
それで以前からも色々迷っていたのがoptionの部分。
Formulaではoptionsメソッドでbrew optionsしたときに表示されるinstall optionのリストを記述できます。あと、そのoptionが指定されているかどうかはARGV.include?で確認できます。
git-nowでは--gnu-getoptと--zsh-completion optionをつけました。
--gnu-getopt
gnu-getoptは以前書いたようにshflagsでlong-optionを使うために必要なものです。
homebrewのgnu-getoptはkeg-onlyなんでdepends_onしただけでは有効にならず、brew link gnu-getoptしないといけないんですがdepends_onと違い、brew linkをFormulaでうまい具合にやる方法がありません。
できる方法とすればsystemメソッドでbrew linkしてやるしかないのですが、それをやってしまうとupgradeとかしたときにも毎回brew linkが走ってエラーになってしまいます。
なので、--gnu-getoptを指定したときだけbrew linkするようにして解決(?)しました。つまり、最初の一回だけ--gnu-getoptすればいいわけですね!
--zsh-completion
git-nowのzsh補完関数をがんばって書きました><(その話はまた別のエントリーで)
なので、brewで補完関数もいれてくれたらいいなぁと思って色々苦心しました…
bashの場合は/usr/local/etc/bash_completion.dができて、Formulaの中ではetcプロバティでこのpathを参照できて、cpしてやればいいわけです。
zshの場合はデフォルトでは/usr/local以下に補完関数のディレクトリは存在しません。zshの補完関数ファイルは$fpathというディレクトリにおくことになっています。
例えばechoで$fpathをみると、
$ echo $fpath /usr/share/zsh/site-functions /usr/local/Cellar/zsh/4.3.12/share/zsh/site-functions /usr/local/Cellar/zsh/4.3.12/share/zsh/functions
このいずれかに補完関数ファイルをcpすればよいということになります。なのでFomulaでは--zsh-completion optionがついたらcpするようにしてます。それで$fpathをFormulaで取得するんですが、ruby 7級のぼくにはよく分かりません><ENV[key]で環境変数を参照できることは分かったんで、ENV['fpath']を試してみると入ってない…orz
zsh fpathでググってみると、どうやらzshrcとかでexport FPATHしないとだめらしい。export書いてENV['FPATH']すると、rubyでFPATHをとれました。FPATHの場合はfpathと違ってコロン(:)区切りなんで、splitして最初にdirectoryの存在が確認されたやつにcpしてます。
exportしてないとFPATHが参照できないため、--zsh-completionしてあってもENV.include?して参照できる場合だけcpしてます。
ちなみに僕は$HOME以下のpathをfpathに追加してるので、そっちにcpされます。
とまあ結構長文になったんですが、まだpull-requestへのレスはきてない*2のでhomebrew install git-nowとかできないんですが、とりこまれたらバージョン管理とかも楽になるかなぁと。といいつつ特にバージョンアップの予定はないんですけどね><
追記 2011/10/21
pull-requestにレスが返ってきたんですが、--gnu-getoptのときにbrew lnしてるところがダメらしくてrejectされました><
じゃあどうすりゃいいんだろ…まあoptionにしてるからいいんじゃないかと思うんですが…
追記2 2011/10/22
zshのFormulaをみるとcompletion functionsディレクトリが#{share}/zsh/functionsになっていたので、--zsh-completionでの動作を以下のように修正しました。
@@ -17,16 +17,18 @@ class GitNow < Formula if ARGV.include? '--gnu-getopt' depends_on 'gnu-getopt' end + if ARGV.include? '--zsh-completion' + depends_on 'zsh' + end def install system "make", "prefix=#{prefix}", "install" if ARGV.include? '--gnu-getopt' system "brew ln gnu-getopt" end - if ARGV.include?('--zsh-completion') && ENV.include?('FPATH') - ENV['FPATH'].split(':').find do |path| - system "cp etc/_git-now #{path}" if File.directory? path - end + if ARGV.include?('--zsh-completion') + zsh_functions_d = share + 'zsh/functions' + zsh_functions_d.install "etc/_git-now" end end
install使っているので、brew removeしたときに一緒にこの補完関数も削除してくれます。
追記3 2011/10/27
最終的なformulaはhttp://d.hatena.ne.jp/mobcov/20111027/1319721530に書いたのでそちらを参照のこと。