Подтвердить что ты не робот

Как определить зависимости CPAN до развертывания проекта Perl?

Есть ли у кого-нибудь предложения по хорошему подходу к поиску всех зависимостей CPAN, которые могли возникнуть в индивидуальном проекте разработки. Как правило, ваша локальная среда разработки редко соответствует вашему живому, и по мере того, как вы создаете все больше проектов, вы, как правило, создаете локальную библиотеку установленных модулей. Это приводит к тому, что вы не обязательно замечаете, что ваш последний проект имеет требование к неосновному модулю. Поскольку обычно требуется упаковать весь проект для развертывания в другую группу (в нашем случае наша операционная группа), важно знать, какие модули должны быть включены в пакет.

Есть ли у кого-нибудь идеи в этой проблеме.

Спасибо

Петр

4b9b3361

Ответ 1

У меня была эта проблема. Devel::Modlist (как предложено этим ответом) используется динамический подход. Он сообщает модули, которые были загружены во время определенного запуска вашего script. Это улавливает модули, которые загружаются любыми способами, но может не вызывать условные требования. То есть, если у вас есть такой код:

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 видеть их.)

Ответ 2

Вы можете использовать онлайн-сервис в deps.cpantesters.org, который предоставит вам много полезных данных зависимостей. Все модули CPAN уже имеют ссылку на сайт зависимостей (в правой части страницы модуля).

Ответ 3

В прошлом я использовал Devel:: Modlist, который достаточно хорош, позволяя вам пойти

perl -d:Modlist script.pl

Получить список необходимых модулей.

Ответ 4

У меня есть система сборки на основе Make-for для всех моих приложений на C/С++ (как на базе ПК, так и для различных встроенных проектов), и, хотя мне нравится, что я могу сделать сборку верхнего уровня на новой машине и проверить все (я проверяю свои инструментальные средства на контроль версий: D), я был расстроен тем, что не делал то же самое для интерпретируемых языков, которые в настоящее время не имеют makefile в моей системе сборки.

Я соблазн написать script, который:

  • выполняет поиск моего репозитория контроля версий для файлов с расширением .pl или .pm
  • запускает perl -d:Modlist на них (спасибо Вагнерру!)
  • объединить его в список необходимых модулей
  • и, наконец, сравнить его со списком установленных модулей.

Затем я выполнил бы это script как часть моей сборки верхнего уровня, так что кто-нибудь, строивший что-нибудь, узнает, есть ли у них все необходимое для запуска каждого perl script, полученного из контроля версий. Если есть какой-то perl script, они никогда не запускаются и не хотят, чтобы CPAN устанавливал все необходимое для его запуска, им пришлось бы удалить нежелательный script из своего жесткого диска, поэтому средство проверки зависимостей не сможет их найти. Я знаю, как изменить клиента perforce, чтобы оставить определенные подкаталоги, когда вы выполняете "синхронизацию", мне нужно будет понять это для подрывной деятельности...

Я предлагаю сделать проверку зависимостей одним script, который ищет файлы pl, а не отдельный makefile для проверки зависимостей для каждого script или на основе жестко закодированного списка имен script, Если вы выберете метод, требующий действия пользователя для проверки зависимостей script, люди забудут выполнить это действие, так как они смогут запустить script, даже если они не выполняют проверку зависимостей.

Как я уже сказал, я еще не реализовал вышеупомянутое, но этот вопрос побудил меня попытаться это сделать. Я отправлю обратно с моим опытом после того, как я закончил.

Ответ 5

"Очевидный" способ - болезненный, но умеренно эффективный - это установить совершенно новую сборку базы Perl в некотором некотором местоположении (вы не собираетесь использовать это в процессе производства), а затем попытаться установить модуль с использованием этой "виргинской" версии Perl. Вы найдете все недостающие зависимости. В первый раз это может быть болезненным. После первого раза у вас уже будет большая часть зависимостей, и это будет значительно менее болезненным.

Подумайте о том, как запустить собственный локальный репозиторий модулей CPAN - чтобы вам не всегда приходилось загружать код. Также рассмотрите, как вы очищаете устаревшие модули.

Ответ 6

use Acme::Magic::Pony;

Серьезно. Он автоматически установит модули Perl, если они не исчезнут. См. Страницу Acme:: Magic:: Pony в CPAN.

Ответ 7

Его ответ "лошадь, которая болтала", но у меня есть привычка создавать файл 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 modules
XML::Twig
XML::Writer
Perl6::Say
Moose

Поместите это в ~/.cpan/Bundle/(или там, где живет ваш .cpan), а затем установите "Bundle:: Baz" как обычный модуль CPAN. Затем устанавливаются все модули, перечисленные в разделе "= head1 CONTENTS".

Ответ 8

Вот функция 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
}