【问题标题】:How can I "use lib" the appropriate directory depending on installation location?如何根据安装位置“使用 lib”适当的目录?
【发布时间】:2009-11-11 00:53:05
【问题描述】:

我有一个面向对象的网络应用程序,它安装在我服务器上的多个位置。一次用于“live”,一次用于“beta”,等等。作为面向对象,它由许多 perl 模块组成。在主模块中,我必须为该应用程序实例的所有 custom perl 模块“使用 lib”适当的目录。

这没什么大不了的,我有一个 BEGIN 块来检查主程序的位置并适当地设置库目录。但是我也有很多实用程序,需要做同样事情的命令行程序。我不想到处剪切和粘贴这段代码。

在需要它的各种程序之间共享此代码 sn-p 的最佳方式是什么?

我无法“使用”它,因为尚未设置库路径。也许“做”或“要求”是正确的答案,但两者都会搜索@INC,这是不合适的。

也许像eval `cat GetLib.pl`; 这样的东西比较合适,但它看起来有点笨重和脆弱。

这是我目前使用的 BEGIN 块:

BEGIN {
  use FindBin qw ($Bin);
  require lib;

  if ($Bin =~ /^\/home\/w\/myapp_live/) {
    lib->import('/home/w/myapp_live/lib');
    print STDERR "live site\n";
  }

  if ($Bin =~ /^\/home\/w\/myapp_beta/) {
    lib->import('/home/w/myapp_beta/lib');
    print STDERR "beta site\n";
  }

  if ($Bin =~ /^\/home\/w\/myapp_test/) {
    lib->import('/home/w/myapp_test/lib');
    print STDERR "testing site\n";
  }

}

谢谢!

【问题讨论】:

  • 正如我在回复中暗示的那样,我认为您在这里问错了问题,因为您让生活变得比应有的更加困难。您的代码应始终位于同一路径中——它位于您的修订控制系统中,您可以在其中区分“实时”和“测试版”代码。
  • Ether:当实时代码和测试代码都在同一台服务器上运行时,它们如何驻留在同一路径中?

标签: perl


【解决方案1】:

FindBin::libs 非常适合。我在大型系统中使用了一段时间,完全没有问题。

默认调用看起来很适合你,只是:

use FindBin::libs;

这将搜索当前文件目录的所有父目录中的所有./lib 目录和use lib 它们。因此,例如,如果您的脚本位于 /home/w/myapp_live/scripts/defurblise_widgets.pl(和 use()es FindBin::libs)中,它将查找:

/home/w/myapp_live/scripts/lib
/home/w/myapp_live/lib
/home/w/lib
/home/lib
/lib       # (presumably!)

它找到的任何内容都将添加到您的@INCuse lib

但是,如果这不是您所需要的,它是一个非常灵活的模块。如果你找不到一种方法让它做你想做的事,我会很惊讶。

【讨论】:

  • 我认为这是最好的答案。
【解决方案2】:

如果您从命令行运行程序,请不要以编程方式设置库:只需将其作为参数传入,例如:perl -I/location/of/my/lib myprog.pl

对于您的网络应用程序,为什么不让您的库相对于脚本本身的位置?然后只需将其安装在库所在的每台机器上。

use FindBin;
use File::Spec::Functions;
use Cwd qw(abs_path getcwd);

BEGIN {
    my $curdir = getcwd;
    my $selfdir = $FindBin::Bin;
    my $libdir = abs_path(catdir($selfdir, 'lib'));

    chdir $libdir or die "can't chdir to $libdir: $@";
    use lib $libdir;
}

当然,最简单的选择是不使用不同的 lib 目录。为什么不能在所有环境中保持一致?

编辑。回复您的评论“我必须使用不同的 lib 目录的原因是因为在实时站点中运行的代码与在 beta 站点上运行的代码不同……这就是拥有 beta 站点的意义所在。” -- 你为什么不在安装程序的级别处理这个问题,而不是让代码本身必须知道它是实时的还是测试版的?例如像现在一样将代码存储在源代码树的不同目录中,但只将相关代码安装到每个盒子。毕竟,这正是一个好的版本控制系统能为你做的——你一次只检查一个分支,而且你一次只应该安装一个版本的代码(正如 brian d foy 所暗示的那样)。

【讨论】:

  • 你的第一个建议太不可靠了,我宁愿让它自动化。第二个建议对 webapp 来说非常好,但我不想依赖命令行脚本的硬编码位置,它们位于 */lib 下的各个子目录中。
  • 我必须使用不同的 lib 目录的原因是因为在 live 站点中运行的代码与在 beta 站点上运行的代码不同......这就是拥有 beta 站点的意义。跨度>
  • 如果您的“测试版”网站与您的生产网站不同,您应该先修复它。 :)
  • 布赖恩:你什么意思? Beta 版网站用于测试新功能,然后在我们对它们满意时将其发布到实时网站。
  • 对不起,你们怎么能不明白呢?测试版站点是新代码,正在测试中。当我们完成测试时,它被复制(通过颠覆)到活动站点目录。这可能有什么问题?
【解决方案3】:

我在许多脚本中使用以下内容:

use strict;
use warnings;

use 5.008;

use FindBin;
use lib $FindBin::Bin;

最后一行可以这样修改:

use FindBin;
use lib "$FindBin::Bin/lib";

【讨论】:

  • 谢谢。如果您再次查看我的代码,您会注意到我正在测试以特定路径开始的 $Bin,而不是特定路径。这样,无论程序在该路径下的哪个位置,它都可以工作。
  • 那么将一个相对的lib 目录符号链接到每个顶级lib 目录怎么样?
【解决方案4】:

不同的环境可能对环境变量$PERL5LIB 有不同的设置。

【讨论】:

  • 谢谢,但这是为程序库添加路径,而不是为整个 Perl 5 库添加路径。
  • 您可以为每个进程设置 PERL5LIB。它不必是全球性的。
  • Brian 我知道它可以按进程设置...但是 PERL5LIB 用于查找系统库,而不是您为程序编写的自定义库。
  • Perl 已经用系统库的路径填充了@INC(除非有问题)。 $PERL5LIB 的最佳用途之一是指定非系统库的位置。
  • Mobrule,感谢您澄清这一点,我第一次看 PERL5LIB 时错过了。
【解决方案5】:

您显示的代码看起来很合理。您可以将该代码的一个副本安装到系统范围的位置,然后调用它的代码将归结为

require '/path/to/findlib.pl';
findlib->import;

采用文件名的require 形式搜索@INC

作为替代方案,如果您想改变周围的很多东西,您可以考虑以一种对local::lib 使用更友好的方式部署应用程序。

【讨论】:

  • 您的回答似乎很合乎逻辑。我宁愿将文件与站点的其余部分一起保持在源代码控制之下,但现在我认为它对所有站点都通用是完全合理的。我唯一担心的是我在编辑该文件时必须非常小心,因为它可能会破坏实时站点。但我认为这可能是最好的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多