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

在部署Perl项目之前,如何确定CPAN依赖关系?,perl,deployment,dependencies,cpan,Perl,Deployment,Dependencies,Cpan,有人对找到定制开发项目中可能出现的所有CPAN依赖项的好方法有什么建议吗。通常情况下,您的本地开发环境很少与您的实时开发环境相匹配,并且随着您构建越来越多的项目,您倾向于构建本地已安装模块库。这样,您就不必注意到您的最新项目对非核心模块有需求。由于通常需要将整个项目打包以部署到另一个组(在我们的案例中是我们的操作团队),因此了解包中应该包含哪些模块非常重要 有人对这个问题有什么见解吗 谢谢 彼得在过去,我用过一种比较好的方法让你去 perl -d:Modlist script.pl 获取所需模

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

有人对这个问题有什么见解吗

谢谢

彼得

在过去,我用过一种比较好的方法让你去

perl -d:Modlist script.pl

获取所需模块的列表。

您可以使用在线web服务,该服务将为您提供许多有用的依赖关系数据。CPAN上的所有模块都已经有了到依赖项站点的链接(在模块页面的右侧)。

显而易见的方法是在一些偏僻的位置安装全新的基本Perl版本(您不会在生产中使用),然后尝试使用这个“virgin”版本的Perl安装您的模块。您将找到所有缺少的依赖项。第一次,这可能是痛苦的。在第一次之后,您将已经覆盖了大部分依赖项,并且这将大大减少痛苦


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

< P>我有一个基于构建的构建系统,用于所有的C/C++应用程序(基于PC和各种嵌入式项目),而我喜欢能够在一台新机器上做一个顶级的构建,并验证所有依赖性都已就位(我检查工具链到修订控制:D),对于目前在我的构建系统中没有makefile的解释语言,我一直很沮丧没有这样做

我很想写一个脚本:

  • 在我的修订控制存储库中搜索扩展名为.pl或.pm的文件
  • 在它们上运行
    perl-d:Modlist
    (感谢Vagnerr!)
  • 将其连接到所需模块列表
  • 最后将其与已安装模块列表进行比较
然后,我会将该脚本作为顶级构建的一部分来执行,这样构建任何东西的任何人都会知道他们是否拥有运行从修订控制中获得的每个perl脚本所需的一切。如果有一些perl脚本从未运行过,并且不想安装运行它所需的内容,那么他们必须从硬盘中删除不需要的脚本,这样依赖项检查器就找不到它们。我知道如何修改perforce客户端,在您执行“同步”时省去某些子目录,我必须为subversion解决这个问题

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

正如我所说的,我还没有实现上述功能,但这个问题促使我尝试这样做。完成后,我会将我的经验发回。

这是一个“栓住的马”的答案,但我已经养成了创建包含所有依赖项的捆绑文件的习惯。因此,当我进入一个新环境时,我只是复制它并安装它

例如,我有一个下午八点的聚会

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”下列出的所有模块。

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

if ($some_condition) { require Some::Module }
$some_条件
恰好为假,
Devel::Modlist
不会将
some::Module
列为需求

我决定改用。它进行静态分析,这意味着在上面的示例中,它将始终捕获
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
它打印运行列出的脚本所需的所有非核心模块的列表。(除非他们在加载模块时耍花招,阻止module::ExtractUse看到它们。)


真的。如果发现Perl模块丢失,它将自动安装这些模块。请参阅CPAN中的页面。

这里有一个quickie bash函数(使用优秀的:

#查找perl模块的用法(默认为lib/)
函数find-perl-module-use(){
dir=${1:-lib}
ack'^\s*使用\s+.*\s*$'$dir | awk'{print$2}'| sed's/();\?$\\\\\\\;$/'| sort | uniq
ack'^\s*使用\s+base\s+.*\s*$'$dir | awk'{print$3}'| sed's/();\?$\\\\\\\\;$/'| sort | uniq
}

很有趣,但如果您尝试在实时商业环境中使用它,您的运营团队会对您感到有点不安,希望了解您是否了解稳定性和安全性的概念:-)
perl finddeps.pl scriptToCheck.pl otherScriptToCheck.pl
use Acme::Magic::Pony;
# 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
}