2012-10-03 40 views
1

背景:我有一个perl模块 - 我们把它叫做Foo::Common,它已经安装在我们的一个文件服务器上(为了简单起见,我将称之为'全局'版本)。该模块包含在每隔15分钟启动的1000个脚本的顺序中。该模块有几个版本,但更新它将在几个月内进行大量测试。如何根据模块版本有条件地更改@INC?

我正在写一个新的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::Commonour $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 ([email protected]) { 
     $INC{$filename} = undef; 
     die [email protected]; 
    } elsif (!$result) { 
     delete $INC{$filename}; 
     die "$filename did not return true value"; 
    } else { 
     return $result; 
    } 
} 

我不是这个如何与use MODULE VERSION语法交互清楚,虽然在回答What does Perl do when two versions of a module are installed?讨论表明use Module Version是不够的。

我相信,我要去操纵@INC,但我不知道怎么做,基于每个模块的$VERSION,特别是因为use有一个隐BEGIN声明。

我该如何解决这个问题?

回答

2

由于$VERSION不存在,所以不能根据版本进行检查,直到它被加载后又被执行。


所以你想要使用“全球”版本,如果存在,并使用本地版本,否则?将本地路径附加到@INC而不是预先添加它。

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

use Foo::Common; 

如果您不能重新排列@INC,因为它会影响别的东西,尝试改变@INC之前加载的Foo ::常见。如果它前面已经加载

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

use Foo::Common;不会加载模块,它会从哪个版本没有得到加载(不管它得到加载)进口。

+0

不,不是很......我想用'$ ENV {} FOO_ENV_HOME /核心/斌/富/ Common.pm'当且仅当它是'$ VERSION'大于或等于到'./ lib/Foo/Common.pm'的'$ VERSION'。 –

+0

如果我运行'eval {require Foo :: Common; };检查它是否为'$ VERSION',然后更改@INC并重新运行'eval {require Foo :: Common; };'如果之前的'$ VERSION'不够高? (我没有从Foo :: Common命名空间导出任何东西,所以我不需要*使用'use') –

+0

执行这两个模块会导致问题,而这完全没有必要。 – ikegami