背景:私は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ステートメントがあるため、各モジュールに基づいて操作する方法がわかりません。
どうすればこれにアプローチできますか?