【问题标题】:Upgrade all modules installed by local::lib升级 local::lib 安装的所有模块
【发布时间】:2014-10-26 13:35:59
【问题描述】:

我一直在使用 local::lib 来处理服务器上 Perl 模块的安装,因此我可以在不污染系统安装的情况下为某些开发工作获得正确的版本。

但是,系统管理员最近将 Perl 从 5.16 升级到 5.18,我现在遇到了与二进制模块相关的错误,例如

perl -e 'use Scalar::Util'
Perl API version v5.16.0 of List::Util does not match v5.18.0 at /usr/lib64/perl5/5.18.2/XSLoader.pm line 92.
Compilation failed in require at /home/paul/perl5/lib/perl5/x86_64-linux/Scalar/Util.pm line 11.
Compilation failed in require at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

我的理解是我可以通过强制 local::lib 重建其所有模块来解决问题,但我在文档中找不到任何告诉我如何执行此操作,甚至如何获取列表的内容在使用 local::lib 安装的所有模块中(如果我在“每行一个模块”文本文件中拥有它,我可以轻松编写一个 Bash 脚本来处理它)。

这可能吗,还是我必须删除 ~/perl5 目录并从头开始重新安装所有模块(可能会丢失一些,因为我不记得全部了)?

【问题讨论】:

    标签: perl locallib


    【解决方案1】:

    更新:一段时间以来,INSTALL_BASE 一直在制作更好的目录结构,以避免新安装时出现此问题。

    这就是 install::lib 使用的perl Makefile.PL INSTALL_BASE=... 约定(以及Build.PL 的对应约定)很烂的原因。

    删除(或重命名目录以便备份)是最简单的解决方案。您可以通过查找 .pm 文件来找出您安装的内容。

    cd ~
    mv perl5{,16}
    cd perl516/lib/perl5
    find -name '*.pm' | xargs perl -MConfig -E'
       for (@ARGV) {
          s!^\./!!;
          s!^5\.\d+\.\d+/!!;
          s!^x86_64-linux/!!;
          s!^auto/!!;
          s!\.pm\z!!;
          s!/!::!g;
          say;
       }
    ' | xargs cpan
    

    (先进行试运行——没有尾随 | xargs cpan 的运行。)

    请注意,如果您不想受管理员升级的摆布,您可以使用 perlbrew 在您的主目录中轻松安装整个 Perl 版本。

    【讨论】:

    • 谢谢 - 我用你的回答生成了一个模块列表,然后通过perl -MCPAN -Mlocal::lib -e "CPAN::install($module)" 运行这些模块(根据local::lib 文档)。我在它周围放了一些包装代码来重新安装local::lib 并优雅地处理错误,它似乎工作正常,尽管它确实需要很长时间并且尝试安装很多不存在的模块。
    【解决方案2】:

    如果您使用的是cpanm,您可以使用-L--reinstall 开关强制它在您的local::lib 位置重建模块:

    list_modules | cpanm -L ~/perl5 --reinstall

    其中list_modules 是一个将模块名称提供给cpanm 的脚本(cpanm 也有一个-f 选项)。这个脚本可能像上面的@ikegami 或类似cpan-outdated 的东西(但是它只列出了过时的模块)。这里有一个 最近对我最有效的 hackish 尝试(注意:ikegami 的可能更好) - 当它失败或脚本给 cpanm 一个它无法识别的模块名称时,cpanm 继续运行并且似乎没有破坏任何东西(但要备份):

    cd $PERL_LOCAL_LIB_ROOT  
    perl -MFile::Find -MConfig -E'
          find { 
            wanted => sub { 
                           $mod = $_ if /\.pm\z/; 
                           $mod =~ s/lib\/perl5\/auto\/.*//g;
                           $mod =~ s/lib\/perl5\/\Q$Config{archname}\E\/.*//g;
                           $mod =~ s/lib\/perl5\///g;
                           push @mods, $mod unless $mod =~ /^$/;
                          },no_chdir=>1 
               },"lib/perl5"; @modhash{@mods}=(); say for sort keys %modhash '
    

    通过更改File::Findwanted() 中找到的位置和内容,您可以将不同的模块列表提供给cpanm。如果cpancpanm 有一个内部_method-switch 允许您强制重建local::lib 安装的使用XS 的模块,那就太好了。有这种事吗?

    正是cpanmcarton(以及看到node.js 工具npm 的实际应用)启发了我进行更多基于local::lib 的安装。现在,与 perl (cpan) 一起提供的 CORE 捆绑“CPAN 客户端”似乎变得更加自动化并且更易于使用。我真的很喜欢local::lib,因为它允许您使用系统perl,但无需系统级权限即可管理您自己的模块堆栈。但是,如果您使用perlbrew 运行“非系统”(“本地”)perl,则总体上更容易管理更改和升级。当然你可以这样做并且仍然有local::libcarton。管理目录或应用程序特定的模块堆栈。

    1)。另一种升级方法是使用perllocal 生成您当前安装的模块的列表(NB我不完全确定perllocal.pod 是否保持在可靠/有用的状态)。 [编辑:事实上,perllocal 保留了您已安装模块的历史,而不是当前已安装模块的列表。你会想要过滤这个,否则你最终会一个接一个地重新安装整个系列的模块版本!)。这个 perlmonks 节点展示了如何清理你的perllocal.pod:http://www.perlmonks.org/?node_id=483020。我更喜欢保留历史记录。]

    要解析perllocal.pod 以获取cpanm 的输入,请搜索文件并将匹配项保存在一个数组中,然后将它们除以两个以从数组元素(key,value,key,value)中创建一个散列。文件中较新的安装和版本号较低,因此您可以创建一个以模块名称作为键的哈希,并由以后的条目更新值:

     perl -ne 'push @arr, grep {defined}
     (/\A=head2.*:\s+C<Module>\s+L<(.*)\||.*C<VERSION:\s(.*)>\Z/msx); }{
     %h = map{ split/,/,$_,2 } @arr; print "$_\@$h{$_}\n" for keys %h' perllocal.pod
    

    (注意:这不会错误检查 - perllocal.pod 中的条目偶尔会缺少 VERSION 数据和其他奇怪的东西,所以要小心。)

    2)。 但是 与 ilmari 在 IRC 上的#perl-help 中提到的 shell 脚本相比,这种方法显得相形见绌。它用 jq - 你真正需要的命令行实用程序(在此之后你会更想要它)。如果您使用cpanm 安装模块,它将创建install.json 文件。您可以利用它来制作列表以提供给 cpanm 以重新安装您当前的模块集:

     find ~/perl5/ -name install.json -exec jq '.name + "@" + .version' {} +
    

    非常快速,非常简单,您可以将其与使用curlcpanm 方法结合使用以自行安装以重建您的模块。

    3)。如果您使用perlbrew 来管理您的perl 安装,您可以easily copy and reinstall 您的所有模块从一个perl 版本到另一个版本。

    HTH!

    【讨论】:

    • 我对我的进行了相同的更改,但我恢复了它。我们想要最初安装的 Perl (x86_64-linux) 的 archname,而不是当前安装的(可能不同)。我会让你自己决定你想要你的代码是什么。
    • 呃哦,这是否意味着我必须记住/usr/local/lib/perl5/site_perl/5.16/mach/$HOME/perl5/lib/perl5/amd64-freebsd-thread-multi 之间的区别... :-) 无论如何,我看到了有关可能发生的升级的鸡/蛋问题。我非常喜欢您使用mv perl5{,16}find 进行的简单备份/重新安装方法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-27
    • 2021-12-09
    • 2012-07-25
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多