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使ってできるといいなぁと思ってます。

どうぞご利用ください。

このブログ記事について

このページは、Masahiro Naganoが2014年6月13日 14:30に書いたブログ記事です。

ひとつ前のブログ記事は「Module::CoreList の Web Interface を作りました」です。

次のブログ記事は「VagrantのVMを使い捨てる。vagrant-destroy-provisionerをリリースしました」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

ウェブページ

OpenID対応しています OpenIDについて
Powered by Movable Type 4.27-ja