(1)はこちら 、( 2)はこちら から。
Carton
Carton もcpanmと同様に、宮川達彦さんを中心に開発しているツールです。Cartonがどんなツールかについては、PODにズバリな一文があるので引用します。
carton is a command line tool to track the Perl module dependencies for your Perl application.
「Cartonとは、アプリケーションにおけるPerlモジュールの依存関係を管理するコマンドラインツール」というわけです。
また、PODのNAMEセクションには次の記述があります。
Carton - Perl module dependency manager (aka Bundler for Perl)
Rubyでお馴染みのBundler という単語が出てきました。Rubyを使う人にはこちらのほうがピンとくるのではないでしょうか。BundlerはRubyのモジュール管理ツールとして有名で、CartonはBundlerにインスパイアされて開発されています。
どのように動くのか
それでは、Cartonとはどのように動くツールなのかを見ていきます。
そもそもPerlモジュールのインストールにはメタデータが必要です。メタデータとは、Makefile.PLや Build.PL のことで、ExtUtils::MakeMaker やModule::Build 、あるいはModule::Install といったツールチェイン[2] と協調して動くものです。ここにモジュール名や作者情報、そしてモジュールの依存関係などを書くようになっていて、その書き方はツールチェインごとに異なります。
Cartonはここで定義された依存関係を解決し、それらモジュールを一括で、アプリケーション単位で独立した場所にインストールしたりダウンロードしたりできます。また、ここで独立してインストールしたモジュールを使うようにPerlを実行できます。
次のセクションで解説しますが、Carton 0.9.4まではMakefile.PLやBuild.PLに書かれた依存関係を読んで実行していましたが、0.9_5以降ではcpanfileという新しいフォーマットのみをサポートするように変更されました。
なお、以降の説明では特にことわりがない場合、Carton 0.9.15を例に使い方を説明します。
cpanfile
cpanfile とは、モジュールの依存関係を定義するファイルです。RubyでいうGemfile と同じ役割を持っています。BundlerがGemfileからモジュール依存関係を解決するように、Cartonはcpanfileを使うことで同様のことを行います。
前述のとおり、以前はcpanfileは存在せずMakefile.PLなどを直接読むようになっていましたが、なぜcpanfileというフォーマットが新規に作成され、そしてCartonではそれをサポートするようになったのでしょうか。cpanfile-faq の記載を抜粋すると、次のような理由によります。
CPANにアップロードしないプロダクトの考慮
たとえばアプリケーションプロジェクトでは、依存関係の定義だけが欲しいので、Makefile.PLやBuild.PLをあえて作成する必要はない
より正確な依存関係の解析
モジュールのビルドそのものに必要となるconfigureフェーズも、正確に定義・解析できるようになる(後述)
CPAN Meta Spec v2のサブセットとなるDSL(Do main Specific Language 、ドメイン特化言語)のサポート
Module::InstallライクなDSLに加えて、CPAN Meta Spec v2の機能であるバージョンの範囲指定などもサポートされる
既存のMakefile.PLなどをそのまま利用するのでは、CPAN Meta Spec v2の完全なサポートが難しいなど制約が残ります。既存のツールチェインを無理矢理ハックして利用するのは筋が悪いですし、そのせいでCartonの新機能開発にも制約が出てしまったりもするので、cpanfileという新規フォーマットを使ってCartonの利用シーンに合ったやるべきことを実現するというアプローチは、お互いにとって良いことだと言えるでしょう。
cpanfileの書き方
cpanfileは前述のとおりModule::Installによく似たDSLで依存関係を定義します。PODからcpanfileの例を引用します。
requires 'Catalyst', '5.8000'; # 5.8000 or newer
requires 'Catalyst::View::JSON', '>= 0.30, < 0.40';
recommends 'JSON::XS', '2.0';
conflicts 'JSON', '< 1.0';
on 'test' => sub {
requires 'Test::More', '>= 0.96, < 2.0';
recommends 'Test::TCP', '1.12';
};
on 'develop' => sub {
recommends 'Devel::NYTProf';
};
requires
やrecommends
はModule::Installでも使われており、それぞれ必須モジュールおよび推奨モジュールを書きます。ほかにconflicts
やsuggests
もありますので、詳しくはCPAN::Meta::Spec を参照してください。ちなみにCarton 0.9.15でサポートされているのはrequires
のみです。
これらの引数は以下のように指定でき、モジュール名は必須ですが、バージョン定義部分は省略すると取得できる最新バージョンとして解釈されます。バージョン部分を指定する場合は、最低バージョン、範囲指定、あるいは特定バージョンというようにさまざまな書き方ができます。
requires 'Module::Name';
requires 'Module::Name', 'MINIMUM VERSION';
requires 'Module::Name', '>= MINIMUM, < MAXIMUM';
requires 'Module::Name', '== SPECIFIC VERSION';
フェーズ
on 'PHASE'
という記法で、モジュール定義の動作フェーズを限定できます。フェーズにはconfigure
、build
、test
、runtime
、develop
の5つがあります。上記例のようにフェーズ指定がない場合は、runtime
フェーズとして扱われます。
テストのみで必要なモジュールはtest
フェーズで、モジュール開発者のみ必要なモジュールはdevelop
フェーズで、ビルド実行前にツールチェインレベルで必要なモジュールはconfigure
フェーズで、というように使い分けることができます。
on 'confgure' => sub {
requires 'Module::Build', '0.40';
requires 'Module::CPANfile', '0.9031';
};
on 'test' => sub {
requires 'Test::More', '>= 0.96, < 2.0';
};
on 'develop' => sub {
recommends 'Devel::NYTProf';
};
既存ツールチェインとの連携
ところで、cpanfileを使うとMakefile.PLやBuild.PLが使えなくなるわけではありません。それら用のcpanfileブリッジモジュールが存在するので、あわせて使うことで、CPANモジュールのプロジェクトであっても、依存関係はcpanfileに定義して、そのほかのメタデータはツールチェインのものをそのまま使うことができます。
Module::Installの場合
Module::Install の場合は、Module::Install::CPAN file を使うことで実現できます。次のようにcpanfileとMakefile.PLを書くだけで連携できます。依存関係以外の情報は、今までと同様にMakefile.PLに定義します。
cpanfile
on 'configure' => sub {
requires 'Module::Install';
requires 'Module::Install::CPANfile';
};
requires 'Some::Module';
Makefile.PL
use inc::Module::Install;
(省略)
cpanfile;
WriteAll;
Module::Buildの場合
Module::Buildの場合は、Module::Build::Pluggable::CPANfile を使います。こちらも作者などの情報は従来どおりにBuild.PLに書くだけで大丈夫です。
cpanfile
on 'configure' => sub {
requires 'Module::Build', '0.40';
requires 'Module::Build::Pluggable::CPANfle', '0.04';
};
requires 'Some::Module';
Build.PL
use Module::Build::Pluggable qw(
CPANfile
);
my $builder = Module::Build::Pluggable->new(
(省略)
);
$builder->create_build_script();
Cartonの導入
ここまでCartonを動かすためのしくみを見てきたので、いよいよCarton自体をインストールしていきます。CartonはCPANにモジュールとして登録されているので、それこそcpanmを使ってインストールしましょう。
インストールされたことを確認します。
$ carton -v
carton v0.9.15
旧バージョンの導入
前述のように、Carton 0.9_5以降ではMakefile.PLおよびBuild.PLの利用がサポート外になったので、事情によりこれらビルドファイルのままCartonを使いたい場合は、0.9.4を指定してインストールするとよいでしょう。先に紹介したcpanmの機能を使うと、バージョン固定のインストールも簡単です。
$ cpanm Carton@v0.9.4
# or
$ cpanm MIYAGAWA/carton-v0.9.4.tar.gz
(省略)
$ carton -v
carton v0.9.4
一括インストール
Cartonで現在できることは、cpanfileを使った依存モジュールのダウンロード、インストール、そしてインストール済みのモジュールを使った実行などがあります。ここからそれぞれ説明していきます。
Cartonのメイン機能である一括インストールを行うには、install
サブコマンドを使います。ここではサンプルとして次の内容のcpanfileを使います。
この状態でCartonを実行すると、依存モジュールが一括でインストールされます。
$ carton install
Installing modules using cpanfile
Successfully installed File-ShareDir-Install-0.04
Successfully installed Try-Tiny-0.12
(省略)
Successfully installed Plack-1.0024
34 distributions installed
Complete! Modules were installed into local
このとき、モジュールはカレントディレクトリのlocalディレクトリ以下にインストールされます。
$ tree local
local
├─ bin
│ ├─ instmodsh
(省略)
└─ lib
└─ perl5
├─ Apache
│ └─ LogFormat
│ └─ Compiler.pm
(省略)
125 directories, 301 files
carton install
を実行すると、carton.lock
というファイルが生成されます。このファイルにはインストールされたモジュールのメタデータが入っており、後述するほかのサブコマンド実行時に利用されます。
インストールの挙動を変更するオプションが3つあるので、以降で紹介します。
インストール先の変更── --path、PERL_CARTON_PATH
インストール先を変更したい場合は、--path
オプション、あるいはPERL_CARTON_PATH
環境変数で指定できます。
$ carton install --path=vendor/modules
# or
$ PERL_CARTON_PATH=vendor/modules carton install
Installing modules using cpanfile
(省略)
34 distributions installed
Complete! Modules were installed into vendor/modules
場所が変わっただけで、インストールされたモジュールに違いはありません。
$ tree vendor/modules
(省略)
125 directories, 301 files
デプロイモード ── --deployment
--deployment
オプションを指定すると「deployment mode」として動作します。具体的には、インストール後にcarton.lock
の更新を行わなくなります。利用シーンとしては、アプリケーションのデプロイ先で依存モジュールを展開したい場合などに利用します。
$ carton install --deployment
Installing modules using cpanfile (deployment mode)
(省略)
34 distributions installed
Complete! Modules were installed into local
bundleしたモジュールをインストール── --cached
後述するbundle
サブコマンドを使うと、依存モジュールをローカルディレクトリに一括ダウンロードできます[3] 。--cached
オプションは、このダウンロード済みのディレクトリをCPANミラーとして使用するオプションです[4] 。
$ carton install --cached
(省略)
34 distributions installed
Complete! Modules were installed into local
local環境での実行
exec
サブコマンドを使うと、前述したlocal
ディレクトリにインストールしたモジュールを使ってプログラムを起動できます。
$ carton exec -- plackup -v
Plack 1.0024
exec
のあとに--
を挟んで実行したいコマンドラインを指定しないと、たとえば上記の-v
オプションがplackup
ではなくcarton
のオプションとして解釈されてしまうので、注意が必要です。
$ carton exec plackup -v
carton v0.9.15
local/lib
以外のディレクトリを独自に@INC
に差し込みたい場合は、perlと同様に-I
オプションで指定できます。
$ carton exec -Iextlib -- perl -le 'print join "\n", @INC'
extlib
local/lib/perl5/darwin-2level
local/lib/perl5
.
(省略)
また、local以外の場所にモジュールをインストールしている場合は、PERL_CARTON_PATH
環境変数でディレクトリを指定して実行します[5] 。
$ PERL_CARTON_PATH=vendor/modules carton exec -- plackup -v
Plack 1.0024
依存モジュールのダウンロード
bundle
サブコマンドで依存モジュールのtarballを一括ダウンロードできます。
$ carton bundle
Bundling modules using cpanfile
File-ShareDir-Install-0.04
Plack-1.0024
\_ Try-Tiny-0.12
(省略)
Complete! Modules were bundled into /Users/ikasam_a/myapp/
local/cache
デフォルトでlocal/cache
ディレクトリ以下にCPANミラーと同様の構造で保存します。
$ tree local/cache
local/cache
└─ authors
└─ id
├─ A
│ └─ AD
│ └─ ADAMK
│ ├─ Class-Inspector-1.28.tar.gz
(省略)
41 directories, 34 files
ただし、modules
ディレクトリと02packages
ファイルが存在しない[6] ため、そのまま独立したCPANミラーとして利用することはできません。
ダウンロード先の変更── --path、PERL_CARTON_PATH
インストールと同様に、--path
オプションあるいはPERL_CARTON_PATH
環境変数で保存先を指定できます。ただし、保存先として指定したパスに/cache
が自動で付与されることに注意が必要です。
$ carton bundle --path=vendor/bundle
Bundling modules using cpanfile
(省略)
Complete! Modules were bundled into /Users/ikasam_a/myapp/
vendor/bundle/cache
$ tree vendor/bundle/cache
(省略)
41 directories, 34 files
bundle
であらかじめモジュールを取得しておくと、install --cached
を利用してローカルでインストールを完結させることができるので、いちいちリモートにモジュールを取得しにいくと都合が悪いケースで活用できます。
依存モジュールの確認
モジュールの表示をするサブコマンドにはlist
、tree
、show
があります。名前から予想できるように、主に一覧表示か個別表示かの違いです。
list
サブコマンドを実行すると次のように、依存モジュールのディストリビューション一覧がリスト表示されます[7] 。
$ carton list
Test-NoWarnings-1.04
IO-HTML-1.00
(省略)
list --tree
とすると整形して簡易ツリー表示になります。tree
サブコマンドもまったく同じで、単純にlist --tree
のショートカットなだけです。
$ carton list --tree
# or
$ carton tree
Plack-1.0024
Test-Requires-0.06
ExtUtils-MakeMaker-6.66
(省略)
show Module::Name
で指定したモジュールの情報がJSONでダンプされます。省略していますが、mymetaセクションにはCPAN Meta Spec v2のメタデータが記載されます。
$ carton show File::ShareDir::Install
{
"dist" : "File-ShareDir-Install-0.04",
(省略)
"provides" : {
"File::ShareDir::Install" : {
"file" : "File/ShareDir/Install.pm",
"version" : "0.04"
}
},
"target" : "File::ShareDir::Install",
"version" : "0.04"
}
なお、これらのサブコマンドはcarton.lock
ファイルが存在しないとエラーになるので、先にcarton install
あるいはcarton bundle
を実行しておく必要があります。
Carton今後の課題
Cartonは1.0リリースに向けて鋭意開発中のプロダクトですので、未実装の部分や挙動がおかしい部分もあります。
たとえばサブコマンドによってオプションの一貫性が取れていない部分もありますし、bundle
やinstall
時のcarton.lock
ファイルの扱いがあまり考慮されていない、といったことが挙げられます。また、Bundlerで使える基本サブコマンドのいくつか[8] には未対応です。
今回紹介した機能で基本的なモジュール管理はできるようになりますが、使い込んでいくと、もう一歩細かいところを制御したいケースもあるかと思います。幸いなことにCartonも、そしてcpanmもGitHubで開発されているので、気になった点があれば、パッチを書いてpull requestを送れば取り込んでもらえるかもしれません :p
なお、本誌発売時にはCarton 1.0がリリースされているかもしれませんが、基本的な使い方に変更はない予定です。
まとめ
今回は、Perlモジュール管理の最新事情として、Cartonとcpanmについて簡単に解説しました。まだまだ開発中のツールではありますが、基本機能はそろってきているので、本稿が導入の参考になればと思います。
さて、次回の執筆者はmalaさんで、テーマは「クローラの作り方」です。