1 package CPANPLUS::Dist::Build;
4 use vars qw[@ISA $STATUS $VERSION];
5 @ISA = qw[CPANPLUS::Dist];
8 use CPANPLUS::Internals::Constants;
10 ### these constants were exported by CPANPLUS::Internals::Constants
11 ### in previous versions.. they do the same though. If we want to have
12 ### a normal 'use' here, up the dependency to CPANPLUS 0.056 or higher
14 require CPANPLUS::Dist::Build::Constants;
15 CPANPLUS::Dist::Build::Constants->import()
16 if not __PACKAGE__->can('BUILD') && __PACKAGE__->can('BUILD_DIR');
26 use Params::Check qw[check];
27 use Module::Load::Conditional qw[can_load check_install];
28 use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
30 local $Params::Check::VERBOSE = 1;
42 my $build = CPANPLUS::Dist->new(
43 format => 'CPANPLUS::Dist::Build',
47 $build->prepare; # runs Module::Build->new_from_context;
48 $build->create; # runs build && build test
49 $build->install; # runs build install
54 C<CPANPLUS::Dist::Build> is a distribution class for C<Module::Build>
56 Using this package, you can create, install and uninstall perl
57 modules. It inherits from C<CPANPLUS::Dist>.
59 Normal users won't have to worry about the interface to this module,
60 as it functions transparently as a plug-in to C<CPANPLUS> and will
61 just C<Do The Right Thing> when it's loaded.
69 Returns the C<CPANPLUS::Module> object that parented this object.
73 Returns the C<Object::Accessor> object that keeps the status for
78 =head1 STATUS ACCESSORS
80 All accessors can be accessed as follows:
81 $build->status->ACCESSOR
87 Location of the Build file.
88 Set to 0 explicitly if something went wrong.
92 BOOL indicating if the C<Build> command was successful.
96 BOOL indicating if the C<Build test> command was successful.
100 BOOL indicating if the C<prepare> call exited succesfully
101 This gets set after C<perl Build.PL>
105 Full path to the directory in which the C<prepare> call took place,
106 set after a call to C<prepare>.
110 BOOL indicating if the C<create> call exited succesfully. This gets
111 set after C<Build> and C<Build test>.
115 BOOL indicating if the module was installed. This gets set after
116 C<Build install> exits successfully.
120 BOOL indicating if the module was uninstalled properly.
122 =item _create_args ()
124 Storage of the arguments passed to C<create> for this object. Used
125 for recursive calls when satisfying prerequisites.
127 =item _install_args ()
129 Storage of the arguments passed to C<install> for this object. Used
130 for recursive calls when satisfying prerequisites.
134 Storage of the C<Module::Build> object we used for this installation.
143 =head2 $bool = CPANPLUS::Dist::Build->format_available();
145 Returns a boolean indicating whether or not you can use this package
146 to create and install modules in your environment.
150 ### check if the format is available ###
151 sub format_available {
152 my $mod = "Module::Build";
153 unless( can_load( modules => { $mod => '0.2611' } ) ) {
154 error( loc( "You do not have '%1' -- '%2' not available",
155 $mod, __PACKAGE__ ) );
163 =head2 $bool = $dist->init();
165 Sets up the C<CPANPLUS::Dist::Build> object for use.
166 Effectively creates all the needed status accessors.
168 Called automatically whenever you create a new C<CPANPLUS::Dist> object.
174 my $status = $dist->status;
176 $status->mk_accessors(qw[build_pl build test created installed uninstalled
177 _create_args _install_args _prepare_args
178 _mb_object _buildflags
181 ### just in case 'format_available' didn't get called
182 require Module::Build;
189 =head2 $bool = $dist->prepare([perl => '/path/to/perl', buildflags => 'EXTRA=FLAGS', force => BOOL, verbose => BOOL])
191 C<prepare> prepares a distribution, running C<Module::Build>'s
192 C<new_from_context> method, and establishing any prerequisites this
195 When running C<< Module::Build->new_from_context >>, the environment
196 variable C<PERL5_CPANPLUS_IS_EXECUTING> will be set to the full path
197 of the C<Build.PL> that is being executed. This enables any code inside
198 the C<Build.PL> to know that it is being installed via CPANPLUS.
200 After a succcesfull C<prepare> you may call C<create> to create the
201 distribution, followed by C<install> to actually install it.
203 Returns true on success and false on failure.
208 ### just in case you already did a create call for this module object
209 ### just via a different dist object
211 my $self = $dist->parent;
213 ### we're also the cpan_dist, since we don't need to have anything
214 ### prepared from another installer
215 $dist = $self->status->dist_cpan if $self->status->dist_cpan;
216 $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan;
218 my $cb = $self->parent;
219 my $conf = $cb->configure_object;
223 unless( $dir = $self->status->extract ) {
224 error( loc( "No dir found to operate on!" ) );
229 my( $force, $verbose, $buildflags, $perl);
230 { local $Params::Check::ALLOW_UNKNOWN = 1;
232 force => { default => $conf->get_conf('force'),
234 verbose => { default => $conf->get_conf('verbose'),
235 store => \$verbose },
236 perl => { default => $^X, store => \$perl },
237 buildflags => { default => $conf->get_conf('buildflags'),
238 store => \$buildflags },
241 $args = check( $tmpl, \%hash ) or return;
244 return 1 if $dist->status->prepared && !$force;
246 $dist->status->_prepare_args( $args );
248 ### chdir to work directory ###
250 unless( $cb->_chdir( dir => $dir ) ) {
251 error( loc( "Could not chdir to build directory '%1'", $dir ) );
255 ### by now we've loaded module::build, and we're using the API, so
256 ### it's safe to remove CPANPLUS::inc from our inc path, especially
257 ### because it can trip up tests run under taint (just like EU::MM).
258 ### turn off our PERL5OPT so no modules from CPANPLUS::inc get
259 ### included in make test -- it should build without.
260 ### also, modules that run in taint mode break if we leave
261 ### our code ref in perl5opt
262 ### XXX we've removed the ENV settings from cp::inc, so only need
263 ### to reset the @INC
264 #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt;
265 #local $ENV{PERL5LIB} = CPANPLUS::inc->original_perl5lib;
266 local @INC = CPANPLUS::inc->original_inc;
268 ### this will generate warnings under anything lower than M::B 0.2606
269 my %buildflags = $dist->_buildflags_as_hash( $buildflags );
270 $dist->status->_buildflags( $buildflags );
274 # Wrap the exception that may be thrown here (should likely be
275 # done at a much higher level).
277 my $env = 'ENV_CPANPLUS_IS_EXECUTING';
278 local $ENV{$env} = BUILD_PL->( $dir );
279 Module::Build->new_from_context( %buildflags )
282 error(loc("Could not create Module::Build object: %1","$@"));
286 $dist->status->_mb_object( $mb );
288 $self->status->prereqs( $dist->_find_prereqs( verbose => $verbose ) );
292 ### send out test report? ###
293 if( $fail and $conf->get_conf('cpantest') ) {
297 buffer => CPANPLUS::Error->stack_as_string,
300 ) or error(loc("Failed to send test report for '%1'",
304 unless( $cb->_chdir( dir => $orig ) ) {
305 error( loc( "Could not chdir back to start dir '%1'", $orig ) );
308 ### save where we wrote this stuff -- same as extract dir in normal
309 ### installer circumstances
310 $dist->status->distdir( $self->status->extract );
312 return $dist->status->prepared( $fail ? 0 : 1 );
317 my $mb = $dist->status->_mb_object;
318 my $self = $dist->parent;
319 my $cb = $self->parent;
322 foreach my $type ('requires', 'build_requires') {
323 my $p = $mb->$type() || {};
324 $prereqs->{$_} = $p->{$_} foreach keys %$p;
327 ### allows for a user defined callback to filter the prerequisite
328 ### list as they see fit, to remove (or add) any prereqs they see
329 ### fit. The default installed callback will return the hashref in
330 ### an unmodified form
331 ### this callback got added after cpanplus 0.0562, so use a 'can'
332 ### to find out if it's supported. For older versions, we'll just
333 ### return the hashref as is ourselves.
334 my $href = $cb->_callbacks->can('filter_prereqs')
335 ? $cb->_callbacks->filter_prereqs->( $cb, $prereqs )
338 $self->status->prereqs( $href );
340 ### make sure it's not the same ref
344 sub prereq_satisfied {
345 # Return true if this prereq is satisfied. Return false if it's
346 # not. Also issue an error if the latest CPAN version doesn't
349 my ($dist, %args) = @_;
350 my $mb = $dist->status->_mb_object;
351 my $cb = $dist->parent->parent;
352 my $mod = $args{modobj}->module;
354 my $status = $mb->check_installed_status($mod, $args{version});
355 return 1 if $status->{ok};
357 # Check the latest version from the CPAN index
360 local ${$mod . '::VERSION'} = $args{modobj}->version;
361 $status = $mb->check_installed_status($mod, $args{version});
363 unless( $status->{ok} ) {
364 error(loc("This distribution depends on $mod, but the latest version of $mod on CPAN ".
365 "doesn't satisfy the specific version dependency ($args{version}). ".
366 "Please try to resolve this dependency manually."));
374 =head2 $dist->create([perl => '/path/to/perl', buildflags => 'EXTRA=FLAGS', prereq_target => TARGET, force => BOOL, verbose => BOOL, skiptest => BOOL])
376 C<create> preps a distribution for installation. This means it will
377 run C<Build> and C<Build test>, via the C<Module::Build> API.
378 This will also satisfy any prerequisites the module may have.
380 If you set C<skiptest> to true, it will skip the C<Build test> stage.
381 If you set C<force> to true, it will go over all the stages of the
382 C<Build> process again, ignoring any previously cached results. It
383 will also ignore a bad return value from C<Build test> and still allow
384 the operation to return true.
386 Returns true on success and false on failure.
388 You may then call C<< $dist->install >> on the object to actually
394 ### just in case you already did a create call for this module object
395 ### just via a different dist object
397 my $self = $dist->parent;
399 ### we're also the cpan_dist, since we don't need to have anything
400 ### prepared from another installer
401 $dist = $self->status->dist_cpan if $self->status->dist_cpan;
402 $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan;
404 my $cb = $self->parent;
405 my $conf = $cb->configure_object;
406 my $mb = $dist->status->_mb_object;
410 unless( $dir = $self->status->extract ) {
411 error( loc( "No dir found to operate on!" ) );
416 my( $force, $verbose, $buildflags, $skiptest, $prereq_target,
417 $perl, $prereq_format, $prereq_build);
418 { local $Params::Check::ALLOW_UNKNOWN = 1;
420 force => { default => $conf->get_conf('force'),
422 verbose => { default => $conf->get_conf('verbose'),
423 store => \$verbose },
424 perl => { default => $^X, store => \$perl },
425 buildflags => { default => $conf->get_conf('buildflags'),
426 store => \$buildflags },
427 skiptest => { default => $conf->get_conf('skiptest'),
428 store => \$skiptest },
429 prereq_target => { default => '', store => \$prereq_target },
430 ### don't set the default format to 'build' -- that is wrong!
431 prereq_format => { #default => $self->status->installer_type,
433 store => \$prereq_format },
434 prereq_build => { default => 0, store => \$prereq_build },
437 $args = check( $tmpl, \%hash ) or return;
440 return 1 if $dist->status->created && !$force;
442 $dist->status->_create_args( $args );
444 ### is this dist prepared?
445 unless( $dist->status->prepared ) {
446 error( loc( "You have not successfully prepared a '%2' distribution ".
447 "yet -- cannot create yet", __PACKAGE__ ) );
451 ### chdir to work directory ###
453 unless( $cb->_chdir( dir => $dir ) ) {
454 error( loc( "Could not chdir to build directory '%1'", $dir ) );
458 ### by now we've loaded module::build, and we're using the API, so
459 ### it's safe to remove CPANPLUS::inc from our inc path, especially
460 ### because it can trip up tests run under taint (just like EU::MM).
461 ### turn off our PERL5OPT so no modules from CPANPLUS::inc get
462 ### included in make test -- it should build without.
463 ### also, modules that run in taint mode break if we leave
464 ### our code ref in perl5opt
465 ### XXX we've removed the ENV settings from cp::inc, so only need
466 ### to reset the @INC
467 #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt;
468 #local $ENV{PERL5LIB} = CPANPLUS::inc->original_perl5lib;
469 local @INC = CPANPLUS::inc->original_inc;
471 ### but do it *before* the new_from_context, as M::B seems
472 ### to be actually running the file...
473 ### an unshift in the block seems to be ignored.. somehow...
474 #{ my $lib = $self->best_path_to_module_build;
475 # unshift @INC, $lib if $lib;
477 unshift @INC, $self->best_path_to_module_build
478 if $self->best_path_to_module_build;
480 ### this will generate warnings under anything lower than M::B 0.2606
481 my %buildflags = $dist->_buildflags_as_hash( $buildflags );
482 $dist->status->_buildflags( $buildflags );
484 my $fail; my $prereq_fail; my $test_fail;
487 ### this will set the directory back to the start
488 ### dir, so we must chdir /again/
489 my $ok = $dist->_resolve_prereqs(
491 format => $prereq_format,
493 prereqs => $self->status->prereqs,
494 target => $prereq_target,
495 prereq_build => $prereq_build,
498 unless( $cb->_chdir( dir => $dir ) ) {
499 error( loc( "Could not chdir to build directory '%1'", $dir ) );
504 #### use $dist->flush to reset the cache ###
505 error( loc( "Unable to satisfy prerequisites for '%1' " .
506 "-- aborting install", $self->module ) );
507 $dist->status->build(0);
508 $fail++; $prereq_fail++;
512 eval { $mb->dispatch('build', %buildflags) };
514 error(loc("Could not run '%1': %2", 'Build', "$@"));
515 $dist->status->build(0);
519 $dist->status->build(1);
521 ### add this directory to your lib ###
522 $cb->_add_to_includepath(
523 directories => [ BLIB_LIBDIR->( $self->status->extract ) ]
526 ### this buffer will not include what tests failed due to a
527 ### M::B/Test::Harness bug. Reported as #9793 with patch
528 ### against 0.2607 on 26/1/2005
529 unless( $skiptest ) {
530 eval { $mb->dispatch('test', %buildflags) };
532 error(loc("Could not run '%1': %2", 'Build test', "$@"));
534 ### mark specifically *test* failure.. so we dont
535 ### send success on force...
538 if( !$force and !$cb->_callbacks->proceed_on_test_failure->(
541 $dist->status->test(0);
546 $dist->status->test(1);
549 msg(loc("Tests skipped"), $verbose);
553 unless( $cb->_chdir( dir => $orig ) ) {
554 error( loc( "Could not chdir back to start dir '%1'", $orig ) );
557 ### send out test report? ###
558 if( $conf->get_conf('cpantest') and not $prereq_fail ) {
561 failed => $test_fail || $fail,
562 buffer => CPANPLUS::Error->stack_as_string,
565 tests_skipped => $skiptest,
566 ) or error(loc("Failed to send test report for '%1'",
570 return $dist->status->created( $fail ? 0 : 1 );
573 =head2 $dist->install([verbose => BOOL, perl => /path/to/perl])
575 Actually installs the created dist.
577 Returns true on success and false on failure.
582 ### just in case you already did a create call for this module object
583 ### just via a different dist object
585 my $self = $dist->parent;
587 ### we're also the cpan_dist, since we don't need to have anything
588 ### prepared from another installer
589 $dist = $self->status->dist_cpan if $self->status->dist_cpan;
590 my $mb = $dist->status->_mb_object;
592 my $cb = $self->parent;
593 my $conf = $cb->configure_object;
597 my $verbose; my $perl; my $force;
598 { local $Params::Check::ALLOW_UNKNOWN = 1;
600 verbose => { default => $conf->get_conf('verbose'),
601 store => \$verbose },
602 force => { default => $conf->get_conf('force'),
604 perl => { default => $^X, store => \$perl },
607 my $args = check( $tmpl, \%hash ) or return;
608 $dist->status->_install_args( $args );
612 unless( $dir = $self->status->extract ) {
613 error( loc( "No dir found to operate on!" ) );
619 unless( $cb->_chdir( dir => $dir ) ) {
620 error( loc( "Could not chdir to build directory '%1'", $dir ) );
624 ### value set and false -- means failure ###
625 if( defined $self->status->installed &&
626 !$self->status->installed && !$force
628 error( loc( "Module '%1' has failed to install before this session " .
629 "-- aborting install", $self->module ) );
634 my $buildflags = $dist->status->_buildflags;
635 ### hmm, how is this going to deal with sudo?
636 ### for now, check effective uid, if it's not root,
637 ### shell out, otherwise use the method
640 ### don't worry about loading the right version of M::B anymore
641 ### the 'new_from_context' already added the 'right' path to
642 ### M::B at the top of the build.pl
643 my $cmd = [$perl, BUILD->($dir), 'install', $buildflags];
644 my $sudo = $conf->get_program('sudo');
645 unshift @$cmd, $sudo if $sudo;
649 unless( scalar run( command => $cmd,
651 verbose => $verbose )
653 error(loc("Could not run '%1': %2", 'Build install', $buffer));
657 my %buildflags = $dist->_buildflags_as_hash($buildflags);
659 eval { $mb->dispatch('install', %buildflags) };
661 error(loc("Could not run '%1': %2", 'Build install', "$@"));
667 unless( $cb->_chdir( dir => $orig ) ) {
668 error( loc( "Could not chdir back to start dir '%1'", $orig ) );
671 return $dist->status->installed( $fail ? 0 : 1 );
674 ### returns the string 'foo=bar zot=quux' as (foo => bar, zot => quux)
675 sub _buildflags_as_hash {
677 my $flags = shift or return;
679 my @argv = Module::Build->split_like_shell($flags);
680 my ($argv) = Module::Build->read_args(@argv);
687 ### just in case you already did a create call for this module object
688 ### just via a different dist object
690 my $self = $dist->parent;
692 ### we're also the cpan_dist, since we don't need to have anything
693 ### prepared from another installer
694 $dist = $self->status->dist_cpan if $self->status->dist_cpan;
695 my $mb = $dist->status->_mb_object;
697 my $cb = $self->parent;
698 my $conf = $cb->configure_object;
703 unless( $dir = $self->status->extract ) {
704 error( loc( "No dir found to operate on!" ) );
708 ### chdir to work directory ###
710 unless( $cb->_chdir( dir => $dir ) ) {
711 error( loc( "Could not chdir to build directory '%1'", $dir ) );
715 my $fail; my $distdir;
717 $dist->prepare( @_ ) or (++$fail, last TRY);
720 eval { $mb->dispatch('distdir') };
722 error(loc("Could not run '%1': %2", 'Build distdir', "$@"));
726 ### /path/to/Foo-Bar-1.2/Foo-Bar-1.2
727 $distdir = File::Spec->catdir( $dir, $self->package_name . '-' .
728 $self->package_version );
730 unless( -d $distdir ) {
731 error(loc("Do not know where '%1' got created", 'distdir'));
736 unless( $cb->_chdir( dir => $orig ) ) {
737 error( loc( "Could not chdir to start directory '%1'", $orig ) );
747 Below are some of the known issues with Module::Build, that we hope
748 the authors will resolve at some point, so we can make full use of
749 Module::Build's power.
750 The number listed is the bug number on C<rt.cpan.org>.
754 =item * Module::Build can not be upgraded using its own API (#13169)
756 This is due to the fact that the Build file insists on adding a path
757 to C<@INC> which force the loading of the C<not yet installed>
758 Module::Build when it shells out to run it's own build procedure:
760 =item * Module::Build does not provide access to install history (#9793)
762 C<Module::Build> runs the create, test and install procedures in it's
763 own processes, but does not provide access to any diagnostic messages of
764 those processes. As an end result, we can not offer these diagnostic
765 messages when, for example, reporting automated build failures to sites
766 like C<testers.cpan.org>.
772 Originally by Jos Boumans E<lt>kane@cpan.orgE<gt>. Brought to working
773 condition and currently maintained by Ken Williams E<lt>kwilliams@cpan.orgE<gt>.
777 The CPAN++ interface (of which this module is a part of) is
778 copyright (c) 2001, 2002, 2003, 2004, 2005 Jos Boumans E<lt>kane@cpan.orgE<gt>.
781 This library is free software;
782 you may redistribute and/or modify it under the same
783 terms as Perl itself.
790 # c-indentation-style: bsd
792 # indent-tabs-mode: nil
794 # vim: expandtab shiftwidth=4: