2010年9月29日

Perlでモジュールのバージョン一覧を取得する - その2

標準モジュールのバージョン一覧を取得する方法は比較的簡単です。標準モジュールのModule::CoreListを使います。

Module::CoreListは、あるモジュールがいつ標準モジュールになったか、あるバージョンのPerlに、どのバージョンのモジュールが添付されているか、などが分かります。

module.pl

#!/usr/bin/env perl

use strict;
use warnings;

use utf8;

use Module::CoreList;

my $perl_version = shift @ARGV;

foreach my $module (Module::CoreList->find_modules(qr//, $perl_version)) {
	print "$module";
	my $version = $Module::CoreList::version{$perl_version}{$module};
	print "\t$version" if defined $version;
	print "\n";
}

引数にPerlのバージョンを渡すと、そのPerlの標準モジュール一覧をバージョン付きで得ることができます。

$ perl module.pl 5.012002
AnyDBM_File	1.00
App::Cpan	1.5701
App::Prove	3.17
App::Prove::State	3.17

...途中省略...

version	0.82
vmsish	1.02
warnings	1.09
warnings::register	1.01

2010年9月27日

@INCで辿れる全モジュールのバージョン一覧を作ろうとしたが...

@INCで辿れる全モジュールのバージョン一覧を作ろうとしたが...単純に全部requireして$VERSIONの値を取得するって技はできないのね...。

サブルーチンが重複しているって警告出まくり...。そりゃそうか...。

さて、どうやって作ろう...。

2010年9月21日

Perlでモジュールのバージョン一覧を取得する - その1

先日の当サイトの検索キーワードにこんなものが引っかかっていた。

  • perl+モジュールのバージョン一覧取得
  • perl+モジュールのバージョン
  • perl+モジュールのバージョンを調べる

よくあるお題だけど、残念ながらまだそんな記事は書いていないのできっとこの人はお目当ての記事は見つけられなかったと思うな。

で、そう言えば実際にはどんなコードを書けばいいんだっけ?と調べてみると、けっこう方法がたくさん有る。せっかくなのでまとめてみました。

そもそも"何の"モジュールのバージョンを調べるのか?

一口にモジュールのバージョンと言っても沢山考えられますね。

  1. 実行中のパッケージで読み込んでいるモジュールのバージョン一覧
  2. インストールされているモジュールのバージョン一覧
  3. 標準モジュールのバージョン一覧

今回は一つ目のパターンを検証してみます。

実行中のパッケージで読み込んでいるモジュールのバージョン一覧

あるパッケージの中で使われているモジュール(requireやuseされている、という意味で)は、%INCという特殊変数に格納されています。

例えばこんなコードで一覧を出す事ができます(module_list.pl )。

#!/usr/bin/env perl

use strict;
use warnings;

use utf8;
use Encode;

use File::Spec;

print "$_\n" for (keys %INC);
Mac OS X Snow Leopard上で、Perl 5.12.2を使って実行すると、こんな結果が出ました。意外と直接していないモジュールも実は呼び出されている事が分かりますね。
$ perl module_list.pl 
bytes.pm
warnings/register.pm
XSLoader.pm
File/Spec/Unix.pm
Encode/Alias.pm
Exporter.pm
vars.pm
strict.pm
Encode/Config.pm
Encode/Encoding.pm
warnings.pm
File/Spec.pm
utf8.pm
Encode.pm
base.pm

@INCで設定されているモジュールの読み込みパス以降のファイル名が表示されています(ちなみにハッシュ値の方には@INCのパスも含めたフルパスが入っています)。

%INCはパッケージ毎に定義されているので、上記の出力はmainパッケージで読み込まれているモジュールの一覧になります。別のパッケージを定義して、別のモジュール呼び出しを行うと、異なる結果が表示されます。

モジュールのパス名が分かったので、後はパッケージ名形式に変換して、$VERSIONを取得すれば、バージョン一覧が取得できます。

こんなコードを書いて見ました(module_list2.pl)

#!/usr/bin/env perl

use strict;
use warnings;

use utf8;
use Encode;

use File::Spec;

no strict 'refs';

foreach my $module (sort keys %INC) {
	$module =~ s/\//::/;
	$module =~ s/.pm$//;

	if (defined ${$module . "::VERSION"}) {
		print "$module\t" . ${$module . "::VERSION"} . "\n"
	}
}
$ perl module_list2.pl 
Encode	2.40
Encode::Alias	2.12
Encode::Config	2.05
Encode::Encoding	2.05
Exporter	5.64_01
File::Spec	3.3101
XSLoader	0.10
base	2.15
bytes	1.04
strict	1.04
utf8	1.08
vars	1.01
warnings	1.09
warnings::register	1.01
バージョンが定義されていないパッケージもあるので、数が一致していませんが、これで現在パッケージで使っているモジュールのバージョン一覧が取得できました。

次回は「インストールされているモジュールのバージョン一覧」をやってみます。

2010年9月18日

次に作るツール

こんなツールを作ろうと思った。


  • Perlのモジュールのリストを渡すとまとめてインストールしてくれる。
  • バージョン指定可能
  • ビルド条件も指定可能
  • インストールファイルをダウンロードして取得するか、所定のローカルディレクトリから取得するか指定可能
  • 依存モジュールのインストールをダウンロードして取得するか、所定のローカルディレクトリから取得するか指定可能

ネット接続のない環境でモジュールをインストールしたり、テストで使った環境をバージョンを揃えて再現したい時に便利かなと思った。


2010年9月17日

Perlのモジュールを色んな場所にインストールする - やっとlocal::libの話

local::libを使う

前回の記事からずいぶんと時間が経ってしまいましたが、ようやくlocal::libの使い方の解説に投入します。

前回の記事でも解説しましたが、モジュールのインストールの仕組みと、モジュールを読み込む仕組みは別々の物なので、標準以外の場所にモジュールをインストールしたい場合はそれぞれで設定する必要が有りました。この二つの作業をまとめてやってくれるのがlocal::libです。

インストール

local::libのインストール方法には二つ有ります。

  • 管理者権限で、他のモジュールと同じ場所へインストールする
  • 通常のモジュールのインストールと同じです。cpanコマンド等を用いてインストールします。

    $ sudo cpan local::lib

    モジュールは通常のcpanコマンドでインストールする場所にインストールされます。

  • 一般ユーザー権限で、ローカルディレクトリへインストールする
  • レンタルサーバ上で環境構築をしたい場合など管理者権限が無くローカルディレクトリへインストールしたい場合や、特定アプリケーション用に使うモジュールなので標準インストールパスへインストールしたくない場合が有ります。

    この様な場合に、local::libではブーストラップテクニックと呼ばれる方法でインストール先を決定します。

    1. インストール手順

    2. $ curl -LO http://search.cpan.org/CPAN/authors/id/G/GE/GETTY/local-lib-1.006007.tar.gz
      $ tar xvf local-lib-1.006007.tar.gz
      $ cd local-lib-1.006007
      $ perl Makefile.PL --bootstrap
      $ make
      $ make install
      $ echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >>~/.bashrc

      最後はシェルにbashを使っている場合の記述です。

      これでlocal::lib自体が~/perl5/ディレクトリ配下へインストールされました。

    3. 環境変数の設定

    4. インストールの最後に.bashrcへ追加したのは、local::libを実行して必要な環境変数を設定する内容です。モジュールの読み込み先を-Iオプションでlocal::libをインストールした先を指定し、local::libを実行します。

      local::lib自体をを実行すると、以下の環境変数が設定されます(ユーザー名はuserAとしました)。

      $ perl -I$HOME/perl5/lib/perl5 -Mlocal::lib
      Attempting to create file /Users/userA/perl5/.modulebuildrc
      export MODULEBUILDRC="/Users/userA/perl5/.modulebuildrc"
      export PERL_MM_OPT="INSTALL_BASE=/Users/userA/perl5"
      export PERL5LIB="/Users/userA/perl5/lib/perl5/darwin-2level:/Users/userA/perl5/lib/perl5:$PERL5LIB"
      export PATH="/Users/userA/perl5/bin:$PATH"

      これでcpanコマンドでモジュールをインストールすると、~/perl5/ディレクトリ配下へインストールされるようになります。また、PERL5LIBも設定されているので、モジュールの読み込みも行われます。

      ~/perl5/ディレクトリ配下以外へインストールする場合は、以下の様にインストール時に設定します(~/foo/ディレクトリ配下へインストール例)。

      $ perl Makefile.PL --bootstrap=~/foo
      $ make
      $ make install
      $ echo 'eval $(perl -I$HOME/foo/lib/perl5 -Mlocal::lib=$HOME/foo)' >>~/.bashrc

モジュールの読み込み

.bashrcへlocal::libの設定を追加した場合は、自動的に~/perl5/配下へモジュールのパスが設定されますが、.bashrcへ設定を追加していない場合は、スクリプトの中で明示的にlocal::libを呼び出す必要があります。

use local::lib; # ~/perl5が設定される。

use local::lib '~/foo'; # ~/fooが設定される。

2010年9月15日

cookperlというコマンドを書いた

自分用のperlバイナリをインストールするのにperlbrewは最強のツールですが、PerlのソースコードをダウンロードするのにHTTP::Liteを使っているので認証付きproxyを通らないとネットへ接続できない環境では動きません。そこだけがちょっと不便でした。

あと、最近Perlのバージョンアップ頻度が上がってきたので、その度にモジュールのセットアップをするのも面倒くさいなぁと思って、cookperlというコマンドを書いてみました。

こんなツールです。

  • LWPモジュールを使ってPerlのソースコードをダウンロードするので、認証付きproxyでも大丈夫。
  • cpanmをダウンロードしてきてモジュールのセットアップも行います。
  • インストールしたいモジュールの一覧をrecipeと呼ばれるファイルに書いて渡すと、cpanmを使ってインストールします。
  • 後からインストールしたモジュールは全部local::libを使って標準モジュールとは別ディレクトリへインストールします。

ドキュメントも、メッセージも全然整備されていませんが、以下使い方。

インストール

$ curl -LO http://roova.jp/cookperl
$ chmod +x cookperl

recipeファイルの用意

最初の行にインストールするPerlをバージョン指定します。

2行目以降はモジュール名をxxx::yyy形式で記述します。

「recipe.txt」

perl-5.12.2
Module::Starter
Test::Exception

Perlのインストール

$ ./cookperl recipe recipe.txt

Perl本体と、App::cpanminus、local::libは必ずインストールされます。

最後にPATHを設定するためのbashrcのパスが表示されるので、.bashrcへ追記して下さい。

念のために一旦ログアウトして、再度ログインして下さい。

「~/perl5/cookperl/perls/current/bin/perl」が有効なPerlへのパスになります。

local::libを使ってモジュールのインストール先が設定されています。

モジュールは、「~/perl5/cookperl/perls/current/locallib」へインストールされます。

installedコマンド

インストールされているrecipeの一覧はinstalledコマンドで表示されます。*が付いたレシピ名が現在有効なレシピです(パスが通っている、という意味)。

switchコマンド

$ switch recipe名で有効なレシピが切り替わります。

これからやること

  • ドキュメントを書く
  • 中途半端に書いたテストを真面目に書く
  • メッセージの英語があまりにデタラメなので直す
  • アンインストール機能を作る
  • LWPが無い環境でも動く様にする
  • モジュール名の形式チェックを真面目にやる
  • 色んな環境で動くか試す(今はMac OS XとUbuntuしか試していない)
  • Perl自体のビルドオプションを設定できる様にする

Perl-5.12.2をインストール出来た時点で、90%くらい自分の目的は達成しちゃった気もしますが。

こんなツール、いくらでも有る気もしますが、新幹線で計8時間も移動した時に頑張って作ってみました。

2010/9/16追記

ヘルプを一応付けました。$ ./coolperl helpで簡単な使い方が出ます。

2010年9月 7日

Perl 5.12.2がリリースされました

Perl 5.12.2がリリースされました。

メンテナンスリリースなので、修正量は少ないですね。