在部署Perl项目之前,如何确定CPAN依赖项?

时间:2008-10-27 17:19:19

标签: perl deployment dependencies cpan

是否有人建议找到可能在定制开发项目中出现的所有CPAN依赖关系的好方法。往往是这样的情况,您的本地开发环境很少与您的实时开发环境匹配,并且当您构建越来越多的项目时,您倾向于构建已安装模块的本地库。这些导致您不一定注意到您的最新项目对非核心模块有要求。由于通常需要将整个项目打包以部署到另一个组(在我们的案例中是我们的运营团队),因此了解应该包含哪些模块非常重要。

有没有人对此问题有任何见解。

由于

彼得

8 个答案:

答案 0 :(得分:13)

我自己也遇到过这个问题。 Devel::Modlist(由this answer建议)采用动态方法。它报告在特定的脚本运行期间实际加载的模块。这会捕获以任何方式加载的模块,但它可能无法捕获条件要求。也就是说,如果你有这样的代码:

if ($some_condition) { require Some::Module }

$some_condition恰好是错误的,Devel::Modlist不会将Some::Module列为要求。

我决定使用Module::ExtractUse代替。它进行静态分析,这意味着它将始终在上面的示例中捕获Some::Module。另一方面,它无法对代码执行任何操作:

my $module = "Other::Module";
eval "use $module;";

当然,您可以使用这两种方法然后合并两个列表。

无论如何,这是我提出的解决方案:

#! /usr/bin/perl
#---------------------------------------------------------------------
# Copyright 2008 Christopher J. Madsen <perl at cjmweb.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See either the
# GNU General Public License or the Artistic License for more details.
#
# Recursively collect dependencies of Perl scripts
#---------------------------------------------------------------------

use strict;
use warnings;
use File::Spec ();
use Module::CoreList ();
use Module::ExtractUse ();

my %need;
my $core = $Module::CoreList::version{'5.008'};

# These modules have lots of dependencies.  I don't need to see them now.
my %noRecurse = map { $_ => 1 } qw(
  Log::Log4perl
  XML::Twig
);

foreach my $file (@ARGV) {
  findDeps($file);
}

foreach my $module (sort keys %need) {
  print "  $module\n";
}

#---------------------------------------------------------------------
sub findDeps
{
  my ($file) = @_;

  my $p = Module::ExtractUse->new;

  $p->extract_use($file);

  foreach my $module ($p->array) {
    next if exists $core->{$module};
    next if $module =~ /^5[._\d]+/; # Ignore "use MIN-PERL-VERSION"
    next if $module =~ /\$/;        # Run-time specified module

    if (++$need{$module} == 1 and not $noRecurse{$module}) {
      my $path = findModule($module);
      if ($path) { findDeps($path) }
      else       { warn "WARNING: Can't find $module\n" }
    } # end if first use of $module
  } # end foreach $module used
} # end findDeps

#---------------------------------------------------------------------
sub findModule
{
  my ($module) = @_;

  $module =~ s!::|\'!/!g;
  $module .= '.pm';

  foreach my $dir (@INC) {
    my $path = File::Spec->catfile($dir, $module);
    return $path if -f $path;
  }

  return;
} # end findModule

你可以这样运行:

perl finddeps.pl scriptToCheck.pl otherScriptToCheck.pl

它打印运行所列脚本所需的所有非核心模块的列表。 (除非他们使用模块加载来防止Module :: ExtractUse看到它们。)

答案 1 :(得分:11)

您可以在deps.cpantesters.org使用在线网络服务,它将为您提供许多有用的依赖关系数据。 CPAN上的所有模块都已具有指向依赖关系站点的链接(位于模块页面的右侧)。

答案 2 :(得分:10)

在过去,我使用了Devel::Modlist,相当不错,允许你去

perl -d:Modlist script.pl

获取所需模块的列表。

答案 3 :(得分:5)

我有一个基于Make的构建系统,适用于我所有的C / C ++应用程序(基于PC和各种嵌入式项目),虽然我喜欢能够在新机器上进行顶级构建并验证所有依赖关系到位(我检查我的工具链到版本控制:D),我对在我的构建系统中当前没有makefile的解释语言不做同样的事情感到沮丧。

我很想写一个脚本:

  • 在我的修订控制存储库中搜索扩展名为.pl或.pm的文件
  • 在他们身上运行perl -d:Modlist(感谢Vagnerr!)
  • 将其连接到所需模块列表
  • 最后将其与已安装模块列表进行比较。

然后我将该脚本作为顶级构建的一部分执行,这样任何构建任何内容的人都会知道他们是否拥有运行每个从修订控制获得的perl脚本所需的一切。如果有一些perl脚本它们从不运行并且不想CPAN安装运行它所需的内容,则它们必须从其硬盘驱动器中删除不需要的脚本,因此依赖性检查器无法找到它们。我知道如何在执行“同步”时修改perforce客户端以省略某些子目录,我将不得不为颠覆做出决定......

我建议将依赖检查器设置为搜索pl文件的单个脚本,而不是单个makefile来检查每个脚本的依赖关系,或者基于硬编码的脚本名称列表。如果您选择一个需要用户操作来检查脚本依赖关系的方法,那么人们将忘记执行该操作,因为即使他们不进行依赖性检查,他们也能够运行该脚本。

就像我说的那样,我还没有实现上述内容,但这个问题促使我尝试这样做。我完成后会用我的经验回复。

答案 4 :(得分:3)

'明显'的方式 - 痛苦但适度有效 - 是在一些偏僻的位置安装一个全新的Perl基础版本(你不打算在生产中使用它),然后尝试安装你的模块使用这个'处女'版本的Perl。您将找到所有缺少的依赖项。第一次,这可能是痛苦的。在第一次之后,你已经覆盖了大多数依赖项,并且它将不那么痛苦。

考虑运行您自己的CPAN模块本地存储库 - 这样您就不必总是下载代码了。还要考虑如何清理过时的模块。

答案 5 :(得分:3)

use Acme::Magic::Pony;

严重。如果它们丢失,它将自动安装Perl模块。请参阅CPAN中的Acme::Magic::Pony页面。

答案 6 :(得分:2)

它是一匹“疯狂的马”,但我已养成了创建一个包含所有依赖项的Bundle文件的习惯。因此,当我进入一个新环境时,我只需将其复制并安装即可。

例如。我有一个Baz.pm

package Bundle::Baz;
$VERSION = '0.1';
1;
__END__
=head1 NAME
Bundle::Baz
=head1 SYNOPSIS
perl -MCPAN -e 'install Bundle::Baz'
=head1 CONTENTS
# Baz's modules
XML::Twig
XML::Writer
Perl6::Say
Moose

将它放在〜/ .cpan / Bundle /(或.cpan所在的任何地方),然后像普通的CPAN模块一样安装'Bundle :: Baz'。然后安装“= head1 CONTENTS”下列出的所有模块。

答案 7 :(得分:1)

这是一个quickie bash函数(使用优秀的ack):

# find-perl-module-use <directory> (lib/ by default)
function find-perl-module-use() {
    dir=${1:-lib}
    ack '^\s*use\s+.*;\s*$' $dir | awk '{ print $2 }' | sed 's/();\?$\|;$//' | sort | uniq
    ack '^\s*use\s+base\s+.*;\s*$' $dir | awk '{ print $3 }' | sed 's/();\?$\|;$//' | sort | uniq
}