Pergunta

Alguém tem alguma sugestão para uma abordagem boa para encontrar todas as dependências do CPAN que possam ter surgido em um bespoke projeto de desenvolvimento. Como tende a ser o caso do seu ambiente de desenvolvimento local raramente coincide com o seu um ao vivo e como você construir mais e mais projetos que tendem a construir uma biblioteca local de módulos instalados. Estes, então, levar a você não necessariamente perceber que seu projeto mais recente tem uma exigência em um módulo non-core. Como não é geralmente um requisito para embalar todo o projeto para implantação de um outro grupo (no nosso caso, a nossa equipe de operações), é importante saber o que os módulos devem ser incluídos no pacote.

Alguém tem alguma insights sobre o problema.

Graças

Peter

Foi útil?

Solução

Eu tive esse problema sozinho. Devel :: Modlist (como sugerido por this resposta ) tem uma abordagem dinâmica. Ele relata os módulos que foram realmente carregados durante um determinado prazo do seu script. Esta pega módulos que são carregados por qualquer meio, mas não pode pegar requisitos condicionais. Ou seja, se você tem um código como este:

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

e $some_condition passa a ser falsa, Devel::Modlist não irá lista Some::Module como um requisito.

Eu decidi usar Module :: ExtractUse . Ele faz uma análise estática, o que significa que ele irá sempre pegar Some::Module no exemplo acima. Por outro lado, ele não pode fazer nada sobre o código como:

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

É claro, você pode usar ambas as abordagens e, em seguida, combinar as duas listas.

De qualquer forma, aqui está a solução que eu vim com:

#! /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

Você iria executar este como:

perl finddeps.pl scriptToCheck.pl otherScriptToCheck.pl

Ela imprime uma lista de todos os módulos não essenciais necessárias para executar os scripts listados. (A menos que eles fazem truques extravagantes com módulo de carga que prevent Module :: ExtractUse de vê-los.)

Outras dicas

Você pode usar o serviço web online em deps.cpantesters.org que irá fornecer-lhe muitos dependência útil dados. Todos os módulos no CPAN já tem o link para o site de dependência (no lado direito da página do módulo).

No passado, eu usei Devel :: Modlist que é razoavelmente bom permitindo -lhe para ir

perl -d:Modlist script.pl

Para obter uma lista dos módulos necessários.

Eu tenho um sistema de construção à base de Marca para todas as aplicações meus C / C ++ (ambos baseados em PC e para vários projetos incorporados), e enquanto eu adoro ser capaz de fazer uma compilação de nível superior em uma máquina fresca e verificar todas as dependências estão no lugar (eu verifico meus toolchains no controle de revisão: D)., eu tenho sido frustrado por não fazer o mesmo para linguagens interpretadas que atualmente não têm makefile no meu sistema de compilação

Estou tentado a escrever um script que:

  • procura meu repositório de controle de revisão para arquivos com a extensão .pl ou .pm
  • corre perl -d:Modlist sobre eles (graças Vagnerr!)
  • concatenando-lo à lista de módulos necessários
  • e, finalmente, comparando-a com a lista de módulos instalados.

Eu, em seguida, executar esse script como parte do meu alto nível de construção, para que qualquer pessoa construir qualquer coisa vai saber se eles têm tudo que precisam para executar cada script perl que tenho de controle de revisão. Se houver algum script perl eles nunca correr e não quero CPAN instalar o que é necessário para executá-lo, eles teriam que remover o script indesejada de seu disco rígido, de modo que o verificador de dependência não pode encontrá-los. Eu sei como modificar um cliente forçosamente a deixar de fora alguns subdiretórios quando você faz um 'sync', eu vou ter que descobrir isso por subversão ...

Eu sugiro fazer o verificador de dependência de um único script que procura por arquivos pl, ao contrário de um makefile indivíduo para verificar dependências para cada script, ou com base em uma lista codificada de nomes de script. Se você escolher um método que requer ação do usuário para ter um script verificados para dependências, as pessoas vão se esqueça de executar essa ação, uma vez que será capaz de executar o script, mesmo que eles não fazem a verificação de dependência.

Como eu disse, eu não ter implementado o ainda acima, mas esta questão levou-me a tentar fazê-lo. Vou postar de volta com a minha experiência depois que eu sou feito.

A maneira 'óbvia' - doloroso, mas moderadamente eficaz - é a instalação de uma marca nova compilação da base de Perl em alguns fora do caminho localização (você não vai usar isso em produção), e em seguida, tentar instalar o seu módulo usando esta versão 'virgem' de Perl. Você vai encontrar todas as dependências que estão faltando. Pela primeira vez, isso pode ser doloroso. Depois da primeira vez, você já tem a maioria das dependências coberto, e será muito menos doloroso.

Considere executar o seu próprio repositório local de módulos CPAN - de modo que você não vai ter sempre para baixar o código. Considere também como você limpar o fora de módulos de data.

use Acme::Magic::Pony;

A sério. Vai auto-instalar módulos Perl se transformar-se em falta. Veja a Acme :: Magic: :. página Pony no CPAN

É um "cavalo que está trancada" resposta, mas eu tenho o hábito de criar um arquivo de Pacote com todas as minhas dependências. Assim, quando eu vou para um novo ambiente Eu apenas copiá-lo e instalá-lo.

Para por exemplo. Eu tenho um 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

Coloque este em ~ / .cpan / Bundle / (ou onde quer que suas vidas .cpan) e depois instalar 'Bundle :: Baz' como um módulo CPAN normal. Isso, então, instala todos os módulos listados em "= head1 CONTEÚDO".

Aqui está uma função rapidinha bash (usando a excelente 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
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top