CPAN-Visitor
view release on metacpan or search on metacpan
lib/CPAN/Visitor.pm view on Meta::CPAN
use 5.006;
use strict;
use warnings;
package CPAN::Visitor;
# ABSTRACT: Generic traversal of distributions in a CPAN repository
our $VERSION = '0.005';
use autodie;
use Archive::Extract 0.34 ();
use File::Find ();
use File::pushd 1.00 ();
use File::Temp 0.20 ();
use Path::Class 0.17 ();
use Parallel::ForkManager 0.007005 ();
use Moose 0.93 ;
use MooseX::Params::Validate 0.13;
use namespace::autoclean 0.09 ;
has 'cpan' => ( is => 'ro', required => 1 );
has 'quiet' => ( is => 'ro', default => 0 );
has 'stash' => ( is => 'ro', isa => 'HashRef', default => sub { {} } );
has 'files' => ( is => 'ro', isa => 'ArrayRef', default => sub { [] } );
sub BUILD {
my $self = shift;
unless (
-d $self->cpan &&
-d Path::Class::dir($self->cpan, 'authors', 'id')
) {
die "'cpan' parameter must be the root of a CPAN repository";
}
}
#--------------------------------------------------------------------------#
# selection methods
#--------------------------------------------------------------------------#
my $archive_re = qr{\.(?:tar\.(?:bz2|gz|Z)|t(?:gz|bz)|zip)$}i;
sub select {
my ($self, %params) = validated_hash( \@_,
match => { isa => 'RegexpRef | ArrayRef[RegexpRef]', default => [qr/./] },
exclude => { isa => 'RegexpRef | ArrayRef[RegexpRef]', default => [] },
subtrees => { isa => 'Str | ArrayRef[Str]', default => [] },
all_files => { isa => 'Bool', default => 0 },
append => { isa => 'Bool', default => 0 },
);
# normalize to arrayrefs
for my $k ( qw/match exclude subtrees/ ) {
next unless exists $params{$k};
next if ref $params{$k} && ref $params{$k} eq 'ARRAY';
$params{$k} = [ $params{$k} ];
}
# determine search dirs
my $id_dir = Path::Class::dir($self->cpan, qw/authors id/);
my @search_dirs = map { $id_dir->subdir($_)->stringify } @{$params{subtrees}};
@search_dirs = $id_dir->stringify if ! @search_dirs;
# perform search
my @found;
File::Find::find(
{
no_chdir => 1,
follow => 0,
preprocess => sub { my @files = sort @_; return @files },
wanted => sub {
return unless -f;
return unless $params{all_files} || /$archive_re/;
for my $re ( @{$params{exclude}} ) {
return if /$re/;
}
for my $re ( @{$params{match}} ) {
return if ! /$re/;
}
(my $f = Path::Class::file($_)->relative($id_dir)) =~ s{./../}{};
( run in 0.514 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )