Carton について調べてみました。

このエントリーをはてなブックマークに追加
初めまして、3ヶ月前 Node.js と Playframework という言葉につられて入社しました nomo と申します。念願かなって業務で Node.js 触る機会をいただきました!
前職ではホームページ事業のインフラ回りで AWS をいじっていたり、グループウェア開発で Ruby on Rails をやっていたりしました。

今回は Perl の module dependency manager である Carton について書きたいと思います。対象バージョンは Carton v0.9.4、cpanm 1.5017 です。間違いなどありましたらご指摘いただけると幸いです。
(cpanm --self-upgrade して 1.5017 と出たのに cpanm --version で 1.5011 って出るなーと思ったら perlbrew でインストールしたものだったので、再度 perlbrew install-cpanm しないとダメだった)

CPAN でご覧いただくとわかる通り、このモジュールは Bundler for Perl とも書かれており、Plack に続き他言語の優れた部分を取り入れる試みです。

http://search.cpan.org/~miyagawa/carton-v0.9.4/lib/Carton.pod


まず注意していただきたいのは、やはり「ドキュメントはきちんと読みましょう」という事です。実は自分自身に向かって言っているんですが。。。

WARNING ^

This software is under the heavy development and considered ALPHA quality till the version hits v1.0.0. Things might be broken, not all features have been implemented, and APIs will be likely to change. YOU HAVE BEEN WARNED.

と書かれている様に現在はまだαバージョンで、未実装な部分もあるし、API も変わるよと書かれています。


 で、残念ながら現在はまだ指定したバージョンをインストールする実装はされていない様です。


ドキュメント上はバージョン指定方法として以下の様な記述方法が書かれています。

> carton install URI~1.51 
http://search.cpan.org/~miyagawa/carton-v0.9.4/lib/Carton/Doc/Install.pod


 しかし実際に試してみると、

$ carton install URI~1.51
Installing modules from the command line
Successfully installed ExtUtils-MakeMaker-6.62 (upgraded from 6.30)
Successfully installed ExtUtils-Install-1.54 (upgraded from 1.33)
Successfully installed URI-1.60
3 distributions installed
Complete! Modules were installed into local

現時点での最新版 1.60 がインストールされています。


ちょっとコードの中を見てみると


/usr/bin/carton

#!/usr/bin/perl

eval 'exec /usr/bin/perl  -S $0 ${1+"$@"}'
    if 0; # not running under some shell
use strict;
use 5.008001;
use Carton::CLI;

Carton::CLI->new->run(@ARGV);

Carton/CLI.pm

sub run {
    my($self, @args) = @_;

    ..snip..

    my $call = $self->can("cmd_$cmd");

    if ($call) {
        try {
            $self->$call(@commands);
        } catch {
            /Carton::Error::CommandExit/ and return;
            die $_;
        }
    } else {
        $self->error("Could not find command '$cmd'\n");
    }
}

sub cmd_install {
    my($self, @args) = @_;

    ..snip..

    my $build_file = $self->has_build_file;

    if (@args) {
        $self->print("Installing modules from the command line\n");
        $self->carton->install_modules(\@args);
        $self->carton->update_lock_file($self->lock_file);
    } elsif ($self->{deployment} or not $build_file) {

Carton.pm

sub install_modules {
    my($self, $modules) = @_;
    $self->install_conservative($modules, 1)
        or die "Installing modules failed\n";
}

sub install_conservative {
    my($self, $modules, $cascade) = @_;

    $modules = $self->dedupe_modules($modules);

    ..snip..

    $self->run_cpanm(
        "--mirror", $mirror,
        "--mirror", "http://backpan.perl.org/", # fallback
        "--skip-satisfied",
        ( $mirror ne $DefaultMirror ? "--mirror-only" : () ),
        ( $self->lock ? ("--mirror-index", $self->{mirror_file}) : () ),
        ( $cascade ? "--cascade-search" : () ),
        @$modules,
    );
}

という様な流れなんですが、run_cpanm 前の dedupe_modules で

sub dedupe_modules {
    my($self, $modules) = @_;

    my %seen;
    my @result;
    for my $spec (reverse @$modules) {
        my($mod, $ver) = split /~/, $spec;
        next if $seen{$mod}++;
        push @result, $spec;
    }

    return [ reverse @result ];
}

とモジュール名の重複を避けるコードの際に「~」で分割しているのに、戻り値では分割した $mod, $ver を使わず元のまま返しています。よって特にバージョンを意識したインストールは行われません。
Carton は内部的には cpanm を利用しているようなので、そちら側に実装があるかもしれないと思い確認しましたが、標準では http://cpanmetadb.plackperl.org/v1.0/package/$module を参照し、この API がやはり最新版を返すようなのでバージョン指定はうまく働かないようです。PERL_CARTON_MIRROR='http://backpan.perl.org/' してみてもダメでした。


Carton はとても素晴らしいコンセプトのモジュールなので期待しております。
とりあえず上記の問題は github の issue に登録したほうが良いのかな?
英語で書くの辛いなー。。


8/23 追記
github にて issue 登録し、返信をいただきました。

やはり現在は未サポートの機能で carton install module_name というアドホックなインストール形式は duprecate になる予定だそうです。

https://github.com/miyagawa/carton/issues/51

次の記事
« Prev Post
前の記事
Next Post »
Related Posts Plugin for WordPress, Blogger...