背景:私はperlモジュールを持っています-Foo::Common
ファイルサーバーの1つにインストールされているものと呼びましょう(簡単にするために、これを「グローバル」バージョンと呼びます)。このモジュールは、15分ごとに起動される1000個程度のperlスクリプトに含まれています。モジュールはいくつかのバージョンが古いですが、モジュールを更新するには、数か月の間に多くのテストが必要になります。
同じ処理サーバーで実行される新しいperlスクリプトを作成していますが、の最新バージョンにのみ含まれている機能が必要ですFoo::Common
。新しいバージョンのを使用したいだけの場合は、スクリプトが実行されているディレクトリにFoo::Common
配置Foo/Common.pm
して、次のコードを使用できます。./lib
my $lib = '';
BEGIN {
$lib = $ENV{FOO_ENV_HOME} || '';
}
use lib "$lib/core/bin/";
use lib './lib';
use Foo::Common;
use lib
の先頭にディレクトリを追加するため@INC
、の新しいバージョンがFoo::Common
最初に検出されて使用されます。
これはすべてうまくいきますが、スクリプトをのローカルバージョンに依存させたくありませんFoo::Common
。のグローバルバージョンはFoo::Common
にありour $VERSION = '1.1.2'
、ローカルにインストールしたいバージョンはにあり1.1.7
ます。上記のコードをデプロイしてから、グローバルバージョンをまだ記述されていないバージョンにアップグレードすると1.2.0
、スクリプトの実行が停止します1.1.7
。
によるとperldoc -f require
:
`require $filename` Has semantics similar to the following subroutine:
sub require {
my ($filename) = @_;
if (exists $INC{$filename}) {
return 1 if $INC{$filename};
die "Compilation failed in require";
}
my ($realfilename,$result);
ITER: {
foreach $prefix (@INC) {
$realfilename = "$prefix/$filename";
if (-f $realfilename) {
$INC{$filename} = $realfilename;
$result = do $realfilename;
last ITER;
}
}
die "Can't find $filename in \@INC";
}
if ($@) {
$INC{$filename} = undef;
die $@;
} elsif (!$result) {
delete $INC{$filename};
die "$filename did not return true value";
} else {
return $result;
}
}
use MODULE VERSION
これが構文とどのように相互作用するかはわかりませんが、2つのバージョンのモジュールがインストールされている場合、Perlは何をしますか?use Module Version
それだけでは不十分であることを示します。
@INCを操作しようとしていると思いますが$VERSION
、特にuse
暗黙のBEGIN
ステートメントがあるため、各モジュールに基づいて操作する方法がわかりません。
どうすればこれにアプローチできますか?