plenvやxbuildで使っているperl-buildなのですが、ひろむ氏からコミット権限頂いてアップデートをしました。
変更点としてはいつでも使えるように search.cpan.org への依存度を減らしたことと、だれでも同じように作業ができるよう依存モジュールを1つのスクリプトにまとめるfatpackにDockerを導入して自動化した点です。
search.cpan.org への依存度の削減
perl-buildはperlのバージョンを引数に渡してインストールを行います。
$ perl-build 5.20.0 /opt/perl-5.20
この際に、渡されたperlのバージョンからアーカイブのパスを調べる必要があります。アーカイブのパスとは以下のようなものです
R/RJ/RJBS/perl-5.21.0.tar.gz
R/RJ/RJBS/perl-5.20.0.tar.gz
R/RJ/RJBS/perl-5.20.0-RC1.tar.gz
S/SH/SHAY/perl-5.19.11.tar.gz
A/AR/ARC/perl-5.19.10.tar.bz2
T/TO/TONYC/perl-5.19.9.tar.bz2
アーカイブはリリースを行ったCPAN Authorのディレクトリ以下に配置されます。perlのソースコードをダウンロードするにはそのバージョンのperlをリリースしたAuthorのPAUSE IDやパスをなにかしらの方法で調べる必要があります。
この一つの方法が CPAN::Perl::Releases モジュールです。CPAN::Perl::Releasesを使うとこんな感じでパスが取れます。
use CPAN::Perl::Releases qw/perl_tarballs/;
perl_tarballs( '5.14.0' );
Returns a hashref like:
{
"tar.bz2" => "J/JE/JESSE/perl-5.14.0.tar.bz2",
"tar.gz" => "J/JE/JESSE/perl-5.14.0.tar.gz"
}
CPAN::Perl::Releasesのソースコード中にベタにバージョンとPAUSE IDの対照表が書かれています。
perl-buildのスクリプトにはCPAN::Perl::Releasesが組み込まれており、最初にCPAN::Perl::Releasesを使ってパスを得ようとします。しかし、組み込まれているCPAN::Perl::Releasesはperl-buildスクリプトをアップデートしない限り、どんどん古くなって行くので、新しいバージョンがリリースされたときに追従出来ず、パスを探せなくなります。
そこでperl-buildは次に http://search.cpan.org/dist/perl-$version をスクレイピングし、パスを調べます。ところが最近、しばしばsearch.cpan.orgがダウンし、またそのダウンタイムも長くなっている(感覚値)ことから、perlをインストールしたい時にエラーでインストールができないということも起きています。
そこで、search.cpan.orgへの依存を減らすべく、こんなページを作りました。curlでアクセスするとこんな感じ。
$ curl -s http://perl-releases.s3-website-us-east-1.amazonaws.com/|head
5.21.0 R/RJ/RJBS/perl-5.21.0.tar.gz
5.20.0 R/RJ/RJBS/perl-5.20.0.tar.gz
5.20.0-RC1 R/RJ/RJBS/perl-5.20.0-RC1.tar.gz
5.19.11 S/SH/SHAY/perl-5.19.11.tar.gz
5.19.10 A/AR/ARC/perl-5.19.10.tar.bz2
5.19.9 T/TO/TONYC/perl-5.19.9.tar.bz2
5.19.8 R/RJ/RJBS/perl-5.19.8.tar.bz2
中身はtsvファイルで、バージョンとパスの組み合わせが得られるだけのページです。静的ファイルなのでs3でホストしています。tsvファイルを作るスクリプトは
https://github.com/kazeburo/perl-releases-list
にあげてあります。このスクリプトをcronで定期的に動かし、s3にアップロードしています。
新しいperl-buildはsearch.cpan.orgにアクセスする前に、このページをダウンロードしてパスを解決します。このページでも解決できない場合はsearch.cpan.orgへアクセスします。
さらに、perlのアーカイブをダウンロードする際のデフォルトのミラーがsearch.cpan.orgだったので、www.cpan.orgへ変更し、search.cpan.orgへの依存をぐっと減らしました。これでもし、search.cpan.orgが落ちていたとしてもperl-buildが使えるようになりました。
ちなみにミラーは環境変数で変更が可能です。
$ PERL_BUILD_CPAN_MIRROR=http://ftp.jaist.ac.jp/pub/CPAN/ perl-build 5.18.1 /opt/perl-5.18
国内ミラーの方がダウンロード速度は速くなるんじゃないかなぁと思います。
Dockerを使ったfatpack
githubに上がっているperl-buildは依存モジュール等を1つにまとめたスクリプトとなっています。これはApp::Fatpackerを使って生成したファイルとなっています。
fatpackしたスクリプトが古いperl 5.8でも動くようにするために、fatpackを行うperlも5.8を使います。以前はtokuhirom氏のローカル環境でやっていた思うのですが、だれでも簡単に再現できるようにした方がいいよねということで、Docker(+Vagrant)で自動化してみました。
Vagrantは1.63が必要です。実行は
$ cd author
$ vagrant up --provision
$ vagrant halt
Docker provisionerを使ってimageを作って実行します。Vagrantfileはこんな感じ
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
config.vm.synced_folder "../", "/perl-build"
config.vm.provision "docker" do |d|
d.build_image "/perl-build/author",
args: "-t perl-build"
end
config.vm.provision "shell",
inline: "docker run -v /perl-build:/perl-build perl-build"
end
最後、shell provisionerを使ってdocker runしていますが、これはDocker provisionerにサポートされているrun機能を使うとrunが終了するまえにvagrant upコマンドが終了してしまう(runはバックグラウンドで実行されている)からです。shellで実行するとfatpackが完了するまでvagrant upが待ってくれるので分かりやすくなります。
Dockerfileはこんなの
FROM jmmills/plenv-base:latest
RUN plenv install 5.8.5
RUN plenv global 5.8.5
ENV PLENV_VERSION 5.8.5
RUN curl -L http://cpanmin.us/ | plenv exec perl - -n ExtUtils::MakeMaker@6.56
RUN curl -L http://cpanmin.us/ | plenv exec perl - -n App::cpanminus
RUN curl -L http://cpanmin.us/ | plenv exec perl - -n Perl::Strip App::FatPacker
RUN plenv rehash
CMD bash -l -c 'cd /perl-build; cpanm -n --installdeps . ; bash author/fatpack.sh'
あとは、作ったスクリプトのテストもDocker使ってできるといいなぁと思ってます。
どうぞご利用ください。