1 package CPANPLUS::Dist::Build;
5 use vars qw[@ISA $STATUS $VERSION];
6 @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');
27 use Params::Check qw[check];
28 use Module::Load::Conditional qw[can_load check_install];
29 use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
31 local $Params::Check::VERBOSE = 1;
39 CPANPLUS::Dist::Build - CPANPLUS plugin to install packages that use Build.PL
43 my $build = CPANPLUS::Dist->new(
44 format => 'CPANPLUS::Dist::Build',
48 $build->prepare; # runs Build.PL
49 $build->create; # runs build && build test
50 $build->install; # runs build install
55 C<CPANPLUS::Dist::Build> is a distribution class for C<Module::Build>
57 Using this package, you can create, install and uninstall perl
58 modules. It inherits from C<CPANPLUS::Dist>.
60 Normal users won't have to worry about the interface to this module,
61 as it functions transparently as a plug-in to C<CPANPLUS> and will
62 just C<Do The Right Thing> when it's loaded.
70 Returns the C<CPANPLUS::Module> object that parented this object.
74 Returns the C<Object::Accessor> object that keeps the status for
79 =head1 STATUS ACCESSORS
81 All accessors can be accessed as follows:
82 $build->status->ACCESSOR
88 Location of the Build file.
89 Set to 0 explicitly if something went wrong.
93 BOOL indicating if the C<Build> command was successful.
97 BOOL indicating if the C<Build test> command was successful.
101 BOOL indicating if the C<prepare> call exited succesfully
102 This gets set after C<perl Build.PL>
106 Full path to the directory in which the C<prepare> call took place,
107 set after a call to C<prepare>.
111 BOOL indicating if the C<create> call exited succesfully. This gets
112 set after C<Build> and C<Build test>.
114 =item C<installed ()>
116 BOOL indicating if the module was installed. This gets set after
117 C<Build install> exits successfully.
121 BOOL indicating if the module was uninstalled properly.
123 =item C<_create_args ()>
125 Storage of the arguments passed to C<create> for this object. Used
126 for recursive calls when satisfying prerequisites.
128 =item C<_install_args ()>
130 Storage of the arguments passed to C<install> for this object. Used
131 for recursive calls when satisfying prerequisites.
139 =head2 $bool = CPANPLUS::Dist::Build->format_available();
141 Returns a boolean indicating whether or not you can use this package
142 to create and install modules in your environment.
146 ### check if the format is available ###
147 sub format_available {
148 my $mod = "Module::Build";
149 unless( can_load( modules => { $mod => '0.2611' } ) ) {
150 error( loc( "You do not have '%1' -- '%2' not available",
151 $mod, __PACKAGE__ ) );
159 =head2 $bool = $dist->init();
161 Sets up the C<CPANPLUS::Dist::Build> object for use.
162 Effectively creates all the needed status accessors.
164 Called automatically whenever you create a new C<CPANPLUS::Dist> object.
170 my $status = $dist->status;
172 $status->mk_accessors(qw[build_pl build test created installed uninstalled
173 _create_args _install_args _prepare_args
174 _mb_object _buildflags
177 ### just in case 'format_available' didn't get called
178 require Module::Build;
185 =head2 $bool = $dist->prepare([perl => '/path/to/perl', buildflags => 'EXTRA=FLAGS', force => BOOL, verbose => BOOL])
187 C<prepare> prepares a distribution, running C<Build.PL>
188 and establishing any prerequisites this
191 The variable C<PERL5_CPANPLUS_IS_EXECUTING> will be set to the full path
192 of the C<Build.PL> that is being executed. This enables any code inside
193 the C<Build.PL> to know that it is being installed via CPANPLUS.
195 After a succcesfull C<prepare> you may call C<create> to create the
196 distribution, followed by C<install> to actually install it.
198 Returns true on success and false on failure.
203 ### just in case you already did a create call for this module object
204 ### just via a different dist object
206 my $self = $dist->parent;
208 ### we're also the cpan_dist, since we don't need to have anything
209 ### prepared from another installer
210 $dist = $self->status->dist_cpan if $self->status->dist_cpan;
211 $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan;
213 my $cb = $self->parent;
214 my $conf = $cb->configure_object;
218 unless( $dir = $self->status->extract ) {
219 error( loc( "No dir found to operate on!" ) );
224 my( $force, $verbose, $buildflags, $perl, $prereq_target, $prereq_format,
226 { local $Params::Check::ALLOW_UNKNOWN = 1;
228 force => { default => $conf->get_conf('force'),
230 verbose => { default => $conf->get_conf('verbose'),
231 store => \$verbose },
232 perl => { default => $^X, store => \$perl },
233 buildflags => { default => $conf->get_conf('buildflags'),
234 store => \$buildflags },
235 prereq_target => { default => '', store => \$prereq_target },
236 prereq_format => { default => '',
237 store => \$prereq_format },
238 prereq_build => { default => 0, store => \$prereq_build },
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_list( $buildflags );
270 $dist->status->_buildflags( $buildflags );
275 ### we resolve 'configure requires' here, so we can run the 'perl
276 ### Makefile.PL' command
277 ### XXX for tests: mock f_c_r to something that *can* resolve and
278 ### something that *doesnt* resolve. Check the error log for ok
279 ### on this step or failure
280 ### XXX make a seperate tarball to test for this scenario: simply
281 ### containing a makefile.pl/build.pl for test purposes?
282 my $safe_ver = version->new('0.85_01');
283 if ( version->new($CPANPLUS::Internals::VERSION) >= $safe_ver )
284 { my $configure_requires = $dist->find_configure_requires;
285 my $ok = $dist->_resolve_prereqs(
286 format => $prereq_format,
288 prereqs => $configure_requires,
289 target => $prereq_target,
291 prereq_build => $prereq_build,
296 #### use $dist->flush to reset the cache ###
297 error( loc( "Unable to satisfy '%1' for '%2' " .
298 "-- aborting install",
299 'configure_requires', $self->module ) );
300 $dist->status->prepared(0);
304 ### end of prereq resolving ###
307 # Wrap the exception that may be thrown here (should likely be
308 # done at a much higher level).
311 my $env = ENV_CPANPLUS_IS_EXECUTING;
312 local $ENV{$env} = BUILD_PL->( $dir );
313 my $run_perl = $conf->get_program('perlwrapper');
316 $cmd = [$perl, BUILD_PL->($dir), @buildflags]
319 $cmd = [$perl, $run_perl, BUILD_PL->($dir), @buildflags]
322 unless ( scalar run( command => $cmd,
323 buffer => \$prep_output,
324 verbose => $verbose )
326 error( loc( "Build.PL failed: %1", $prep_output ) );
330 msg( $prep_output, 0 );
332 my $prereqs = $self->status->prereqs;
334 $prereqs ||= $dist->_find_prereqs( verbose => $verbose,
337 buildflags => $buildflags );
341 ### send out test report? ###
342 if( $fail and $conf->get_conf('cpantest') ) {
346 buffer => CPANPLUS::Error->stack_as_string,
349 ) or error(loc("Failed to send test report for '%1'",
353 unless( $cb->_chdir( dir => $orig ) ) {
354 error( loc( "Could not chdir back to start dir '%1'", $orig ) );
357 ### save where we wrote this stuff -- same as extract dir in normal
358 ### installer circumstances
359 $dist->status->distdir( $self->status->extract );
361 return $dist->status->prepared( $fail ? 0 : 1 );
366 my $self = $dist->parent;
367 my $cb = $self->parent;
368 my $conf = $cb->configure_object;
371 my ($verbose, $dir, $buildflags, $perl);
373 verbose => { default => $conf->get_conf('verbose'), store => \$verbose },
374 dir => { default => $self->status->extract, store => \$dir },
375 perl => { default => $^X, store => \$perl },
376 buildflags => { default => $conf->get_conf('buildflags'),
377 store => \$buildflags },
380 my $args = check( $tmpl, \%hash ) or return;
384 my $safe_ver = version->new('0.31_03');
388 if ( version->new( $Module::Build::VERSION ) >= $safe_ver and ! ON_WIN32 and ! ON_VMS ) {
389 my @buildflags = $dist->_buildflags_as_list( $buildflags );
391 # Use the new Build action 'prereq_data'
392 my $run_perl = $conf->get_program('perlwrapper');
394 unless ( scalar run( command => [$perl, $run_perl, BUILD->($dir), 'prereq_data', @buildflags],
398 error( loc( "Build 'prereq_data' failed: %1 %2", $!, $content ) );
404 my $file = File::Spec->catfile( $dir, '_build', 'prereqs' );
405 return unless -f $file;
407 my $fh = FileHandle->new();
409 unless( $fh->open( $file ) ) {
410 error( loc( "Cannot open '%1': %2", $file, $! ) );
414 $content = do { local $/; <$fh> };
417 return unless $content;
418 my $bphash = eval $content;
419 return unless $bphash and ref $bphash eq 'HASH';
420 foreach my $type ('requires', 'build_requires') {
421 next unless $bphash->{$type} and ref $bphash->{$type} eq 'HASH';
422 $prereqs->{$_} = $bphash->{$type}->{$_} for keys %{ $bphash->{$type} };
426 delete $prereqs->{'perl'};
428 ### allows for a user defined callback to filter the prerequisite
429 ### list as they see fit, to remove (or add) any prereqs they see
430 ### fit. The default installed callback will return the hashref in
431 ### an unmodified form
432 ### this callback got added after cpanplus 0.0562, so use a 'can'
433 ### to find out if it's supported. For older versions, we'll just
434 ### return the hashref as is ourselves.
435 my $href = $cb->_callbacks->can('filter_prereqs')
436 ? $cb->_callbacks->filter_prereqs->( $cb, $prereqs )
439 $self->status->prereqs( $href );
441 ### make sure it's not the same ref
447 =head2 $dist->create([perl => '/path/to/perl', buildflags => 'EXTRA=FLAGS', prereq_target => TARGET, force => BOOL, verbose => BOOL, skiptest => BOOL])
449 C<create> preps a distribution for installation. This means it will
450 run C<Build> and C<Build test>.
451 This will also satisfy any prerequisites the module may have.
453 If you set C<skiptest> to true, it will skip the C<Build test> stage.
454 If you set C<force> to true, it will go over all the stages of the
455 C<Build> process again, ignoring any previously cached results. It
456 will also ignore a bad return value from C<Build test> and still allow
457 the operation to return true.
459 Returns true on success and false on failure.
461 You may then call C<< $dist->install >> on the object to actually
467 ### just in case you already did a create call for this module object
468 ### just via a different dist object
470 my $self = $dist->parent;
472 ### we're also the cpan_dist, since we don't need to have anything
473 ### prepared from another installer
474 $dist = $self->status->dist_cpan if $self->status->dist_cpan;
475 $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan;
477 my $cb = $self->parent;
478 my $conf = $cb->configure_object;
482 unless( $dir = $self->status->extract ) {
483 error( loc( "No dir found to operate on!" ) );
488 my( $force, $verbose, $buildflags, $skiptest, $prereq_target,
489 $perl, $prereq_format, $prereq_build);
490 { local $Params::Check::ALLOW_UNKNOWN = 1;
492 force => { default => $conf->get_conf('force'),
494 verbose => { default => $conf->get_conf('verbose'),
495 store => \$verbose },
496 perl => { default => $^X, store => \$perl },
497 buildflags => { default => $conf->get_conf('buildflags'),
498 store => \$buildflags },
499 skiptest => { default => $conf->get_conf('skiptest'),
500 store => \$skiptest },
501 prereq_target => { default => '', store => \$prereq_target },
502 ### don't set the default format to 'build' -- that is wrong!
503 prereq_format => { #default => $self->status->installer_type,
505 store => \$prereq_format },
506 prereq_build => { default => 0, store => \$prereq_build },
509 $args = check( $tmpl, \%hash ) or return;
512 # restore the state as we have created this already.
513 if ( $dist->status->created && !$force ) {
514 ### add this directory to your lib ###
515 $self->add_to_includepath();
519 $dist->status->_create_args( $args );
521 ### is this dist prepared?
522 unless( $dist->status->prepared ) {
523 error( loc( "You have not successfully prepared a '%2' distribution ".
524 "yet -- cannot create yet", __PACKAGE__ ) );
528 ### chdir to work directory ###
530 unless( $cb->_chdir( dir => $dir ) ) {
531 error( loc( "Could not chdir to build directory '%1'", $dir ) );
535 ### by now we've loaded module::build, and we're using the API, so
536 ### it's safe to remove CPANPLUS::inc from our inc path, especially
537 ### because it can trip up tests run under taint (just like EU::MM).
538 ### turn off our PERL5OPT so no modules from CPANPLUS::inc get
539 ### included in make test -- it should build without.
540 ### also, modules that run in taint mode break if we leave
541 ### our code ref in perl5opt
542 ### XXX we've removed the ENV settings from cp::inc, so only need
543 ### to reset the @INC
544 #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt;
545 #local $ENV{PERL5LIB} = CPANPLUS::inc->original_perl5lib;
546 #local @INC = CPANPLUS::inc->original_inc;
548 ### but do it *before* the new_from_context, as M::B seems
549 ### to be actually running the file...
550 ### an unshift in the block seems to be ignored.. somehow...
551 #{ my $lib = $self->best_path_to_module_build;
552 # unshift @INC, $lib if $lib;
554 unshift @INC, $self->best_path_to_module_build
555 if $self->best_path_to_module_build;
557 ### this will generate warnings under anything lower than M::B 0.2606
558 my @buildflags = $dist->_buildflags_as_list( $buildflags );
559 $dist->status->_buildflags( $buildflags );
561 my $fail; my $prereq_fail; my $test_fail;
564 my $run_perl = $conf->get_program('perlwrapper');
566 ### this will set the directory back to the start
567 ### dir, so we must chdir /again/
568 my $ok = $dist->_resolve_prereqs(
570 format => $prereq_format,
572 prereqs => $self->status->prereqs,
573 target => $prereq_target,
574 prereq_build => $prereq_build,
577 unless( $cb->_chdir( dir => $dir ) ) {
578 error( loc( "Could not chdir to build directory '%1'", $dir ) );
583 #### use $dist->flush to reset the cache ###
584 error( loc( "Unable to satisfy prerequisites for '%1' " .
585 "-- aborting install", $self->module ) );
586 $dist->status->build(0);
587 $fail++; $prereq_fail++;
591 my ($captured, $cmd);
593 $cmd = [$perl, BUILD->($dir), @buildflags];
596 $cmd = [$perl, $run_perl, BUILD->($dir), @buildflags];
599 unless ( scalar run( command => $cmd,
600 buffer => \$captured,
601 verbose => $verbose )
603 error( loc( "MAKE failed:\n%1", $captured ) );
604 $dist->status->build(0);
610 $dist->status->build(1);
612 ### add this directory to your lib ###
613 $self->add_to_includepath();
615 ### this buffer will not include what tests failed due to a
616 ### M::B/Test::Harness bug. Reported as #9793 with patch
617 ### against 0.2607 on 26/1/2005
618 unless( $skiptest ) {
621 $cmd = [$perl, BUILD->($dir), "test", @buildflags];
624 $cmd = [$perl, $run_perl, BUILD->($dir), "test", @buildflags];
626 unless ( scalar run( command => $cmd,
627 buffer => \$test_output,
628 verbose => $verbose )
630 error( loc( "MAKE TEST failed:\n%1 ", $test_output ) );
632 ### mark specifically *test* failure.. so we dont
633 ### send success on force...
636 if( !$force and !$cb->_callbacks->proceed_on_test_failure->(
639 $dist->status->test(0);
645 msg( $test_output, 0 );
646 $dist->status->test(1);
650 msg(loc("Tests skipped"), $verbose);
654 unless( $cb->_chdir( dir => $orig ) ) {
655 error( loc( "Could not chdir back to start dir '%1'", $orig ) );
658 ### send out test report? ###
659 if( $conf->get_conf('cpantest') and not $prereq_fail ) {
662 failed => $test_fail || $fail,
663 buffer => CPANPLUS::Error->stack_as_string,
666 tests_skipped => $skiptest,
667 ) or error(loc("Failed to send test report for '%1'",
671 return $dist->status->created( $fail ? 0 : 1 );
674 =head2 $dist->install([verbose => BOOL, perl => /path/to/perl])
676 Actually installs the created dist.
678 Returns true on success and false on failure.
683 ### just in case you already did a create call for this module object
684 ### just via a different dist object
686 my $self = $dist->parent;
688 ### we're also the cpan_dist, since we don't need to have anything
689 ### prepared from another installer
690 $dist = $self->status->dist_cpan if $self->status->dist_cpan;
692 my $cb = $self->parent;
693 my $conf = $cb->configure_object;
697 my $verbose; my $perl; my $force;
698 { local $Params::Check::ALLOW_UNKNOWN = 1;
700 verbose => { default => $conf->get_conf('verbose'),
701 store => \$verbose },
702 force => { default => $conf->get_conf('force'),
704 perl => { default => $^X, store => \$perl },
707 my $args = check( $tmpl, \%hash ) or return;
708 $dist->status->_install_args( $args );
712 unless( $dir = $self->status->extract ) {
713 error( loc( "No dir found to operate on!" ) );
719 unless( $cb->_chdir( dir => $dir ) ) {
720 error( loc( "Could not chdir to build directory '%1'", $dir ) );
724 ### value set and false -- means failure ###
725 if( defined $self->status->installed &&
726 !$self->status->installed && !$force
728 error( loc( "Module '%1' has failed to install before this session " .
729 "-- aborting install", $self->module ) );
734 my @buildflags = $dist->_buildflags_as_list( $dist->status->_buildflags );
735 my $run_perl = $conf->get_program('perlwrapper');
737 ### hmm, how is this going to deal with sudo?
738 ### for now, check effective uid, if it's not root,
739 ### shell out, otherwise use the method
742 ### don't worry about loading the right version of M::B anymore
743 ### the 'new_from_context' already added the 'right' path to
744 ### M::B at the top of the build.pl
747 $cmd = [$perl, BUILD->($dir), "install", @buildflags];
750 $cmd = [$perl, $run_perl, BUILD->($dir), "install", @buildflags];
752 my $sudo = $conf->get_program('sudo');
753 unshift @$cmd, $sudo if $sudo;
757 unless( scalar run( command => $cmd,
759 verbose => $verbose )
761 error(loc("Could not run '%1': %2", 'Build install', $buffer));
765 my ($install_output, $cmd);
767 $cmd = [$perl, BUILD->($dir), "install", @buildflags];
770 $cmd = [$perl, $run_perl, BUILD->($dir), "install", @buildflags];
772 unless( scalar run( command => $cmd,
773 buffer => \$install_output,
774 verbose => $verbose )
776 error(loc("Could not run '%1': %2", 'Build install', $install_output));
780 msg( $install_output, 0 );
785 unless( $cb->_chdir( dir => $orig ) ) {
786 error( loc( "Could not chdir back to start dir '%1'", $orig ) );
789 return $dist->status->installed( $fail ? 0 : 1 );
792 ### returns the string 'foo=bar --zot quux'
793 ### as the list 'foo=bar', '--zot', 'qux'
794 sub _buildflags_as_list {
796 my $flags = shift or return;
798 return Module::Build->split_like_shell($flags);
803 Originally by Jos Boumans E<lt>kane@cpan.orgE<gt>. Brought to working
804 condition by Ken Williams E<lt>kwilliams@cpan.orgE<gt>.
806 Other hackery and currently maintained by Chris C<BinGOs> Williams ( no relation ). E<lt>bingos@cpan.orgE<gt>.
810 The CPAN++ interface (of which this module is a part of) is
811 copyright (c) 2001, 2002, 2003, 2004, 2005 Jos Boumans E<lt>kane@cpan.orgE<gt>.
814 This library is free software;
815 you may redistribute and/or modify it under the same
816 terms as Perl itself.
824 # c-indentation-style: bsd
826 # indent-tabs-mode: nil
828 # vim: expandtab shiftwidth=4: