我遇到了包含必须从Perforce存储库获取的Perl模块的问题。我通过使用P4 print
从Perforce中读取文本来包含模块。
对于不熟悉Perforce的人来说,它是一个代码版本控制工具。我不能直接从该路径读取文件,就像它是映射驱动器一样,所以我需要运行此命令。
p4 print
等同于cat
,但路径是特殊的,只有命令p4
可以从Perforce工作区访问文件。
BEGIN {
push @INC, (
sub {
open my $fh, "p4 print -q //sw/pvt/shashikanths/perl/mylib/ReadElf.pm |";
return $fh;
},
sub {
open my $fh1, "p4 print -q //sw/pvt/shashikanths/perl/mylib/SimpleLogger.pm |";
return $fh1;
},
);
}
BEGIN {
push @INC, sub {
open my $fh2, "p4 print -q //sw/pvt/shashikanths/perl/mylib/Table.pm |";
return $fh2;
}
}
use ReadElf;
use SimpleLogger;
use Table;
始终只包含第一个文件ReadElf.pm
。我尝试将所有三个文件连接到一个文件,并且还为每个文件单独使用BEGIN
块。它们都不起作用。
因此,当我尝试从SimpleLogger访问模块时,我得到了未定义的子程序错误。
答案 0 :(得分:7)
我道歉,我只是明白你在做什么。将子程序引用推送到@INC
是Perl功能的一个神秘部分,很少有人知道。
您还可以通过将Perl代码直接放入@INC数组中,将挂钩插入导入工具。钩子有三种形式:子程序引用,数组引用和祝福对象。
子程序引用是最简单的情况。当包含系统遍历@INC并遇到子程序时,将使用两个参数调用此子例程,第一个是对自身的引用,第二个是要包含的文件的名称(例如,“Foo / Bar.pm”) 。子例程应按以下顺序返回任何内容或最多返回三个值的列表:
1 - 文件句柄,将从中读取文件。
2 - 对子程序的引用。如果没有文件句柄(前一项),那么这个子程序应该每次调用生成一行源代码,将行写入$ _并返回1,最后在文件末尾返回0.如果有文件句柄,然后调用子程序作为一个简单的源过滤器,该行在$ _中读取。同样,为每个有效行返回1,并在返回所有行后返回0。
3 - 子程序的可选状态。州以$ _ [1]的形式传递。子例程本身的引用作为$ _ [0]传递。
问题在于您忽略了要推送到@INC
的子程序的参数。第二个参数是perl尝试加载的模块文件的名称,即ReadElf.pm
,SimpleLogger.pm
或Table.pm
。 Perl在@INC
中找到返回任何内容的第一个条目,它始终是第一个子例程,它提取ReadElf.pm
并返回一个文件句柄以便从中读取。
要加载其中任何一个,只要它们都在Perforce存储库中的相同位置,您就可以编写
BEGIN {
push @INC, sub {
my ($self, $module) = @_;
my $file = "//sw/pvt/shashikanths/perl/mylib/$module";
open my $fh, "p4 print -q $file |";
return $fh;
}
}
这可以通过构建模块的Perforce副本的完整路径并返回一个允许Perl读取它的文件句柄来实现。
您确实应首先检查$file
指定的文件是否存在,如果不存在,则不返回任何内容。否则p4
正在被不必要地运行,子程序返回一个文件句柄,无论模块是否被成功提取。