App-ucpan
view release on metacpan or search on metacpan
script/ucpan view on Meta::CPAN
my $flag = '';
if ( -d $org ) {
$flag = '/J';
rmdir $dest;
}
!system qq{mklink $flag "$dest" "$org" >NUL};
};
}
#== customizing cpanm!!
eval qq{require '$cpanm_file'};
my $app = App::cpanminus::script->new;
# give undef as dummy. this is needed for build argv correctly
$app->parse_options( @{ $CONFIG->{updater_options} }, undef );
pop @{ $app->{argv} };
{
no strict 'refs';
$org_m
= +{ map { $_ => \&{ "App::cpanminus::script::" . $_ } }
qw/_diag install_module fetch_module configure build test install/
};
}
my $pid;
no warnings 'once';
if (WIN32) {
*App::cpanminus::script::run_timeout = sub {
my ( $self, $cmd, $timeout ) = @_;
$cmd = $self->shell_quote(@$cmd) if ref $cmd eq 'ARRAY';
my $cmd_wrap
= $cmd . ' >> '
. $self->shell_quote( $self->{log} ) . ' 2>&1';
my ( $pid, $pipe, $exit_code );
local $SIG{ALRM} = sub {
CORE::die "alarm\n";
};
eval {
$pid = system 1, $cmd_wrap;
alarm $timeout;
waitpid $pid, 0;
$exit_code = $?;
alarm 0;
};
if ( $@ && $@ eq "alarm\n" ) {
pr_progress($state);
local $STDERR = $ORG_STDERR;
$self->diag_fail(
"Timed out (> ${timeout}s). Use --verbose to retry.");
CORE::kill -KILL => $pid;
return;
}
return !$exit_code;
};
}
my $diag_msg;
*App::cpanminus::script::_diag = sub {
my ( $self, $m, $a, $e ) = @_;
$state->{fail} = ( $state->{phase} || 'N/A' ) if $e;
if ( $m =~ /^! Timed out/ ) {
$state->{phase} .= "(Timeout)";
}
};
*App::cpanminus::script::install_module = sub {
my ( $self, $m, $d, $v ) = @_;
return 1 if $self->{seen}{$m};
my ( $dist, $mod, $ver, $file )
= @{ $self->resolve_name($m) }
{qw/dist module module_version pathname/};
my ( $target, @mods );
if ( !$outdated{$dist} ) {
($file) = $file =~ m#([^/]+/[^/]+)$#;
$added{$dist} = +{
file => $file,
version => $ver,
modules => [
+{ module => $mod,
current => undef,
new => $ver,
}
],
};
@mods = ($mod);
$target = \$added{$dist};
}
else {
@mods = map $_->{module}, @{ $outdated{$dist}->{modules} };
$count_of_upgrade++;
$target = \$outdated{$dist};
}
$state = +{
prev => $state,
depth => $d,
curr => $dist,
};
if ( ( $d || 0 ) > ( $state->{prev}{depth} || 0 ) ) {
unless ( $state->{prev}{in}{$d}++ ) {
$state->{prev}{dependency}++;
pr_progress( $state->{prev} );
pr( IN_PROGRESS => "Dependency found!" . $/ );
}
}
elsif ( ( $d || 0 ) < ( $state->{prev}{depth} || 0 ) ) {
pr( DEFAULT => $/ );
}
pr( DEFAULT => $ispace x $state->{depth} );
pr( HEADER => $dist );
pr( NOTE => ' [', join( ', ', @mods ), ']' ) if @mods;
pr( NOTE =>
sprintf( qq{ (%d/%d)}, $count_of_upgrade, $num_of_upgrade ) )
if !$state->{depth};
pr( DEFAULT => $/ );
my $elapse_one;
my $res = do {
$elapse_one = time;
my $r = &{ $org_m->{install_module} };
$elapse_one = time() - $elapse_one;
$r;
};
if ($res) {
if ( $diag_msg =~ /up to date/i ) {
$$target->{status} = 1;
$total_upgrade++;
pr( SUCCESS => $ispace x $state->{depth}
. "Up to date"
. $/ );
}
elsif ( $$target and !$$target->{fail_at} ) {
$$target->{status} = 1;
$$target->{time_required} = $elapse_one;
$total_upgrade++;
pr_progress($state);
pr( SUCCESS => "SUCCESS" );
pr( DEFAULT => "($elapse_one sec)" . $/ );
}
elsif ($$target) {
pr( ( $$target->{status} ? 'SUCCESS' : 'FAIL' ) =>
$ispace x $state->{depth} . "Already tried" . $/ );
}
if ( !$outdated{$dist} ) {
my $t = delete $added{$dist};
$t->{status} = 1;
$t->{time_required} = $elapse_one;
$outdated{$dist} = +{%$t};
$total_upgrade--;
$total_added++;
}
}
else {
$$target->{fail_at}
= $state->{dependency} ? 'Dependency' : $state->{fail};
$$target->{time_required} = $elapse_one;
$outdated{$dist} ||= delete $added{$dist};
if ( $state->{in}{ $d + 1 } ) {
$state->{progress_prev} = undef;
pr( DEFAULT => $ispace x $state->{depth} );
pr( DEFAULT => '--> ' . $dist . '..' );
}
else {
pr_progress($state);
}
pr( FAIL => "Timeout!!.." ) if $state->{fail} =~ /timeout/i;
pr( FAIL => "FAIL" );
pr( DEFAULT => "($elapse_one sec)" . $/ );
}
$state = $state->{prev};
return $res;
};
*App::cpanminus::script::fetch_module = sub {
$state->{phase} = "Fetch";
pr( FETCH => $ispace x $state->{depth},
$state->{progress_prev} = "Fetch.."
);
goto &{ $org_m->{fetch_module} };
};
*App::cpanminus::script::configure = sub {
## configure_ARGS: @_
if ( $state->{in} ) {
$state->{in} = $state->{progress_prev} = undef;
pr( DEFAULT => $ispace x $state->{depth}, '-->' );
pr( HEADER => "[$state->{curr}]" );
}
pr_progress($state);
pr( CONFIG => $state->{progress_prev} = "Configure.." );
$state->{phase} = "Configure";
goto &{ $org_m->{configure} };
};
*App::cpanminus::script::build = sub {
if ( $state->{in} ) {
$state->{in} = $state->{progress_prev} = undef;
pr( DEFAULT => $ispace x $state->{depth}, '-->' );
pr( HEADER => "[$state->{curr}]" );
}
pr_progress($state);
pr( BUILD => $state->{progress_prev} = "Build.." );
$state->{phase} = "Build";
goto &{ $org_m->{build} };
};
*App::cpanminus::script::test = sub {
pr_progress($state);
pr( TEST => $state->{progress_prev} = "Test.." );
$state->{phase} = "Test";
goto &{ $org_m->{test} };
};
*App::cpanminus::script::install = sub {
pr_progress($state);
pr( INSTALL => $state->{progress_prev} = "Install.." );
$state->{phase} = "Install";
goto &{ $org_m->{install} };
};
use warnings 'once';
for my $method (qw/setup_home init_tools configure_mirrors/) {
$app->${method};
}
for my $method (qw/setup_home init_tools configure_mirrors/) {
no strict 'refs';
no warnings 'redefine';
*{ 'App::cpanminus::script::' . $method } = sub { };
}
local $ENV{HARNESS_OPTIONS} = "j$DEBUG{jobs}" if $DEBUG{jobs};
script/ucpan view on Meta::CPAN
=item -S, --sudo
=item --no-sudo
Switch to the root user with sudo when installing modules,
or deny this.
See L<cpanm> for more detail.
=back
=head1 RECODING FILE
The previous result is recorded in the recoding file of this program.
Normally you do not need to edit this file.
The recoding file is named .ucpandb and placed in the top of @INC (ie. $INC[0]).
For example, if using local::lib, it is placed in /your/local/lib/$Config{archname}/.ucpandb.
This is to ensure that the settings do not interfere with running this program for different Perl environments.
In the recording file, the following items are recorded in YAML format.
=over 4
=item Successful module
Module name, preinstallation version, installed version
=item Failed distribution
Distribution file path, distribution version, module name of included module, version before installation, latest version, reason (for example, build, test, test timeout), processing time (seconds)
=back
=head1 BRIEF EXPLANATION OF THE MECHANISM
At first, the previous execution record is loaded from the recoding file.
In Check Phase, information on outdated modules is gathered via L<cpan-outdated>. The module to be skipped is determined by collating with the previous execution record.
In Installation Phase, the installation work is progressed using the function of loaded L<cpanm> (yes, loading L<cpanm>). Success of the result, which phases of the work failed, etc. are recorded.
In Result Phase, the summary is assembled and displayed based on the record of the installation.
Finally, the execution record is written to the recoding file.
=head1 SPECIAL FEATURE FOR WIN32
In the Win32 environment, the following matters have been improved for L<cpanm>.
=over 4
=item Symbolic link
L<cpanm> creates a symbolic link of the latest build log and working directory directly under $HOME/.cpanm,
but it is not created under Win32 environment.
ucpan can emulate symlink() and create it using Win32's mklink command.
(There is no one working in FAT32 environment anymore, is it?)
=item Timeout
L<cpanm> ignores the --*-timeout option in Win32 environment,
but in Win32 environment SIGALARM can also be used to implement timeout processing.
ucpan implements this.
=back
=head1 ENVIRONMENT VARIABLES
The following environment variables affect this program.
=over 4
=item PERL5LIB, PERL_LOCAL_LIB_ROOT, PERL_MB_OPT, PERL_MM_OPT,
=item PERL_CPANM_HOME, PERL_CPANM_OPT
=item HARNESS_OPTIONS( for test environment )
=back
=head1 SEE ALSO
L<App::ucpan>, L<App::cpanminus>, L<cpanm>
=head1 LICENSE
Copyright (C) KPEE.
This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=head1 AUTHOR
KPEE E<lt>kpee.cpan@gmail.comE<gt>
=cut
( run in 0.644 second using v1.01-cache-2.11-cpan-39bf76dae61 )