buildbotが作成する、バイナリインストール用gemのファイル配置がおかしいのを直した
いやー、けっこう手間取ってしまった。長く苦しい戦いだった……
潜在的にはすごく前からの問題だったけれど、先日にportgroupを使ったgemのインストールを改善した(r112446)際に影響を受けやすくなってしまった。
現象
件の変更(10/23)移行にbuildbotが作成した、gemのportの配置がおかしくなっている。たぶん対象は3件。
バイナリインストール。
% sudo port -n upgrade --force rb-pkg-config : % port contents rb-pkg-config Port rb-pkg-config contains: /opt/local/lib/ruby/gems/cache/pkg-config-1.1.4.gem /opt/local/lib/ruby/gems/doc/pkg-config-1.1.4/rdoc/classes/PKGConfig.html :
ソースから手元でインストール(-s)。
% sudo port -ns upgrade --force rb-pkg-config % port contents rb-pkg-config Port rb-pkg-config contains: /opt/local/lib/ruby/gems/1.8/cache/pkg-config-1.1.4.gem /opt/local/lib/ruby/gems/1.8/doc/pkg-config-1.1.4/rdoc/classes/PKGConfig.html
ということで、
/opt/local/lib/ruby/gems/cache/pkg-config-1.1.4.gem 誤 /opt/local/lib/ruby/gems/1.8/cache/pkg-config-1.1.4.gem 正
gemの場所のrubyのバージョン有無が異なる。手元でソースからインストールしたバージョン有りのほうが正しい。
原因
port:rubyやport:ruby19がインストールされていない環境で、"port install rb-pkg-config"などいっぺんに依存でインストールしようとしたときにこうなる。要するにbuildbot。
optionsで定義されたグローバル変数をdefaultを使用してprocで値を与えたとき、実際の例で言うと、
set ruby.gemdir ${prefix}/lib/ruby${ruby.branch}/gems/${ruby.api_version}
default ruby.api_version {[ruby.extract_config ruby_version]} proc ruby.extract_config {var {default ""}} { global ruby.bin if {[catch {set val [exec ${ruby.bin} -e "require 'rbconfig';puts RbConfig::CONFIG\[\"${var}\"\]"]}]} { set val ${default} } return $val }
のように定義されており、その値の初回評価時に実際にコマンド(ruby-1.9, ruby-1.8, ...)が実行されて値が設定される。
つまり、r112446の変更前の
destroot { system -W ${worksrcpath} "${ruby.gem} install --local --force --install-dir ${destroot}${ruby.gemdir} ${distpath}/${distname}.gem" :
は実際のdestroot時に評価される(他で${ruby.api_version}を使用していなければ)のに対し、変更後の
destroot.args --local --force --install-dir ${destroot}${ruby.gemdir}
はPortfileの処理時に値を評価してしまう。このタイミングではruby.extract_configで使用するruby本体がまだインストールされていない可能性があり、そのとき初期値を与えていないので""と空文字に落ちてしまう。
その結果、ソースからインストールすると正しい結果になるのに、ビルド済みのファイルをサーバからとってくるとおかしい、という状況になっていた。
対策
- ruby.extract_configには常に正しいデフォルト値を与える必要がある。
- ruby.branchセット時に毎度defaultでruby.*の値を設定し直す。ruby.api_versionとかは手書きのswitchで導出する。
という対策を行った。
- {[ruby.extract_config ]}を使った値は、build {}やdestroot {}などのアクション中では使えるが、configure.argsなどの値には使えないものとする。
という選択肢もあって、そっちのほうが簡単だし意味的には正当なんだけど、それもなんか実装の都合だよなあ。。と思って今回の対処とした。
でもさ、常に正しい初期値を与える必要があるならさ、そもそもruby.extract_config使う必要なくね?