CPAN-Visitor

 view release on metacpan or  search on metacpan

lib/CPAN/Visitor.pm  view on Meta::CPAN

  }

  if ( ! $extract_ok ) {
    warn "Couldn't extract '$job->{distpath}'\n" if $Archive::Extract::WARN;
    return;
  }

  # most distributions unpack a single directory that we must enter
  # but some behave poorly and unpack to the current directory
  my @children = Path::Class::dir()->children;
  if ( @children == 1 && -d $children[0] ) {
    return Path::Class::dir($job->{tempdir}, $children[0])->absolute->stringify;
  }
  else {
    return Path::Class::dir($job->{tempdir})->absolute->stringify;
  }
}

sub _enter {
  my $job = shift;
  my $curdir = Path::Class::dir()->absolute;
  my $target_dir = $job->{result}{extract} or return;
  if ( -d $target_dir ) {
    unless ( -x $target_dir ) {
        warn "Directory '$target_dir' missing +x; trying to fix it\n"
            unless $job->{quiet};
        chmod 0755, $target_dir;
    }
    chdir $target_dir;
  }
  else {
    warn "Can't chdir to directory '$target_dir'\n"
      unless $job->{quiet};
    return;
  }
  return $curdir;
}

sub _visit { 1 } # do nothing

# chdir out and clean up
sub _leave {
  my $job = shift;
  chdir $job->{result}{enter};
  return 1;
}

sub _finish { 1 } # no special finish action

#--------------------------------------------------------------------------#
# iteration methods
#--------------------------------------------------------------------------#

# iterate()
#
# Arguments:
#
#   jobs -- if greater than 1, distributions are processed in parallel
#           via Parallel::ForkManager
#
# iterate() takes several optional callbacks which are run in the following
# order.  Callbacks get a single hashref argument as described above under
# default actions.
#
#   check -- whether the distribution should be processed; goes to next file
#            if false; default is always true
#
#   start -- used for any setup, logging, etc; default does nothing
#
#   extract -- extracts a distribution into a temp directory or otherwise
#              prepares for visiting; skips to finish action if it returns
#              a false value; default returns the path to the extracted
#              directory
#
#   enter -- skips to the finish action if it returns false; default takes
#            the result of extract, chdir's into it, and returns the
#            original directory
#
#   visit -- examine the distribution or otherwise do stuff; the default
#            does nothing;
#
#   leave -- default returns to the original directory (the result of enter)
#
#   finish -- any teardown processing, logging, etc.

sub iterate {
  my ($self, %params) = validated_hash( \@_,
    jobs    => { isa => 'Int', default => 0 },
    check   => { isa => 'CodeRef', default => \&_check },
    start   => { isa => 'CodeRef', default => \&_start },
    extract => { isa => 'CodeRef', default => \&_extract },
    enter   => { isa => 'CodeRef', default => \&_enter },
    visit   => { isa => 'CodeRef', default => \&_visit },
    leave   => { isa => 'CodeRef', default => \&_leave },
    finish  => { isa => 'CodeRef', default => \&_finish },
  );

  my $pm = Parallel::ForkManager->new( $params{jobs} > 1 ? $params{jobs} : 0 );
  for my $distfile ( @{ $self->files } ) {
    $pm->start and next;
    $self->_iterate($distfile, \%params);
    $pm->finish;
  }
  $pm->wait_all_children;
  return 1;
}

sub _iterate {
  my ($self, $distfile, $params) = @_;
  my $curdir = Path::Class::dir()->absolute;

  # $job outside eval so that later chdir to original directory
  # happens before $job is destroyed and any tempdirs deleted
  my $job;
  eval {
    $job = {
        distfile  => $distfile,
        distpath  => $self->_fullpath($distfile),
        tempdir   => File::Temp->newdir(),
        stash     => $self->stash,
        quiet     => $self->quiet,

lib/CPAN/Visitor.pm  view on Meta::CPAN

=item *

C<leave> — code reference callback

=item *

C<finish> — code reference callback

=back

See L</ACTION CALLBACKS> for more.  Generally, you only need to provide the
C<visit> callback, which is called from inside the unpacked distribution
directory.

The C<iterate> method always returns true.

=for Pod::Coverage BUILD

=head1 ACTION CALLBACKS

Each selected distribution is processed with a series of callback
functions.  These are each passed a hash-ref with information about
the particular distribution being processed.

  sub _my_visit {
    my $job = shift;
    # do stuff
  }

The job hash-ref is initialized with the following fields:

=over 4

=item *

C<distfile> — the unique, short CPAN distfile name, e.g. DAGOLDEN/CPAN-Visitor-0.001.tar.gz

=item *

C<distpath> — the absolute path the distribution archive, e.g. /my/cpan/authors/id/D/DA/DAGOLDEN/CPAN-Visitor-0.001.tar.gz

=item *

C<tempdir>  — a File::Temp directory object for extraction or other things

=item *

C<stash>    — the 'stash' hashref from the Visitor object

=item *

C<quiet>    — the 'quiet' flag from the Visitor object

=item *

C<result>   — an empty hashref to start; the return values from each action are added and may be referenced by subsequent actions

=back

The C<result> field is used to accumulate the return values from action
callbacks.  For example, the return value from the default 'extract' action is
the unpacked distribution directory:

  $job->{result}{extract} # distribution directory path

You do not need to store the results yourself — the C<iterate> method
takes care of it for you.

Callbacks occur in the following order.  Some callbacks skip further
processing if the return value is false.

=over 4

=item *

C<check> — determines whether the distribution should be processed; goes to next file if false; default is always true

=item *

C<start> — used for any setup, logging, etc; default does nothing

=item *

C<extract> — operate on the tarball to prepare for visiting; skips to finish action if it returns a false value; the default extracts a distribution into a temp directory and returns the path to the extracted directory; if the C<stash> has a true v...

=item *

C<enter> — skips to the finish action if it returns false; default takes the result of extract, chdir's into it, and returns the original directory; if the extract result is missing the +x permissions, this will attempt to add it before calling chd...

=item *

C<visit> — examine the distribution or otherwise do stuff; the default does nothing;

=item *

C<leave> — default returns to the original directory (the result of enter)

=item *

C<finish> — any teardown processing, logging, etc.

=back

These allow complete customization of the iteration process.  For example,
one could do something like this:

=over 4

=item *

replace the default C<extract> callback with one that returns an arrayref of distribution files without actually unpacking it into a physical directory

=item *

replace the default C<enter> callback with one that does nothing but return a true value; replace the default C<leave> callback likewise

=item *

have the C<visit> callback get the C<< $job->{result}{extract} >> listing and examine it for the presence of certain files

=back

This could potentially speed up iteration if only the file names within
the distribution are of interest and not the contents of the actual files.

=head1 SEE ALSO

=over 4



( run in 2.410 seconds using v1.01-cache-2.11-cpan-cdf2f3d4e48 )