如何根据模块版本有条件地更改@INC



背景:我有一个perl模块,我们称之为Foo::Common,它已经安装在我们的一个文件服务器上(为了简单起见,我将其称为"全局"版本)。该模块包含在大约1000个perl脚本中,每15分钟启动一次。该模块有几个版本,但更新它需要几个月的大量测试。

我正在编写一个新的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语法交互的,尽管在回答"安装两个版本的模块时Perl会做什么?"?表示CCD_ 17是不够的。

我假设我要操作@INC,但我不确定如何根据每个模块的$VERSION来操作,特别是因为use有一个隐含的BEGIN语句。

我该如何处理?

太阳底下没有什么新鲜事。

use only::latest 'Foo::Common'

您不能根据版本进行检查,因为$VERSION在加载或执行后才存在。


所以如果存在,您希望使用"全局"版本,否则使用本地版本?将本地路径附加到@INC,而不是将其前置。

BEGIN {
push @INC, "$ENV{FOO_ENV_HOME}/core/bin";
if $ENV{FOO_ENV_HOME};
}
use Foo::Common;

如果因为@INC会影响其他内容而无法重新排列,请在更改@INC之前尝试加载Foo::Common。

BEGIN { eval { require Foo::Common; }; }
use lib ...;
use Foo::Common;
use ...;

如果use Foo::Common;之前已经加载,它将不会加载模块,并且它将从加载的任何版本导入(无论它在哪里加载)。

最新更新