1package ExtUtils::AutoInstall; 2$ExtUtils::AutoInstall::VERSION = '0.63'; 3 4use strict; 5use Cwd (); 6use ExtUtils::MakeMaker (); 7 8=head1 NAME 9 10ExtUtils::AutoInstall - Automatic install of dependencies via CPAN 11 12=head1 VERSION 13 14This document describes version 0.63 of B<ExtUtils::AutoInstall>, 15released September 12, 2005. 16 17=head1 SYNOPSIS 18 19In F<Makefile.PL>, with L<Module::Install> available on the author's system: 20 21 use inc::Module::Install; 22 23 name ('Joe-Hacker'); 24 abstract ('Perl Interface to Joe Hacker'); 25 author ('Joe Hacker <joe@hacker.org>'); 26 include ('ExtUtils::AutoInstall'); 27 28 requires ('Module0'); # mandatory modules 29 features ( 30 -config => { 31 make_args => '--hello', # option(s) for CPAN::Config 32 force => 1, # pseudo-option to force install 33 do_once => 1, # skip previously failed modules 34 }, 35 'Feature1' => [ 36 'Module2' => '0.1', 37 ], 38 'Feature2' => [ 39 'Module3' => '1.0', 40 ], 41 ); 42 auto_install(); 43 &WriteAll; 44 45Invoking the resulting F<Makefile.PL>: 46 47 % perl Makefile.PL # interactive behaviour 48 % perl Makefile.PL --defaultdeps # accept default value on prompts 49 % perl Makefile.PL --checkdeps # check only, no Makefile produced 50 % perl Makefile.PL --skipdeps # ignores all dependencies 51 % perl Makefile.PL --testonly # don't write installation targets 52 53Note that the trailing 'deps' of arguments may be omitted, too. 54 55Using C<--defaultdeps> will make F<Makefile.PL> behave similarly to a regular 56Makefile.PL file with C<PREREQ_PM> dependencies. 57 58One can use environment variables (see "ENVIRONMENT") below to set a default 59behavior instead of specifying it in the command line for every invocation 60of F<Makefile.PL>. 61 62Using F<make> (or F<nmake>): 63 64 % make [all|test|install] # install dependencies first 65 % make checkdeps # same as the --checkdeps above 66 % make installdeps # install dependencies only 67 68=head1 DESCRIPTION 69 70B<ExtUtils::AutoInstall> lets module writers to specify a more 71sophisticated form of dependency information than the C<PREREQ_PM> 72option offered by B<ExtUtils::MakeMaker>. 73 74This module works best with the B<Module::Install> framework, 75a drop-in replacement for MakeMaker. However, this module also 76supports F<Makefile.PL> files based on MakeMaker; see L</EXAMPLES> 77for instructions. 78 79=head2 Prerequisites and Features 80 81Prerequisites are grouped into B<features>, and the user could choose 82yes/no on each one's dependencies; the module writer may also supply a 83boolean value via C<-default> to specify the default choice. 84 85The B<Core Features> marked by the name C<-core> will double-check with 86the user, if the user chooses not to install the mandatory modules. 87This differs from the pre-0.26 'silent install' behaviour. 88 89Starting from version 0.27, if C<-core> is set to the string C<all> 90(case-insensitive), every feature will be considered mandatory. 91 92The dependencies are expressed as pairs of C<Module> => C<version> 93inside an array reference. If the order does not matter, and there 94are no C<-default>, C<-tests> or C<-skiptests> directives for that 95feature, you may also use a hash reference. 96 97=head2 The Installation Process 98 99Once B<ExtUtils::AutoInstall> has determined which module(s) are needed, 100it checks whether it's running under the B<CPAN> shell and should 101therefore let B<CPAN> handle the dependency. 102 103Finally, the C<WriteMakefile()> is overridden to perform some additional 104checks, as well as skips tests associated with disabled features by the 105C<-tests> option. 106 107The actual installation happens at the end of the C<make config> target; 108both C<make test> and C<make install> will trigger the installation of 109required modules. 110 111If it's not running under B<CPAN>, the installer will probe for an 112active connection by trying to resolve the domain C<cpan.org>, and check 113for the user's permission to use B<CPAN>. If all went well, a separate 114 B<CPAN> instance is created to install the required modules. 115 116If you have the B<CPANPLUS> package installed in your system, it is 117preferred by default over B<CPAN>; it also accepts some extra options 118(e.g. C<-target =E<gt> 'skiptest', -skiptest =E<gt> 1> to skip testing). 119 120All modules scheduled to be installed will be deleted from C<%INC> 121first, so B<ExtUtils::MakeMaker> will check the newly installed modules. 122 123Additionally, you could use the C<make installdeps> target to install 124the modules, and the C<make checkdeps> target to check dependencies 125without actually installing them; the C<perl Makefile.PL --checkdeps> 126command has an equivalent effect. 127 128If the F<Makefile.PL> itself needs to use an independent module (e.g. 129B<Acme::KillarApp>, v1.21 or greater), then use something like below: 130 131 BEGIN { 132 require ExtUtils::AutoInstall; 133 # the first argument is an arrayref of the -config flags 134 ExtUtils::AutoInstall->install([], 'Acme::KillerApp' => 1.21); 135 } 136 use Acme::KillerApp 1.21; 137 138 ExtUtils::AutoInstall->import( 139 # ... arguments as usual ... 140 ); 141 142Note the version test in the use clause; if you are so close to the 143cutting edge that B<Acme::KillerApp> 1.20 is the latest version on CPAN, 144this will prevent your module from going awry. 145 146=head2 User-Defined Hooks 147 148User-defined I<pre-installation> and I<post-installation> hooks are 149available via C<MY::preinstall> and C<MY::postinstall> subroutines, 150as shown below: 151 152 # pre-install handler; takes $module_name and $version 153 sub MY::preinstall { return 1; } # return false to skip install 154 155 # post-install handler; takes $module_name, $version, $success 156 sub MY::postinstall { return; } # the return value doesn't matter 157 158Note that since B<ExtUtils::AutoInstall> performs installation at the 159time of C<use> (i.e. before perl parses the remainder of 160F<Makefile.PL>), you have to declare those two handlers I<before> the 161C<use> statement for them to take effect. 162 163If the user did not choose to install a module or it already exists on 164the system, neither of the handlers is invoked. Both handlers are invoked 165exactly once for each module when installation is attempted. 166 167C<MY::preinstall> takes two arguments, C<$module_name> and C<$version>; 168if it returns a false value, installation for that module will be 169skipped, and C<MY::postinstall> won't be called at all. 170 171C<MY::postinstall> takes three arguments, C<$module_name>, C<$version> 172and C<$success>. The last one denotes whether the installation 173succeeded or not: C<1> means installation completed successfully, C<0> 174means failure during install, and C<undef> means that the installation 175was not attempted at all, possibly due to connection problems, or that 176module does not exist on CPAN at all. 177 178=head2 Customized C<MY::postamble> 179 180Starting from version 0.43, B<ExtUtils::AutoInstall> supports modules 181that require a C<MY::postamble> subroutine in their F<Makefile.PL>. 182The user-defined C<MY::postamble>, if present, is responsible for 183calling C<ExtUtils::AutoInstall::postamble> and include the output in 184its return value. 185 186For example, the B<DBD::*> (database driver) modules for the Perl DBI 187are required to include the postamble generated by the function 188C<dbd_postamble>, so their F<Makefile.PL> may contain lines like this: 189 190 sub MY::postamble { 191 return &ExtUtils::AutoInstall::postamble . &dbd_postamble; 192 } 193 194Note that the B<ExtUtils::AutoInstall> module does not export the 195C<postamble> function, so the name should always be fully qualified. 196 197=head1 CAVEATS 198 199B<ExtUtils::AutoInstall> will add C<UNINST=1> to your B<make install> 200flags if your effective uid is 0 (root), unless you explicitly disable 201it by setting B<CPAN>'s C<make_install_arg> configuration option (or the 202C<makeflags> option of B<CPANPLUS>) to include C<UNINST=0>. This I<may> 203cause dependency problems if you are using a fine-tuned directory 204structure for your site. Please consult L<CPAN/FAQ> for an explanation 205in detail. 206 207If either B<version> or B<Sort::Versions> is available, they will be 208used to compare the required version with the existing module's version 209and the CPAN module's. Otherwise it silently falls back to use I<cmp>. 210This may cause inconsistent behaviours in pathetic situations. 211 212=head1 NOTES 213 214Since this module is needed before writing F<Makefile>, it makes little 215use as a CPAN module; hence each distribution must include it in full. 216The only alternative I'm aware of, namely prompting in F<Makefile.PL> to 217force user install it (cf. the B<Template Toolkit>'s dependency on 218B<AppConfig>) is not very desirable either. 219 220The current compromise is to add the bootstrap code listed in the 221L</SYNOPSIS> before every script, but that does not look pretty, and 222will not work without an Internet connection. 223 224Since we do not want all future options of B<ExtUtils::AutoInstall> to 225be painfully detected manually like above, this module provides a 226I<bootstrapping> mechanism via the C<-version> flag. If a newer version 227is needed by the F<Makefile.PL>, it will go ahead to fetch a new 228version, reload it into memory, and pass the arguments forward. 229 230If you have any suggestions, please let me know. Thanks. 231 232=head1 ENVIRONMENT 233 234B<ExtUtils::AutoInstall> uses a single environment variable, 235C<PERL_EXTUTILS_AUTOINSTALL>. It is taken as the command line argument 236passed to F<Makefile.PL>; you could set it to either C<--defaultdeps> or 237C<--skipdeps> to avoid interactive behaviour. 238 239=head1 EXAMPLES 240 241=head2 Using MakeMaker with AutoInstall 242 243To use this module with L<ExtUtils::MakeMaker>, first make a 244F<inc/ExtUtils/> subdirectory in the directory containing your 245L<Makefile.PL>, and put a copy this module under it as 246F<inc/ExtUtils/AutoInstall.pm>. You can find out where this module 247has been installed by typing C<perldoc -l ExtUtils::AutoInstall> 248in the command line. 249 250Your F<Makefile.PL> should look like this: 251 252 # pull in ExtUtils/AutoInstall.pm from 'inc' 253 use lib 'inc'; 254 use ExtUtils::AutoInstall ( 255 -core => [ # mandatory modules 256 'Module0' => '', # any version would suffice 257 ], 258 'Feature1' => [ 259 # do we want to install this feature by default? 260 -default => ( system('feature1 --version') == 0 ), 261 Module1 => '0.01', 262 ], 263 'Feature2' => [ 264 # associate tests to be disabled if this feature is missing 265 -tests => [ <t/feature2*.t> ], 266 # associate tests to be disabled if this feature is present 267 -skiptests => [ <t/nofeature2*.t> ], 268 Module2 => '0.02', 269 ], 270 'Feature3' => { # hash reference works, too 271 # force installation even if tests fail 272 Module2 => '0.03', 273 } 274 ); 275 276 WriteMakefile( 277 AUTHOR => 'Joe Hacker <joe@hacker.org>', 278 ABSTRACT => 'Perl Interface to Joe Hacker', 279 NAME => 'Joe::Hacker', 280 VERSION_FROM => 'Hacker.pm', 281 DISTNAME => 'Joe-Hacker', 282 ); 283 284=head2 Self-Download Code 285 286If you do not wish to put a copy of L<ExtUtils::AutoInstall> under 287F<inc/>, and are confident that users will have internet access, you 288may replace the C<use lib 'inc';> line with this block of code: 289 290 # ExtUtils::AutoInstall Bootstrap Code, version 7. 291 BEGIN{my$p='ExtUtils::AutoInstall';my$v=0.45;$p->VERSION||0>=$v 292 or+eval"use $p $v;1"or+do{my$e=$ENV{PERL_EXTUTILS_AUTOINSTALL}; 293 (!defined($e)||$e!~m/--(?:default|skip|testonly)/and-t STDIN or 294 eval"use ExtUtils::MakeMaker;WriteMakefile(PREREQ_PM=>{'$p',$v} 295 );1"and exit)and print"==> $p $v required. Install it from CP". 296 "AN? [Y/n] "and<STDIN>!~/^n/i and print"*** Installing $p\n"and 297 do{if (eval '$>' and lc(`sudo -V`) =~ /version/){system('sudo', 298 $^X,"-MCPANPLUS","-e","CPANPLUS::install $p");eval"use $p $v;1" 299 ||system('sudo', $^X, "-MCPAN", "-e", "CPAN::install $p")}eval{ 300 require CPANPLUS;CPANPLUS::install$p};eval"use $p $v;1"or eval{ 301 require CPAN;CPAN::install$p};eval"use $p $v;1"||die"*** Please 302 manually install $p $v from cpan.org first...\n"}}} 303 304If the user did not have L<ExtUtils::AutoInstall> installed, the 305block of code above will automatically download and install it. 306 307However, due to its space-compressed (and obfuscated) nature, you 308should think twice before employing this block of code; it is usually 309much more desirable to just use L<Module::Install> instead. 310 311=cut 312 313# special map on pre-defined feature sets 314my %FeatureMap = ( 315 '' => 'Core Features', # XXX: deprecated 316 '-core' => 'Core Features', 317); 318 319# various lexical flags 320my (@Missing, @Existing, %DisabledTests, $UnderCPAN, $HasCPANPLUS); 321my ($Config, $CheckOnly, $SkipInstall, $AcceptDefault, $TestOnly); 322my ($PostambleActions, $PostambleUsed); 323 324_accept_default(!-t STDIN); # see if it's a non-interactive session 325_init(); 326 327sub _accept_default { 328 $AcceptDefault = shift; 329} 330 331sub missing_modules { 332 return @Missing; 333} 334 335sub do_install { 336 __PACKAGE__->install( 337 [ UNIVERSAL::isa($Config, 'HASH') ? %{$Config} : @{$Config}], 338 @Missing, 339 ); 340} 341 342# initialize various flags, and/or perform install 343sub _init { 344 foreach my $arg (@ARGV, split(/[\s\t]+/, $ENV{PERL_EXTUTILS_AUTOINSTALL} || '')) { 345 if ($arg =~ /^--config=(.*)$/) { 346 $Config = [ split(',', $1) ]; 347 } 348 elsif ($arg =~ /^--installdeps=(.*)$/) { 349 __PACKAGE__->install($Config, @Missing = split(/,/, $1)); 350 exit 0; 351 } 352 elsif ($arg =~ /^--default(?:deps)?$/) { 353 $AcceptDefault = 1; 354 } 355 elsif ($arg =~ /^--check(?:deps)?$/) { 356 $CheckOnly = 1; 357 } 358 elsif ($arg =~ /^--skip(?:deps)?$/) { 359 $SkipInstall = 1; 360 } 361 elsif ($arg =~ /^--test(?:only)?$/) { 362 $TestOnly = 1; 363 } 364 } 365} 366 367# overrides MakeMaker's prompt() to automatically accept the default choice 368sub _prompt { 369 goto &ExtUtils::MakeMaker::prompt unless $AcceptDefault; 370 371 my ($prompt, $default) = @_; 372 my $y = ($default =~ /^[Yy]/); 373 374 print $prompt, ' [', ($y ? 'Y' : 'y'), '/', ($y ? 'n' : 'N'), '] '; 375 print "$default\n"; 376 return $default; 377} 378 379# the workhorse 380sub import { 381 my $class = shift; 382 my @args = @_ or return; 383 my $core_all; 384 385 print "*** $class version ".$class->VERSION."\n"; 386 print "*** Checking for dependencies...\n"; 387 388 my $cwd = Cwd::cwd(); 389 390 $Config = []; 391 392 my $maxlen = length((sort { length($b) <=> length($a) } 393 grep { /^[^\-]/ } 394 map { ref($_) ? keys %{ref($_) eq 'HASH' ? $_ : +{@{$_}}} : '' } 395 map { +{@args}->{$_} } 396 grep { /^[^\-]/ or /^-core$/i } keys %{+{@args}})[0]); 397 398 while (my ($feature, $modules) = splice(@args, 0, 2)) { 399 my (@required, @tests, @skiptests); 400 my $default = 1; 401 my $conflict = 0; 402 403 if ($feature =~ m/^-(\w+)$/) { 404 my $option = lc($1); 405 406 # check for a newer version of myself 407 _update_to($modules, @_) and return if $option eq 'version'; 408 409 # sets CPAN configuration options 410 $Config = $modules if $option eq 'config'; 411 412 # promote every features to core status 413 $core_all = ($modules =~ /^all$/i) and next 414 if $option eq 'core'; 415 416 next unless $option eq 'core'; 417 } 418 419 print "[".($FeatureMap{lc($feature)} || $feature)."]\n"; 420 421 $modules = [ %{$modules} ] if UNIVERSAL::isa($modules, 'HASH'); 422 423 unshift @$modules, -default => &{shift(@$modules)} 424 if (ref($modules->[0]) eq 'CODE'); # XXX: bugward combatability 425 426 while (my ($mod, $arg) = splice(@$modules, 0, 2)) { 427 if ($mod =~ m/^-(\w+)$/) { 428 my $option = lc($1); 429 430 $default = $arg if ($option eq 'default'); 431 $conflict = $arg if ($option eq 'conflict'); 432 @tests = @{$arg} if ($option eq 'tests'); 433 @skiptests = @{$arg} if ($option eq 'skiptests'); 434 435 next; 436 } 437 438 printf("- %-${maxlen}s ...", $mod); 439 440 # XXX: check for conflicts and uninstalls(!) them. 441 if (defined(my $cur = _version_check(_load($mod), $arg ||= 0))) { 442 print "loaded. ($cur".($arg ? " >= $arg" : '').")\n"; 443 push @Existing, $mod => $arg; 444 $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; 445 } 446 else { 447 print "missing." . ($arg ? " (would need $arg)" : '') . "\n"; 448 push @required, $mod => $arg; 449 } 450 } 451 452 next unless @required; 453 454 my $mandatory = ($feature eq '-core' or $core_all); 455 456 if (!$SkipInstall and ($CheckOnly or _prompt( 457 qq{==> Auto-install the }. (@required / 2). 458 ($mandatory ? ' mandatory' : ' optional'). 459 qq{ module(s) from CPAN?}, $default ? 'y' : 'n', 460 ) =~ /^[Yy]/)) { 461 push (@Missing, @required); 462 $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; 463 } 464 465 elsif (!$SkipInstall and $default and $mandatory and _prompt( 466 qq{==> The module(s) are mandatory! Really skip?}, 'n', 467 ) =~ /^[Nn]/) { 468 push (@Missing, @required); 469 $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; 470 } 471 472 else { 473 $DisabledTests{$_} = 1 for map { glob($_) } @tests; 474 } 475 } 476 477 _check_lock(); # check for $UnderCPAN 478 479 if (@Missing and not ($CheckOnly or $UnderCPAN)) { 480 require Config; 481 print "*** Dependencies will be installed the next time you type '$Config::Config{make}'.\n"; 482 # make an educated guess of whether we'll need root permission. 483 print " (You may need to do that as the 'root' user.)\n" if eval '$>'; 484 } 485 print "*** $class configuration finished.\n"; 486 487 chdir $cwd; 488 489 # import to main:: 490 no strict 'refs'; 491 *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main'; 492} 493 494# CPAN.pm is non-reentrant, so check if we're under it and have no CPANPLUS 495sub _check_lock { 496 return unless @Missing; 497 return if _has_cpanplus(); 498 499 require CPAN; CPAN::Config->load; 500 my $lock = MM->catfile($CPAN::Config->{cpan_home}, ".lock"); 501 502 if (-f $lock and open(LOCK, $lock) 503 and ($^O eq 'MSWin32' ? _under_cpan() : <LOCK> == getppid()) 504 and ($CPAN::Config->{prerequisites_policy} || '') ne 'ignore' 505 ) { 506 print << '.'; 507 508*** Since we're running under CPAN, I'll just let it take care 509 of the dependency's installation later. 510. 511 $UnderCPAN = 1; 512 } 513 514 close LOCK; 515} 516 517sub install { 518 my $class = shift; 519 520 my $i; # used below to strip leading '-' from config keys 521 my @config = (map { s/^-// if ++$i; $_ } @{+shift}); 522 523 my (@modules, @installed); 524 while (my ($pkg, $ver) = splice(@_, 0, 2)) { 525 # grep out those already installed 526 if (defined(_version_check(_load($pkg), $ver))) { 527 push @installed, $pkg; 528 } 529 else { 530 push @modules, $pkg, $ver; 531 } 532 } 533 534 return @installed unless @modules; # nothing to do 535 536 print "*** Installing dependencies...\n"; 537 538 return unless _connected_to('cpan.org'); 539 540 my %args = @config; 541 my %failed; 542 local *FAILED; 543 if ($args{do_once} and open(FAILED, '.#autoinstall.failed')) { 544 while (<FAILED>) { chomp; $failed{$_}++ } 545 close FAILED; 546 547 my @newmod; 548 while (my ($k, $v) = splice(@modules, 0, 2)) { 549 push @newmod, ($k => $v) unless $failed{$k}; 550 } 551 @modules = @newmod; 552 } 553 554 if (_has_cpanplus()) { 555 _install_cpanplus(\@modules, \@config); 556 } 557 else { 558 _install_cpan(\@modules, \@config); 559 } 560 561 print "*** $class installation finished.\n"; 562 563 # see if we have successfully installed them 564 while (my ($pkg, $ver) = splice(@modules, 0, 2)) { 565 if (defined(_version_check(_load($pkg), $ver))) { 566 push @installed, $pkg; 567 } 568 elsif ($args{do_once} and open(FAILED, '>> .#autoinstall.failed')) { 569 print FAILED "$pkg\n"; 570 } 571 } 572 573 close FAILED if $args{do_once}; 574 575 return @installed; 576} 577 578sub _install_cpanplus { 579 my @modules = @{+shift}; 580 my @config = @{+shift}; 581 my $installed = 0; 582 583 require CPANPLUS::Backend; 584 my $cp = CPANPLUS::Backend->new; 585 my $conf = $cp->configure_object; 586 587 return unless _can_write( 588 $conf->can('conf') 589 ? $conf->get_conf('base') # 0.05x+ 590 : $conf->_get_build('base') # 0.04x 591 ); 592 593 # if we're root, set UNINST=1 to avoid trouble unless user asked for it. 594 my $makeflags = $conf->get_conf('makeflags') || ''; 595 if (UNIVERSAL::isa($makeflags, 'HASH')) { 596 # 0.03+ uses a hashref here 597 $makeflags->{UNINST} = 1 unless exists $makeflags->{UNINST}; 598 } 599 else { 600 # 0.02 and below uses a scalar 601 $makeflags = join(' ', split(' ', $makeflags), 'UNINST=1') 602 if ($makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' }); 603 } 604 $conf->set_conf(makeflags => $makeflags); 605 $conf->set_conf(prereqs => 1); 606 607 while (my ($key, $val) = splice(@config, 0, 2)) { 608 eval { $conf->set_conf($key, $val) }; 609 } 610 611 my $modtree = $cp->module_tree; 612 while (my ($pkg, $ver) = splice(@modules, 0, 2)) { 613 print "*** Installing $pkg...\n"; 614 615 MY::preinstall($pkg, $ver) or next if defined &MY::preinstall; 616 617 my $success; 618 my $obj = $modtree->{$pkg}; 619 620 if ($obj and defined(_version_check($obj->{version}, $ver))) { 621 my $pathname = $pkg; $pathname =~ s/::/\\W/; 622 623 foreach my $inc (grep { m/$pathname.pm/i } keys(%INC)) { 624 delete $INC{$inc}; 625 } 626 627 my $rv = $cp->install( modules => [ $obj->{module} ]); 628 629 if ($rv and ($rv->{$obj->{module}} or $rv->{ok})) { 630 print "*** $pkg successfully installed.\n"; 631 $success = 1; 632 } 633 else { 634 print "*** $pkg installation cancelled.\n"; 635 $success = 0; 636 } 637 638 $installed += $success; 639 } 640 else { 641 print << "."; 642*** Could not find a version $ver or above for $pkg; skipping. 643. 644 } 645 646 MY::postinstall($pkg, $ver, $success) if defined &MY::postinstall; 647 } 648 649 return $installed; 650} 651 652sub _install_cpan { 653 my @modules = @{+shift}; 654 my @config = @{+shift}; 655 my $installed = 0; 656 my %args; 657 658 require CPAN; CPAN::Config->load; 659 require Config; 660 661 return unless _can_write(MM->catfile($CPAN::Config->{cpan_home}, 'sources')) 662 and _can_write($Config::Config{sitelib}); 663 664 # if we're root, set UNINST=1 to avoid trouble unless user asked for it. 665 my $makeflags = $CPAN::Config->{make_install_arg} || ''; 666 $CPAN::Config->{make_install_arg} = join(' ', split(' ', $makeflags), 'UNINST=1') 667 if ($makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' }); 668 669 # don't show start-up info 670 $CPAN::Config->{inhibit_startup_message} = 1; 671 672 # set additional options 673 while (my ($opt, $arg) = splice(@config, 0, 2)) { 674 ($args{$opt} = $arg, next) 675 if $opt =~ /^force$/; # pseudo-option 676 $CPAN::Config->{$opt} = $arg; 677 } 678 679 local $CPAN::Config->{prerequisites_policy} = 'follow'; 680 681 while (my ($pkg, $ver) = splice(@modules, 0, 2)) { 682 MY::preinstall($pkg, $ver) or next if defined &MY::preinstall; 683 684 print "*** Installing $pkg...\n"; 685 686 my $obj = CPAN::Shell->expand(Module => $pkg); 687 my $success = 0; 688 689 if ($obj and defined(_version_check($obj->cpan_version, $ver))) { 690 my $pathname = $pkg; $pathname =~ s/::/\\W/; 691 692 foreach my $inc (grep { m/$pathname.pm/i } keys(%INC)) { 693 delete $INC{$inc}; 694 } 695 696 $obj->force('install') if $args{force}; 697 698 my $rv = $obj->install || eval { 699 $CPAN::META->instance( 700 'CPAN::Distribution', 701 $obj->cpan_file, 702 )->{install} if $CPAN::META 703 }; 704 705 if ($rv eq 'YES') { 706 print "*** $pkg successfully installed.\n"; 707 $success = 1; 708 } 709 else { 710 print "*** $pkg installation failed.\n"; 711 $success = 0; 712 } 713 714 $installed += $success; 715 } 716 else { 717 print << "."; 718*** Could not find a version $ver or above for $pkg; skipping. 719. 720 } 721 722 MY::postinstall($pkg, $ver, $success) if defined &MY::postinstall; 723 } 724 725 return $installed; 726} 727 728sub _has_cpanplus { 729 return ( 730 $HasCPANPLUS = ( 731 $INC{'CPANPLUS/Config.pm'} or 732 _load('CPANPLUS::Shell::Default') 733 ) 734 ); 735} 736 737# make guesses on whether we're under the CPAN installation directory 738sub _under_cpan { 739 require Cwd; 740 require File::Spec; 741 742 my $cwd = File::Spec->canonpath(Cwd::cwd()); 743 my $cpan = File::Spec->canonpath($CPAN::Config->{cpan_home}); 744 745 return (index($cwd, $cpan) > -1); 746} 747 748sub _update_to { 749 my $class = __PACKAGE__; 750 my $ver = shift; 751 752 return if defined(_version_check(_load($class), $ver)); # no need to upgrade 753 754 if (_prompt( 755 "==> A newer version of $class ($ver) is required. Install?", 'y' 756 ) =~ /^[Nn]/) { 757 die "*** Please install $class $ver manually.\n"; 758 } 759 760 print << "."; 761*** Trying to fetch it from CPAN... 762. 763 764 # install ourselves 765 _load($class) and return $class->import(@_) 766 if $class->install([], $class, $ver); 767 768 print << '.'; exit 1; 769 770*** Cannot bootstrap myself. :-( Installation terminated. 771. 772} 773 774# check if we're connected to some host, using inet_aton 775sub _connected_to { 776 my $site = shift; 777 778 return ( 779 ( _load('Socket') and Socket::inet_aton($site) ) or _prompt(qq( 780*** Your host cannot resolve the domain name '$site', which 781 probably means the Internet connections are unavailable. 782==> Should we try to install the required module(s) anyway?), 'n' 783 ) =~ /^[Yy]/ 784 ); 785} 786 787# check if a directory is writable; may create it on demand 788sub _can_write { 789 my $path = shift; 790 mkdir ($path, 0755) unless -e $path; 791 792 return 1 if -w $path; 793 794 print << "."; 795*** You are not allowed to write to the directory '$path'; 796 the installation may fail due to insufficient permissions. 797. 798 799 if (eval '$>' and lc(`sudo -V`) =~ /version/ and _prompt(qq( 800==> Should we try to re-execute the autoinstall process with 'sudo'?), 'y' 801 ) =~ /^[Yy]/) { 802 # try to bootstrap ourselves from sudo 803 print << "."; 804*** Trying to re-execute the autoinstall process with 'sudo'... 805. 806 my $missing = join(',', @Missing); 807 my $config = join(',', 808 UNIVERSAL::isa($Config, 'HASH') ? %{$Config} : @{$Config} 809 ) if $Config; 810 811 return unless system('sudo', $^X, $0, "--config=$config", "--installdeps=$missing"); 812 813 print << "."; 814*** The 'sudo' command exited with error! Resuming... 815. 816 } 817 818 return _prompt(qq( 819==> Should we try to install the required module(s) anyway?), 'n' 820 ) =~ /^[Yy]/ 821} 822 823# load a module and return the version it reports 824sub _load { 825 my $mod = pop; # class/instance doesn't matter 826 my $file = $mod; 827 828 $file =~ s|::|/|g; 829 $file .= '.pm'; 830 831 local $@; 832 return eval { require $file; $mod->VERSION } || ($@ ? undef : 0); 833} 834 835# compare two versions, either use Sort::Versions or plain comparison 836sub _version_check { 837 my ($cur, $min) = @_; 838 return unless defined $cur; 839 840 $cur =~ s/\s+$//; 841 842 # check for version numbers that are not in decimal format 843 if (ref($cur) or ref($min) or $cur =~ /v|\..*\./ or $min =~ /v|\..*\./) { 844 if ($version::VERSION or defined(_load('version'))) { 845 # use version.pm if it is installed. 846 return ((version->new($cur) >= version->new($min)) ? $cur : undef); 847 } 848 elsif ($Sort::Versions::VERSION or defined(_load('Sort::Versions'))) { 849 # use Sort::Versions as the sorting algorithm for a.b.c versions 850 return ((Sort::Versions::versioncmp($cur, $min) != -1) ? $cur : undef); 851 } 852 853 warn "Cannot reliably compare non-decimal formatted versions.\n". 854 "Please install version.pm or Sort::Versions.\n"; 855 } 856 857 # plain comparison 858 local $^W = 0; # shuts off 'not numeric' bugs 859 return ($cur >= $min ? $cur : undef); 860} 861 862# nothing; this usage is deprecated. 863sub main::PREREQ_PM { return {}; } 864 865sub _make_args { 866 my %args = @_; 867 868 $args{PREREQ_PM} = { %{$args{PREREQ_PM} || {} }, @Existing, @Missing } 869 if $UnderCPAN or $TestOnly; 870 871 if ($args{EXE_FILES}) { 872 require ExtUtils::Manifest; 873 my $manifest = ExtUtils::Manifest::maniread('MANIFEST'); 874 875 $args{EXE_FILES} = [ 876 grep { exists $manifest->{$_} } @{$args{EXE_FILES}} 877 ]; 878 } 879 880 $args{test}{TESTS} ||= 't/*.t'; 881 $args{test}{TESTS} = join(' ', grep { 882 !exists($DisabledTests{$_}) 883 } map { glob($_) } split(/\s+/, $args{test}{TESTS})); 884 885 my $missing = join(',', @Missing); 886 my $config = join(',', 887 UNIVERSAL::isa($Config, 'HASH') ? %{$Config} : @{$Config} 888 ) if $Config; 889 890 $PostambleActions = ( 891 $missing ? "\$(PERL) $0 --config=$config --installdeps=$missing" 892 : "\@\$(NOOP)" 893 ); 894 895 return %args; 896} 897 898# a wrapper to ExtUtils::MakeMaker::WriteMakefile 899sub Write { 900 require Carp; 901 Carp::croak "WriteMakefile: Need even number of args" if @_ % 2; 902 903 if ($CheckOnly) { 904 print << "."; 905*** Makefile not written in check-only mode. 906. 907 return; 908 } 909 910 my %args = _make_args(@_); 911 912 no strict 'refs'; 913 914 $PostambleUsed = 0; 915 local *MY::postamble = \&postamble unless defined &MY::postamble; 916 ExtUtils::MakeMaker::WriteMakefile(%args); 917 918 print << "." unless $PostambleUsed; 919*** WARNING: Makefile written with customized MY::postamble() without 920 including contents from ExtUtils::AutoInstall::postamble() -- 921 auto installation features disabled. Please contact the author. 922. 923 924 return 1; 925} 926 927sub postamble { 928 $PostambleUsed = 1; 929 930 return << "."; 931 932config :: installdeps 933\t\@\$(NOOP) 934 935checkdeps :: 936\t\$(PERL) $0 --checkdeps 937 938installdeps :: 939\t$PostambleActions 940 941. 942 943} 944 9451; 946 947__END__ 948 949=head1 SEE ALSO 950 951L<perlmodlib>, L<ExtUtils::MakeMaker>, L<Sort::Versions>, L<CPAN>, 952L<CPANPLUS>, L<Module::Install> 953 954=head1 ACKNOWLEDGEMENTS 955 956The test script included in the B<ExtUtils::AutoInstall> distribution 957contains code adapted from Michael Schwern's B<Test::More> under the 958I<Perl License>. Please consult to F<t/AutoInstall.t> for details. 959 960See the F<AUTHORS> file in this module's source distribution for the 961list of contributors. 962 963=head1 AUTHORS 964 965Autrijus Tang E<lt>autrijus@autrijus.orgE<gt> 966 967=head1 COPYRIGHT 968 969Copyright 2001, 2002, 2003, 2004 970by Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>. 971 972This program is free software; you can redistribute it and/or 973modify it under the same terms as Perl itself. 974 975See L<http://www.perl.com/perl/misc/Artistic.html> 976 977=cut 978