CPAN-Mini
view release on metacpan or search on metacpan
lib/CPAN/Mini.pm view on Meta::CPAN
Carp::croak "no write permission to local mirror" unless -w $self->{local};
Carp::croak "no remote mirror supplied" unless $self->{remote};
$self->{remote} = "$self->{remote}/" if substr($self->{remote}, -1) ne '/';
my $version = $class->VERSION;
$version = 'v?' unless defined $version;
$self->{__lwp} = LWP::UserAgent->new(
agent => "$class/$version",
env_proxy => 1,
($self->{no_conn_cache} ? () : (keep_alive => 5)),
($self->{timeout} ? (timeout => $self->{timeout}) : ()),
);
unless ($self->{offline}) {
my $test_uri = URI->new_abs(
'modules/02packages.details.txt.gz',
$self->{remote},
)->as_string;
Carp::croak "unable to contact the remote mirror"
unless eval { $self->__lwp->head($test_uri)->is_success };
}
return $self;
}
sub __lwp { $_[0]->{__lwp} }
#pod =method mirror_indices
#pod
#pod $minicpan->mirror_indices;
#pod
#pod This method updates the index files from the CPAN.
#pod
#pod =cut
sub _fixed_mirrors {
qw(
authors/01mailrc.txt.gz
modules/02packages.details.txt.gz
modules/03modlist.data.gz
);
}
sub _scratch_dir {
my ($self) = @_;
$self->{scratch} ||= File::Temp::tempdir(CLEANUP => 1);
return $self->{scratch};
}
sub mirror_indices {
my $self = shift;
$self->_make_index_dirs($self->_scratch_dir);
for my $path ($self->_fixed_mirrors) {
my $local_file = File::Spec->catfile($self->{local}, split m{/}, $path);
my $scratch_file = File::Spec->catfile(
$self->_scratch_dir,
split(m{/}, $path),
);
File::Copy::copy($local_file, $scratch_file);
utime((stat $local_file)[ 8, 9 ], $scratch_file);
$self->mirror_file($path, undef, { to_scratch => 1 });
}
}
sub _mirror_extras {
my $self = shift;
for my $path (@{ $self->{also_mirror} }) {
$self->mirror_file($path, undef);
}
}
sub _make_index_dirs {
my ($self, $base_dir, $dir_mode, $trace) = @_;
$base_dir ||= $self->_scratch_dir;
$dir_mode = 0711 if !defined $dir_mode; ## no critic Zero
$trace = 0 if !defined $trace;
for my $index ($self->_fixed_mirrors) {
my $dir = File::Basename::dirname($index);
my $needed = File::Spec->catdir($base_dir, $dir);
File::Path::mkpath($needed, { verbose => $trace, mode => $dir_mode });
die "couldn't create $needed: $!" unless -d $needed;
}
}
sub _install_indices {
my $self = shift;
$self->_make_index_dirs(
$self->{local},
$self->{dirmode},
$self->{log_level} eq 'debug',
);
for my $file ($self->_fixed_mirrors) {
my $local_file = File::Spec->catfile($self->{local}, split m{/}, $file);
unlink $local_file;
File::Copy::copy(
File::Spec->catfile($self->_scratch_dir, split m{/}, $file),
$local_file,
);
$self->{mirrored}{$local_file} = 1;
}
}
#pod =method mirror_file
#pod
#pod $minicpan->mirror_file($path, $skip_if_present)
#pod
#pod This method will mirror the given file from the remote to the local mirror,
#pod overwriting any existing file unless C<$skip_if_present> is true.
#pod
#pod =cut
sub mirror_file {
my ($self, $path, $skip_if_present, $arg) = @_;
$arg ||= {};
# full URL
my $remote_uri = eval { $path->isa('URI') }
? $path
: URI->new_abs($path, $self->{remote})->as_string;
# native absolute file
my $local_file = File::Spec->catfile(
$arg->{to_scratch} ? $self->_scratch_dir : $self->{local},
split m{/}, $path
);
my $checksum_might_be_up_to_date = 1;
if ($skip_if_present and -f $local_file) {
## upgrade to checked if not already
$self->{mirrored}{$local_file} ||= 1;
} elsif (($self->{mirrored}{$local_file} || 0) < 2) {
## upgrade to full mirror
$self->{mirrored}{$local_file} = 2;
File::Path::mkpath(
File::Basename::dirname($local_file),
{
verbose => $self->{log_level} eq 'debug',
mode => $self->{dirmode},
},
);
$self->log($path, { no_nl => 1 });
my $res = eval { $self->{__lwp}->mirror($remote_uri, $local_file) };
if (! $res) {
my $error = $@ || "(unknown error)";
$self->log(" ... resulted in an HTTP client error");
$self->log_warn("$remote_uri: $error");
return;
} elsif ($res->is_success) {
utime undef, undef, $local_file if $arg->{update_times};
$checksum_might_be_up_to_date = 0;
$self->_recent($path);
$self->log(" ... updated");
$self->{changes_made}++;
} elsif ($res->code != 304) { # not modified
$self->log(" ... resulted in an HTTP error with status " . $res->code);
$self->log_warn("$remote_uri: " . $res->status_line);
return;
} else {
$self->log(" ... up to date");
}
}
if ($path =~ m{^authors/id}) { # maybe fetch CHECKSUMS
my $checksum_path
= URI->new_abs("CHECKSUMS", $remote_uri)->rel($self->{remote})->as_string;
if ($path ne $checksum_path) {
$self->mirror_file($checksum_path, $checksum_might_be_up_to_date);
}
}
}
#pod =begin devel
#pod
#pod =method _filter_module
#pod
#pod next
#pod if $self->_filter_module({ module => $foo, version => $foo, path => $foo });
#pod
#pod This method holds the filter chain logic. C<update_mirror> takes an optional
( run in 1.718 second using v1.01-cache-2.11-cpan-483215c6ad5 )