2

背景:私は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ステートメントがあるため、各モジュールに基づいて操作する方法がわかりません。

どうすればこれにアプローチできますか?

4

2 に答える 2

4

太陽の下で新しいものは何もありません。

use only::latest 'Foo::Common'

于 2012-10-03T18:54:45.150 に答える
2

$VERSIONロードされるか実行されるまで存在しないため、バージョンに基づいてチェックを行うことはできません。


では、存在する場合は「グローバル」バージョンを使用し、そうでない場合はローカルバージョンを使用しますか?ローカルパスを先頭に追加する代わりに、@INCに追加します。

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

use Foo::Common;

@INC他の何かに影響を与えるために再配置できない場合は、を変更する前にFoo::Commonをロードしてみてください@INC

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

モジュールがすでにロードされている場合、はモジュールをロードせず、use Foo::Common;ロードされたバージョンからインポートします(ロードされた場所に関係なく)。

于 2012-10-03T17:55:34.777 に答える