CPAN-Site
view release on metacpan or search on metacpan
lib/CPAN/Site/Index.pm view on Meta::CPAN
# Copyrights 1998,2005-2022 by [Mark Overmeer].
# For other contributors see ChangeLog.
# See the manual pages for details on the licensing terms.
# Pod stripped from pm file by OODoc 2.03.
# This code is part of distribution CPAN::Site.
# Copyright Mark Overmeer. Licensed under the same terms as Perl itself.
package CPAN::Site::Index;
use vars '$VERSION';
$VERSION = '1.17';
use base 'Exporter';
use warnings;
use strict;
our @EXPORT_OK = qw/cpan_index cpan_mirror/;
our $VERSION; # required in test-env
use Log::Report 'cpan-site', syntax => 'SHORT';
use version;
use File::Find qw/find/;
use File::Copy qw/copy/;
use File::Basename qw/basename dirname/;
use HTTP::Date qw/time2str/;
use File::Spec::Functions qw/catfile catdir splitdir/;
use LWP::UserAgent ();
use Archive::Tar ();
use Archive::Zip qw(:ERROR_CODES :CONSTANTS);
use CPAN::Checksums qw(updatedir); # horrible function name
use IO::Zlib ();
my $tar_gz = qr/ \.tar\.gz$ | \.tar\.Z$ | \.tgz$/xi;
my $zip = qr/ \.zip$ /xi;
my $cpan_update = 0.04; # days between reload of full CPAN index
my $ua;
sub safe_copy($$);
sub cpan_index($@);
sub register($$$);
sub package_inventory($$;$);
sub package_on_usual_location($);
sub inspect_archive;
sub inspect_tar_archive($$);
sub inspect_zip_archive($$);
sub collect_package_details($$$);
sub update_global_cpan($$);
sub load_file($$);
sub merge_global_cpan($$$);
sub create_details($$$$$);
sub calculate_checksums($$);
sub read_details($);
sub remove_expired_details($$$);
sub mkdirhier(@);
sub cpan_mirror($$$@);
sub safe_copy($$)
{ my ($from, $to) = @_;
trace "copy $from to $to";
copy $from, $to
or fault __x"cannot copy {from} to {to}", from => $from, to => $to;
}
sub cpan_index($@)
{ my ($mycpan, $globalcpan, %opts) = @_;
my $lazy = $opts{lazy};
my $fallback = $opts{fallback};
my $undefs = exists $opts{undefs} ? $opts{undefs} : 1;
unless($ua)
{ $ua = LWP::UserAgent->new;
$ua->env_proxy if $opts{env_proxy};
}
-d $mycpan
or error __x"archive top '{dir}' is not a directory"
, dir => $mycpan;
my $program = basename $0;
$VERSION ||= 'undef'; # test env at home
trace "$program version $VERSION";
my $global = catdir $mycpan, 'global';
my $mods = catdir $mycpan, 'modules';
my $authors = catdir $mycpan, 'authors';
mkdirhier $global, $mods, $authors;
my $globdetails = update_global_cpan $mycpan, $globalcpan;
# Create mailrc and modlist
safe_copy catfile($global, '01mailrc.txt.gz')
, catfile($authors, '01mailrc.txt.gz');
safe_copy catfile($global, '03modlist.data.gz')
, catfile($mods, '03modlist.data.gz');
# Create packages details
my $details = catfile $mods, '02packages.details.txt.gz';
my $newlist = catfile $mods, '02packages.details.tmp.gz';
my $newer;
my $reuse_dists = {};
if($lazy && -f $details)
{ $reuse_dists = read_details $details;
$newer = -M $details;
lib/CPAN/Site/Index.pm view on Meta::CPAN
sub collect_package_details($$$)
{ my ($fn, $dist) = (shift, shift);
my @lines = split /\r?\n/, ${shift()};
my $in_pod = 0;
my $package;
local $VERSION = undef; # may get destroyed by eval
while(@lines)
{ local $_ = shift @lines;
last if m/^__(?:END|DATA)__$/;
$in_pod = ($1 ne 'cut') if m/^=(\w+)/;
next if $in_pod || m/^\s*#/;
$_ .= shift @lines
while @lines && m/package|use|VERSION/ && !m/[;{]/;
if( m/^\s* package \s* ((?:\w+\:\:)*\w+) (?:\s+ (\S*))? \s* [;{]/x )
{ my ($thispkg, $v) = ($1, $2);
my $thisversion;
if($v)
{ $thisversion = eval {qv($v)};
alert __x"illegal version for {pkg}, found '{version}': {err}"
, pkg => $thispkg, version => $v, err => $@ if $@;
}
# second package in file?
register $package, $VERSION, $dist
if defined $package;
($package, $VERSION) = ($thispkg, $thisversion);
trace "pkg $package from $fn";
}
if( m/^\s* \$ ${package}::VERSION \s* = \s* ["']?(\w+?)["']? \s* ;/x )
{ $VERSION = $1;
}
if( !$VERSION && m/^ (?:use\s+version\s*;\s*)?
(?:our)? \s* \$ ((?: \w+\:\:)*) VERSION \s* \= (.*)/x )
{ defined $2 or next;
my ($ns, $vers) = ($1, $2);
# some versions of CPAN.pm do contain lines like "$VERSION =~ ..."
# which also need to be processed.
eval "\$VERSION =$vers";
if(defined $VERSION)
{ ($package = $ns) =~ s/\:\:$//
if length $ns;
trace "pkg $package version $VERSION";
}
}
}
$VERSION = $VERSION->numify if ref $VERSION;
register $package, $VERSION, $dist
if defined $package;
}
sub update_global_cpan($$)
{ my ($mycpan, $globalcpan) = @_;
my $global = catdir $mycpan, 'global';
my ($mailrc, $globdetails, $modlist) =
map { catfile $global, $_ }
qw/01mailrc.txt.gz 02packages.details.txt.gz 03modlist.data.gz/;
return $globdetails
if -f $globdetails && -f $globdetails && -f $modlist
&& -M $globdetails < $cpan_update;
info "(re)loading global CPAN files";
mkdirhier $global;
load_file "$globalcpan/authors/01mailrc.txt.gz", $mailrc;
load_file "$globalcpan/modules/02packages.details.txt.gz", $globdetails;
load_file "$globalcpan/modules/03modlist.data.gz", $modlist;
$globdetails;
}
sub load_file($$)
{ my ($from, $to) = @_;
my $response = $ua->get($from, ':content_file' => $to);
return if $response->is_success;
unlink $to;
error __x"failed to get {uri} for {to}: {err}"
, uri => $from, to => $to, err => $response->status_line;
}
sub merge_global_cpan($$$)
{ my ($mycpan, $pkgs, $globdetails) = @_;
trace "merge packages with CPAN core list in $globdetails";
my $cpan_pkgs = read_details $globdetails;
while(my ($cpandist, $cpanpkgs) = each %$cpan_pkgs)
{ foreach (@$cpanpkgs)
{ my ($pkg, $version) = @$_;
next if exists $pkgs->{$pkg};
$pkgs->{$pkg} = [$version, $cpandist];
}
}
}
sub create_details($$$$$)
{ my ($details, $filename, $pkgs, $lazy, $undefs) = @_;
trace "creating package details in $filename";
my $fh = IO::Zlib->new($filename, 'wb')
or fault __x"generating gzipped {fn}", fn => $filename;
my $lines = keys %$pkgs;
my $date = time2str time;
my $how = $lazy ? "lazy" : "full";
info "produced list of $lines packages $how";
my $program = basename $0;
my $module = __PACKAGE__;
( run in 0.909 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )