diff options
Diffstat (limited to 'Master/tlpkg/tlperl/lib/CPANPLUS/Dist')
-rw-r--r-- | Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Autobundle.pm | 117 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Base.pm | 261 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build.pm | 836 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build/Constants.pm | 69 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/CPANPLUS/Dist/MM.pm | 1007 | ||||
-rw-r--r-- | Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Sample.pm | 16 |
6 files changed, 2306 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Autobundle.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Autobundle.pm new file mode 100644 index 00000000000..16638b258f8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Autobundle.pm @@ -0,0 +1,117 @@ +package CPANPLUS::Dist::Autobundle; + +use strict; +use warnings; +use CPANPLUS::Error qw[error msg]; +use Params::Check qw[check]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +use base qw[CPANPLUS::Dist::Base]; + +=head1 NAME + +CPANPLUS::Dist::Autobundle + +=head1 SYNOPSIS + + $modobj = $cb->parse_module( module => 'file://path/to/Snapshot_XXYY.pm' ); + $modobj->install; + +=head1 DESCRIPTION + +C<CPANPLUS::Dist::Autobundle> is a distribution class for installing installation +snapshots as created by C<CPANPLUS>' C<autobundle> command. + +All modules as mentioned in the snapshot will be installed on your system. + +=cut + +sub init { + my $dist = shift; + my $status = $dist->status; + + $status->mk_accessors( + qw[prepared created installed _prepare_args _create_args _install_args] + ); + + return 1; +} + +sub prepare { + my $dist = shift; + my %args = @_; + + ### store the arguments, so ->install can use them in recursive loops ### + $dist->status->_prepare_args( \%args ); + + return $dist->status->prepared( 1 ); +} + +sub create { + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my( $force, $verbose, $prereq_target, $prereq_format, $prereq_build); + + my $args = do { + local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + prereq_target => { default => '', store => \$prereq_target }, + + ### don't set the default prereq format to 'makemaker' -- wrong! + prereq_format => { #default => $self->status->installer_type, + default => '', + store => \$prereq_format }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + check( $tmpl, \%hash ) or return; + }; + + ### maybe we already ran a create on this object? ### + return 1 if $dist->status->created && !$force; + + ### store the arguments, so ->install can use them in recursive loops ### + $dist->status->_create_args( \%hash ); + + msg(loc("Resolving prerequisites mentioned in the bundle"), $verbose); + + ### this will set the directory back to the start + ### dir, so we must chdir /again/ + my $ok = $dist->_resolve_prereqs( + format => $prereq_format, + verbose => $verbose, + prereqs => $self->status->prereqs, + target => $prereq_target, + force => $force, + prereq_build => $prereq_build, + ); + + ### if all went well, mark it & return + return $dist->status->created( $ok ? 1 : 0); +} + +sub install { + my $dist = shift; + my %args = @_; + + ### store the arguments, so ->install can use them in recursive loops ### + $dist->status->_install_args( \%args ); + + return $dist->status->installed( 1 ); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Base.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Base.pm new file mode 100644 index 00000000000..c7108ed1392 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Base.pm @@ -0,0 +1,261 @@ +package CPANPLUS::Dist::Base; + +use strict; + +use base qw[CPANPLUS::Dist]; +use vars qw[$VERSION]; +$VERSION = $CPANPLUS::Internals::VERSION = $CPANPLUS::Internals::VERSION; + + +=head1 NAME + +CPANPLUS::Dist::Base - Base class for custom distribution classes + +=head1 SYNOPSIS + + package CPANPLUS::Dist::MY_IMPLEMENTATION + + use base 'CPANPLUS::Dist::Base'; + + sub prepare { + my $dist = shift; + + ### do the 'standard' things + $dist->SUPER::prepare( @_ ) or return; + + ### do MY_IMPLEMENTATION specific things + ... + + ### don't forget to set the status! + return $dist->status->prepared( $SUCCESS ? 1 : 0 ); + } + + +=head1 DESCRIPTION + +CPANPLUS::Dist::Base functions as a base class for all custom +distribution implementations. It does all the mundane work +CPANPLUS would have done without a custom distribution, so you +can override just the parts you need to make your own implementation +work. + +=head1 FLOW + +Below is a brief outline when and in which order methods in this +class are called: + + $Class->format_available; # can we use this class on this system? + + $dist->init; # set up custom accessors, etc + $dist->prepare; # find/write meta information + $dist->create; # write the distribution file + $dist->install; # install the distribution file + + $dist->uninstall; # remove the distribution (OPTIONAL) + +=head1 METHODS + +=cut + +=head2 @subs = $Class->methods + +Returns a list of methods that this class implements that you can +override. + +=cut + +sub methods { + return qw[format_available init prepare create install uninstall] +} + +=head2 $bool = $Class->format_available + +This method is called when someone requests a module to be installed +via the superclass. This gives you the opportunity to check if all +the needed requirements to build and install this distribution have +been met. + +For example, you might need a command line program, or a certain perl +module installed to do your job. Now is the time to check. + +Simply return true if the request can proceed and false if it can not. + +The C<CPANPLUS::Dist::Base> implementation always returns true. + +=cut + +sub format_available { return 1 } + + +=head2 $bool = $dist->init + +This method is called just after the new dist object is set up and +before the C<prepare> method is called. This is the time to set up +the object so it can be used with your class. + +For example, you might want to add extra accessors to the C<status> +object, which you might do as follows: + + $dist->status->mk_accessors( qw[my_implementation_accessor] ); + +The C<status> object is implemented as an instance of the +C<Object::Accessor> class. Please refer to its documentation for +details. + +Return true if the initialization was successul, and false if it was +not. + +The C<CPANPLUS::Dist::Base> implementation does not alter your object +and always returns true. + +=cut + +sub init { return 1; } + +=head2 $bool = $dist->prepare + +This runs the preparation step of your distribution. This step is meant +to set up the environment so the C<create> step can create the actual +distribution(file). +A C<prepare> call in the standard C<ExtUtils::MakeMaker> distribution +would, for example, run C<perl Makefile.PL> to find the dependencies +for a distribution. For a C<debian> distribution, this is where you +would write all the metafiles required for the C<dpkg-*> tools. + +The C<CPANPLUS::Dist::Base> implementation simply calls the underlying +distribution class (Typically C<CPANPLUS::Dist::MM> or +C<CPANPLUS::Dist::Build>). + +Sets C<< $dist->status->prepared >> to the return value of this function. +If you override this method, you should make sure to set this value. + +=cut + +sub prepare { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + my $dist_cpan = $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + + $dist->status->prepared( $dist_cpan->prepare( @_ ) ); +} + +=head2 $bool = $dist->create + +This runs the creation step of your distribution. This step is meant +to follow up on the C<prepare> call, that set up your environment so +the C<create> step can create the actual distribution(file). +A C<create> call in the standard C<ExtUtils::MakeMaker> distribution +would, for example, run C<make> and C<make test> to build and test +a distribution. For a C<debian> distribution, this is where you +would create the actual C<.deb> file using C<dpkg>. + +The C<CPANPLUS::Dist::Base> implementation simply calls the underlying +distribution class (Typically C<CPANPLUS::Dist::MM> or +C<CPANPLUS::Dist::Build>). + +Sets C<< $dist->status->dist >> to the location of the created +distribution. +If you override this method, you should make sure to set this value. + +Sets C<< $dist->status->created >> to the return value of this function. +If you override this method, you should make sure to set this value. + +=cut + +sub create { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + my $dist_cpan = $self->status->dist_cpan; + $dist = $self->status->dist if $self->status->dist; + $self->status->dist( $dist ) unless $self->status->dist; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my $format = ref $dist; + + ### make sure to set this variable, if the caller hasn't yet + ### just so we have some clue where the dist left off. + $dist->status->dist( $dist_cpan->status->distdir ) + unless defined $dist->status->dist; + + $dist->status->created( $dist_cpan->create(prereq_format => $format, @_) ); +} + +=head2 $bool = $dist->install + +This runs the install step of your distribution. This step is meant +to follow up on the C<create> call, which prepared a distribution(file) +to install. +A C<create> call in the standard C<ExtUtils::MakeMaker> distribution +would, for example, run C<make install> to copy the distribution files +to their final destination. For a C<debian> distribution, this is where +you would run C<dpkg --install> on the created C<.deb> file. + +The C<CPANPLUS::Dist::Base> implementation simply calls the underlying +distribution class (Typically C<CPANPLUS::Dist::MM> or +C<CPANPLUS::Dist::Build>). + +Sets C<< $dist->status->installed >> to the return value of this function. +If you override this method, you should make sure to set this value. + +=cut + +sub install { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + my $dist_cpan = $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + + $dist->status->installed( $dist_cpan->install( @_ ) ); +} + +=head2 $bool = $dist->uninstall + +This runs the uninstall step of your distribution. This step is meant +to remove the distribution from the file system. +A C<uninstall> call in the standard C<ExtUtils::MakeMaker> distribution +would, for example, run C<make uninstall> to remove the distribution +files the file system. For a C<debian> distribution, this is where you +would run C<dpkg --uninstall PACKAGE>. + +The C<CPANPLUS::Dist::Base> implementation simply calls the underlying +distribution class (Typically C<CPANPLUS::Dist::MM> or +C<CPANPLUS::Dist::Build>). + +Sets C<< $dist->status->uninstalled >> to the return value of this function. +If you override this method, you should make sure to set this value. + +=cut + +sub uninstall { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + my $dist_cpan = $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + + $dist->status->uninstalled( $dist_cpan->uninstall( @_ ) ); +} + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build.pm new file mode 100644 index 00000000000..0f27639cda5 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build.pm @@ -0,0 +1,836 @@ +package CPANPLUS::Dist::Build; + +use strict; +use warnings; +use vars qw[@ISA $STATUS $VERSION]; +@ISA = qw[CPANPLUS::Dist]; + +use CPANPLUS::Internals::Constants; + +### these constants were exported by CPANPLUS::Internals::Constants +### in previous versions.. they do the same though. If we want to have +### a normal 'use' here, up the dependency to CPANPLUS 0.056 or higher +BEGIN { + require CPANPLUS::Dist::Build::Constants; + CPANPLUS::Dist::Build::Constants->import() + if not __PACKAGE__->can('BUILD') && __PACKAGE__->can('BUILD_DIR'); +} + +use CPANPLUS::Error; + +use Config; +use FileHandle; +use Cwd; +use version; + +use IPC::Cmd qw[run]; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load check_install]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +local $Params::Check::VERBOSE = 1; + +$VERSION = '0.46'; + +=pod + +=head1 NAME + +CPANPLUS::Dist::Build - CPANPLUS plugin to install packages that use Build.PL + +=head1 SYNOPSIS + + my $build = CPANPLUS::Dist->new( + format => 'CPANPLUS::Dist::Build', + module => $modobj, + ); + + $build->prepare; # runs Build.PL + $build->create; # runs build && build test + $build->install; # runs build install + + +=head1 DESCRIPTION + +C<CPANPLUS::Dist::Build> is a distribution class for C<Module::Build> +related modules. +Using this package, you can create, install and uninstall perl +modules. It inherits from C<CPANPLUS::Dist>. + +Normal users won't have to worry about the interface to this module, +as it functions transparently as a plug-in to C<CPANPLUS> and will +just C<Do The Right Thing> when it's loaded. + +=head1 ACCESSORS + +=over 4 + +=item C<parent()> + +Returns the C<CPANPLUS::Module> object that parented this object. + +=item C<status()> + +Returns the C<Object::Accessor> object that keeps the status for +this module. + +=back + +=head1 STATUS ACCESSORS + +All accessors can be accessed as follows: + $build->status->ACCESSOR + +=over 4 + +=item C<build_pl ()> + +Location of the Build file. +Set to 0 explicitly if something went wrong. + +=item C<build ()> + +BOOL indicating if the C<Build> command was successful. + +=item C<test ()> + +BOOL indicating if the C<Build test> command was successful. + +=item C<prepared ()> + +BOOL indicating if the C<prepare> call exited succesfully +This gets set after C<perl Build.PL> + +=item C<distdir ()> + +Full path to the directory in which the C<prepare> call took place, +set after a call to C<prepare>. + +=item C<created ()> + +BOOL indicating if the C<create> call exited succesfully. This gets +set after C<Build> and C<Build test>. + +=item C<installed ()> + +BOOL indicating if the module was installed. This gets set after +C<Build install> exits successfully. + +=item uninstalled () + +BOOL indicating if the module was uninstalled properly. + +=item C<_create_args ()> + +Storage of the arguments passed to C<create> for this object. Used +for recursive calls when satisfying prerequisites. + +=item C<_install_args ()> + +Storage of the arguments passed to C<install> for this object. Used +for recursive calls when satisfying prerequisites. + +=back + +=cut + +=head1 METHODS + +=head2 $bool = CPANPLUS::Dist::Build->format_available(); + +Returns a boolean indicating whether or not you can use this package +to create and install modules in your environment. + +=cut + +### check if the format is available ### +sub format_available { + my $mod = "Module::Build"; + unless( can_load( modules => { $mod => '0.2611' } ) ) { + error( loc( "You do not have '%1' -- '%2' not available", + $mod, __PACKAGE__ ) ); + return; + } + + return 1; +} + + +=head2 $bool = $dist->init(); + +Sets up the C<CPANPLUS::Dist::Build> object for use. +Effectively creates all the needed status accessors. + +Called automatically whenever you create a new C<CPANPLUS::Dist> object. + +=cut + +sub init { + my $dist = shift; + my $status = $dist->status; + + $status->mk_accessors(qw[build_pl build test created installed uninstalled + _create_args _install_args _prepare_args + _mb_object _buildflags + ]); + + ### just in case 'format_available' didn't get called + require Module::Build; + + return 1; +} + +=pod + +=head2 $bool = $dist->prepare([perl => '/path/to/perl', buildflags => 'EXTRA=FLAGS', force => BOOL, verbose => BOOL]) + +C<prepare> prepares a distribution, running C<Build.PL> +and establishing any prerequisites this +distribution has. + +The variable C<PERL5_CPANPLUS_IS_EXECUTING> will be set to the full path +of the C<Build.PL> that is being executed. This enables any code inside +the C<Build.PL> to know that it is being installed via CPANPLUS. + +After a succcesfull C<prepare> you may call C<create> to create the +distribution, followed by C<install> to actually install it. + +Returns true on success and false on failure. + +=cut + +sub prepare { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared from another installer + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $args; + my( $force, $verbose, $buildflags, $perl, $prereq_target, $prereq_format, + $prereq_build ); + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + perl => { default => $^X, store => \$perl }, + buildflags => { default => $conf->get_conf('buildflags'), + store => \$buildflags }, + prereq_target => { default => '', store => \$prereq_target }, + prereq_format => { default => '', + store => \$prereq_format }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + return 1 if $dist->status->prepared && !$force; + + $dist->status->_prepare_args( $args ); + + ### chdir to work directory ### + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + ### by now we've loaded module::build, and we're using the API, so + ### it's safe to remove CPANPLUS::inc from our inc path, especially + ### because it can trip up tests run under taint (just like EU::MM). + ### turn off our PERL5OPT so no modules from CPANPLUS::inc get + ### included in make test -- it should build without. + ### also, modules that run in taint mode break if we leave + ### our code ref in perl5opt + ### XXX we've removed the ENV settings from cp::inc, so only need + ### to reset the @INC + #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt; + #local $ENV{PERL5LIB} = CPANPLUS::inc->original_perl5lib; + #local @INC = CPANPLUS::inc->original_inc; + + ### this will generate warnings under anything lower than M::B 0.2606 + my @buildflags = $dist->_buildflags_as_list( $buildflags ); + $dist->status->_buildflags( $buildflags ); + + my $fail; + RUN: { + # 0.85_01 + ### we resolve 'configure requires' here, so we can run the 'perl + ### Makefile.PL' command + ### XXX for tests: mock f_c_r to something that *can* resolve and + ### something that *doesnt* resolve. Check the error log for ok + ### on this step or failure + ### XXX make a seperate tarball to test for this scenario: simply + ### containing a makefile.pl/build.pl for test purposes? + my $safe_ver = version->new('0.85_01'); + if ( version->new($CPANPLUS::Internals::VERSION) >= $safe_ver ) + { my $configure_requires = $dist->find_configure_requires; + my $ok = $dist->_resolve_prereqs( + format => $prereq_format, + verbose => $verbose, + prereqs => $configure_requires, + target => $prereq_target, + force => $force, + prereq_build => $prereq_build, + ); + + unless( $ok ) { + + #### use $dist->flush to reset the cache ### + error( loc( "Unable to satisfy '%1' for '%2' " . + "-- aborting install", + 'configure_requires', $self->module ) ); + $dist->status->prepared(0); + $fail++; + last RUN; + } + ### end of prereq resolving ### + } + + # Wrap the exception that may be thrown here (should likely be + # done at a much higher level). + my $prep_output; + + my $env = ENV_CPANPLUS_IS_EXECUTING; + local $ENV{$env} = BUILD_PL->( $dir ); + my $run_perl = $conf->get_program('perlwrapper'); + my $cmd = [$perl, $run_perl, BUILD_PL->($dir), @buildflags]; + + unless ( scalar run( command => $cmd, + buffer => \$prep_output, + verbose => $verbose ) + ) { + error( loc( "Build.PL failed: %1", $prep_output ) ); + $fail++; last RUN; + } + + msg( $prep_output, 0 ); + + my $prereqs = $self->status->prereqs; + + $prereqs ||= $dist->_find_prereqs( verbose => $verbose, + dir => $dir, + perl => $perl, + buildflags => $buildflags ); + + } + + ### send out test report? ### + if( $fail and $conf->get_conf('cpantest') ) { + $cb->_send_report( + module => $self, + failed => $fail, + buffer => CPANPLUS::Error->stack_as_string, + verbose => $verbose, + force => $force, + ) or error(loc("Failed to send test report for '%1'", + $self->module ) ); + } + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + ### save where we wrote this stuff -- same as extract dir in normal + ### installer circumstances + $dist->status->distdir( $self->status->extract ); + + return $dist->status->prepared( $fail ? 0 : 1 ); +} + +sub _find_prereqs { + my $dist = shift; + my $self = $dist->parent; + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my ($verbose, $dir, $buildflags, $perl); + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + dir => { default => $self->status->extract, store => \$dir }, + perl => { default => $^X, store => \$perl }, + buildflags => { default => $conf->get_conf('buildflags'), + store => \$buildflags }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my $prereqs = {}; + + $prereqs = $dist->find_mymeta_requires() + if $dist->can('find_mymeta_requires'); + + if ( keys %$prereqs ) { + # Ugly hack + } + else { + my $safe_ver = version->new('0.31_03'); + my $content; + PREREQS: { + if ( version->new( $Module::Build::VERSION ) >= $safe_ver and IPC::Cmd->can_capture_buffer ) { + my @buildflags = $dist->_buildflags_as_list( $buildflags ); + + # Use the new Build action 'prereq_data' + my $run_perl = $conf->get_program('perlwrapper'); + + unless ( scalar run( command => [$perl, $run_perl, BUILD->($dir), 'prereq_data', @buildflags], + buffer => \$content, + verbose => 0 ) + ) { + error( loc( "Build 'prereq_data' failed: %1 %2", $!, $content ) ); + #return; + } + else { + last PREREQS; + } + + } + + my $file = File::Spec->catfile( $dir, '_build', 'prereqs' ); + return unless -f $file; + + my $fh = FileHandle->new(); + + unless( $fh->open( $file ) ) { + error( loc( "Cannot open '%1': %2", $file, $! ) ); + return; + } + + $content = do { local $/; <$fh> }; + + } + + return unless $content; + my $bphash = eval $content; + return unless $bphash and ref $bphash eq 'HASH'; + foreach my $type ('requires', 'build_requires') { + next unless $bphash->{$type} and ref $bphash->{$type} eq 'HASH'; + $prereqs->{$_} = $bphash->{$type}->{$_} for keys %{ $bphash->{$type} }; + } + } + # Temporary fix + delete $prereqs->{'perl'}; + + ### allows for a user defined callback to filter the prerequisite + ### list as they see fit, to remove (or add) any prereqs they see + ### fit. The default installed callback will return the hashref in + ### an unmodified form + ### this callback got added after cpanplus 0.0562, so use a 'can' + ### to find out if it's supported. For older versions, we'll just + ### return the hashref as is ourselves. + my $href = $cb->_callbacks->can('filter_prereqs') + ? $cb->_callbacks->filter_prereqs->( $cb, $prereqs ) + : $prereqs; + + $self->status->prereqs( $href ); + + ### make sure it's not the same ref + return { %$href }; +} + +=pod + +=head2 $dist->create([perl => '/path/to/perl', buildflags => 'EXTRA=FLAGS', prereq_target => TARGET, force => BOOL, verbose => BOOL, skiptest => BOOL]) + +C<create> preps a distribution for installation. This means it will +run C<Build> and C<Build test>. +This will also satisfy any prerequisites the module may have. + +If you set C<skiptest> to true, it will skip the C<Build test> stage. +If you set C<force> to true, it will go over all the stages of the +C<Build> process again, ignoring any previously cached results. It +will also ignore a bad return value from C<Build test> and still allow +the operation to return true. + +Returns true on success and false on failure. + +You may then call C<< $dist->install >> on the object to actually +install it. + +=cut + +sub create { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared from another installer + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $args; + my( $force, $verbose, $buildflags, $skiptest, $prereq_target, + $perl, $prereq_format, $prereq_build); + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + perl => { default => $^X, store => \$perl }, + buildflags => { default => $conf->get_conf('buildflags'), + store => \$buildflags }, + skiptest => { default => $conf->get_conf('skiptest'), + store => \$skiptest }, + prereq_target => { default => '', store => \$prereq_target }, + ### don't set the default format to 'build' -- that is wrong! + prereq_format => { #default => $self->status->installer_type, + default => '', + store => \$prereq_format }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + # restore the state as we have created this already. + if ( $dist->status->created && !$force ) { + ### add this directory to your lib ### + $self->add_to_includepath(); + return 1; + } + + $dist->status->_create_args( $args ); + + ### is this dist prepared? + unless( $dist->status->prepared ) { + error( loc( "You have not successfully prepared a '%2' distribution ". + "yet -- cannot create yet", __PACKAGE__ ) ); + return; + } + + ### chdir to work directory ### + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + ### by now we've loaded module::build, and we're using the API, so + ### it's safe to remove CPANPLUS::inc from our inc path, especially + ### because it can trip up tests run under taint (just like EU::MM). + ### turn off our PERL5OPT so no modules from CPANPLUS::inc get + ### included in make test -- it should build without. + ### also, modules that run in taint mode break if we leave + ### our code ref in perl5opt + ### XXX we've removed the ENV settings from cp::inc, so only need + ### to reset the @INC + #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt; + #local $ENV{PERL5LIB} = CPANPLUS::inc->original_perl5lib; + #local @INC = CPANPLUS::inc->original_inc; + + ### but do it *before* the new_from_context, as M::B seems + ### to be actually running the file... + ### an unshift in the block seems to be ignored.. somehow... + #{ my $lib = $self->best_path_to_module_build; + # unshift @INC, $lib if $lib; + #} + unshift @INC, $self->best_path_to_module_build + if $self->best_path_to_module_build; + + ### this will generate warnings under anything lower than M::B 0.2606 + my @buildflags = $dist->_buildflags_as_list( $buildflags ); + $dist->status->_buildflags( $buildflags ); + + my $fail; my $prereq_fail; my $test_fail; + RUN: { + + my $run_perl = $conf->get_program('perlwrapper'); + + ### this will set the directory back to the start + ### dir, so we must chdir /again/ + my $ok = $dist->_resolve_prereqs( + force => $force, + format => $prereq_format, + verbose => $verbose, + prereqs => $self->status->prereqs, + target => $prereq_target, + prereq_build => $prereq_build, + ); + + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + unless( $ok ) { + #### use $dist->flush to reset the cache ### + error( loc( "Unable to satisfy prerequisites for '%1' " . + "-- aborting install", $self->module ) ); + $dist->status->build(0); + $fail++; $prereq_fail++; + last RUN; + } + + my ($captured, $cmd); + if ( ON_VMS ) { + $cmd = [$perl, BUILD->($dir), @buildflags]; + } + else { + $cmd = [$perl, $run_perl, BUILD->($dir), @buildflags]; + } + + unless ( scalar run( command => $cmd, + buffer => \$captured, + verbose => $verbose ) + ) { + error( loc( "MAKE failed:\n%1", $captured ) ); + $dist->status->build(0); + $fail++; last RUN; + } + + msg( $captured, 0 ); + + $dist->status->build(1); + + ### add this directory to your lib ### + $self->add_to_includepath(); + + ### this buffer will not include what tests failed due to a + ### M::B/Test::Harness bug. Reported as #9793 with patch + ### against 0.2607 on 26/1/2005 + unless( $skiptest ) { + my $test_output; + if ( ON_VMS ) { + $cmd = [$perl, BUILD->($dir), "test", @buildflags]; + } + else { + $cmd = [$perl, $run_perl, BUILD->($dir), "test", @buildflags]; + } + unless ( scalar run( command => $cmd, + buffer => \$test_output, + verbose => $verbose ) + ) { + error( loc( "MAKE TEST failed:\n%1 ", $test_output ) ); + + ### mark specifically *test* failure.. so we dont + ### send success on force... + $test_fail++; + + if( !$force and !$cb->_callbacks->proceed_on_test_failure->( + $self, $@ ) + ) { + $dist->status->test(0); + $fail++; last RUN; + } + + } + else { + msg( loc( "MAKE TEST passed:\n%1", $test_output ), 0 ); + #msg( $test_output, 0 ); + $dist->status->test(1); + } + } + else { + msg(loc("Tests skipped"), $verbose); + } + } + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + ### send out test report? ### + if( $conf->get_conf('cpantest') and not $prereq_fail ) { + $cb->_send_report( + module => $self, + failed => $test_fail || $fail, + buffer => CPANPLUS::Error->stack_as_string, + verbose => $verbose, + force => $force, + tests_skipped => $skiptest, + ) or error(loc("Failed to send test report for '%1'", + $self->module ) ); + } + + return $dist->status->created( $fail ? 0 : 1 ); +} + +=head2 $dist->install([verbose => BOOL, perl => /path/to/perl]) + +Actually installs the created dist. + +Returns true on success and false on failure. + +=cut + +sub install { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared from another installer + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + + my $verbose; my $perl; my $force; my $buildflags; + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + force => { default => $conf->get_conf('force'), + store => \$force }, + buildflags => { default => $conf->get_conf('buildflags'), + store => \$buildflags }, + perl => { default => $^X, store => \$perl }, + }; + + my $args = check( $tmpl, \%hash ) or return; + $dist->status->_install_args( $args ); + } + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $orig = cwd(); + + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + ### value set and false -- means failure ### + if( defined $self->status->installed && + !$self->status->installed && !$force + ) { + error( loc( "Module '%1' has failed to install before this session " . + "-- aborting install", $self->module ) ); + return; + } + + my $fail; + my @buildflags = $dist->_buildflags_as_list( $buildflags ); + my $run_perl = $conf->get_program('perlwrapper'); + + ### hmm, how is this going to deal with sudo? + ### for now, check effective uid, if it's not root, + ### shell out, otherwise use the method + if( $> ) { + + ### don't worry about loading the right version of M::B anymore + ### the 'new_from_context' already added the 'right' path to + ### M::B at the top of the build.pl + my $cmd; + if ( ON_VMS ) { + $cmd = [$perl, BUILD->($dir), "install", @buildflags]; + } + else { + $cmd = [$perl, $run_perl, BUILD->($dir), "install", @buildflags]; + } + my $sudo = $conf->get_program('sudo'); + unshift @$cmd, $sudo if $sudo; + + + my $buffer; + unless( scalar run( command => $cmd, + buffer => \$buffer, + verbose => $verbose ) + ) { + error(loc("Could not run '%1': %2", 'Build install', $buffer)); + $fail++; + } + } else { + my ($install_output, $cmd); + if ( ON_VMS ) { + $cmd = [$perl, BUILD->($dir), "install", @buildflags]; + } + else { + $cmd = [$perl, $run_perl, BUILD->($dir), "install", @buildflags]; + } + unless( scalar run( command => $cmd, + buffer => \$install_output, + verbose => $verbose ) + ) { + error(loc("Could not run '%1': %2", 'Build install', $install_output)); + $fail++; + } + else { + msg( $install_output, 0 ); + } + } + + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + return $dist->status->installed( $fail ? 0 : 1 ); +} + +### returns the string 'foo=bar --zot quux' +### as the list 'foo=bar', '--zot', 'qux' +sub _buildflags_as_list { + my $self = shift; + my $flags = shift or return; + + return Module::Build->split_like_shell($flags); +} + +=head1 AUTHOR + +Originally by Jos Boumans E<lt>kane@cpan.orgE<gt>. Brought to working +condition by Ken Williams E<lt>kwilliams@cpan.orgE<gt>. + +Other hackery and currently maintained by Chris C<BinGOs> Williams ( no relation ). E<lt>bingos@cpan.orgE<gt>. + +=head1 LICENSE + +The CPAN++ interface (of which this module is a part of) is +copyright (c) 2001, 2002, 2003, 2004, 2005 Jos Boumans E<lt>kane@cpan.orgE<gt>. +All rights reserved. + +This library is free software; +you may redistribute and/or modify it under the same +terms as Perl itself. + +=cut + +qq[Putting the Module::Build into CPANPLUS]; + + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build/Constants.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build/Constants.pm new file mode 100644 index 00000000000..1ac02108e44 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build/Constants.pm @@ -0,0 +1,69 @@ +package CPANPLUS::Dist::Build::Constants; + +use strict; +use warnings; +use File::Spec; + +BEGIN { + + require Exporter; + use vars qw[$VERSION @ISA @EXPORT]; + + $VERSION = '0.46'; + @ISA = qw[Exporter]; + @EXPORT = qw[ BUILD_DIR BUILD ]; +} + + +use constant BUILD_DIR => sub { return @_ + ? File::Spec->catdir($_[0], '_build') + : '_build'; + }; +use constant BUILD => sub { my $file = @_ + ? File::Spec->catfile($_[0], 'Build') + : 'Build'; + + ### on VMS, '.com' is appended when + ### creating the Build file + $file .= '.com' if $^O eq 'VMS'; + + return $file; + }; + +1; + +=head1 NAME + +CPANPLUS::Dist::Build::Constants - Constants for CPANPLUS::Dist::Build + +=head1 SYNOPSIS + + use CPANPLUS::Dist::Build::Constants; + +=head1 DESCRIPTION + +CPANPLUS::Dist::Build::Constants provides some constants required by L<CPANPLUS::Dist::Build>. + +=head1 AUTHOR + +Originally by Jos Boumans E<lt>kane@cpan.orgE<gt>. Brought to working +condition and currently maintained by Ken Williams E<lt>kwilliams@cpan.orgE<gt>. + +=head1 LICENSE + +The CPAN++ interface (of which this module is a part of) is +copyright (c) 2001, 2002, 2003, 2004, 2005 Jos Boumans E<lt>kane@cpan.orgE<gt>. +All rights reserved. + +This library is free software; +you may redistribute and/or modify it under the same +terms as Perl itself. + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/MM.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/MM.pm new file mode 100644 index 00000000000..be65cd43cc8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/MM.pm @@ -0,0 +1,1007 @@ +package CPANPLUS::Dist::MM; + +use warnings; +use strict; +use vars qw[@ISA $STATUS]; +use base 'CPANPLUS::Dist::Base'; + +use CPANPLUS::Internals::Constants; +use CPANPLUS::Internals::Constants::Report; +use CPANPLUS::Error; +use FileHandle; +use Cwd; + +use IPC::Cmd qw[run]; +use Params::Check qw[check]; +use File::Basename qw[dirname]; +use Module::Load::Conditional qw[can_load check_install]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +local $Params::Check::VERBOSE = 1; + +=pod + +=head1 NAME + +CPANPLUS::Dist::MM + +=head1 SYNOPSIS + + $mm = CPANPLUS::Dist::MM->new( module => $modobj ); + + $mm->create; # runs make && make test + $mm->install; # runs make install + + +=head1 DESCRIPTION + +C<CPANPLUS::Dist::MM> is a distribution class for MakeMaker related +modules. +Using this package, you can create, install and uninstall perl +modules. It inherits from C<CPANPLUS::Dist>. + +=head1 ACCESSORS + +=over 4 + +=item parent() + +Returns the C<CPANPLUS::Module> object that parented this object. + +=item status() + +Returns the C<Object::Accessor> object that keeps the status for +this module. + +=back + +=head1 STATUS ACCESSORS + +All accessors can be accessed as follows: + $mm->status->ACCESSOR + +=over 4 + +=item makefile () + +Location of the Makefile (or Build file). +Set to 0 explicitly if something went wrong. + +=item make () + +BOOL indicating if the C<make> (or C<Build>) command was successful. + +=item test () + +BOOL indicating if the C<make test> (or C<Build test>) command was +successful. + +=item prepared () + +BOOL indicating if the C<prepare> call exited succesfully +This gets set after C<perl Makefile.PL> + +=item distdir () + +Full path to the directory in which the C<prepare> call took place, +set after a call to C<prepare>. + +=item created () + +BOOL indicating if the C<create> call exited succesfully. This gets +set after C<make> and C<make test>. + +=item installed () + +BOOL indicating if the module was installed. This gets set after +C<make install> (or C<Build install>) exits successfully. + +=item uninstalled () + +BOOL indicating if the module was uninstalled properly. + +=item _create_args () + +Storage of the arguments passed to C<create> for this object. Used +for recursive calls when satisfying prerequisites. + +=item _install_args () + +Storage of the arguments passed to C<install> for this object. Used +for recursive calls when satisfying prerequisites. + +=back + +=cut + +=head1 METHODS + +=head2 $bool = $dist->format_available(); + +Returns a boolean indicating whether or not you can use this package +to create and install modules in your environment. + +=cut + +### check if the format is available ### +sub format_available { + my $dist = shift; + + ### we might be called as $class->format_available =/ + require CPANPLUS::Internals; + my $cb = CPANPLUS::Internals->_retrieve_id( + CPANPLUS::Internals->_last_id ); + my $conf = $cb->configure_object; + + my $mod = "ExtUtils::MakeMaker"; + unless( can_load( modules => { $mod => 0.0 } ) ) { + error( loc( "You do not have '%1' -- '%2' not available", + $mod, __PACKAGE__ ) ); + return; + } + + for my $pgm ( qw[make] ) { + unless( $conf->get_program( $pgm ) ) { + error(loc( + "You do not have '%1' in your path -- '%2' not available\n" . + "Please check your config entry for '%1'", + $pgm, __PACKAGE__ , $pgm + )); + return; + } + } + + return 1; +} + +=pod $bool = $dist->init(); + +Sets up the C<CPANPLUS::Dist::MM> object for use. +Effectively creates all the needed status accessors. + +Called automatically whenever you create a new C<CPANPLUS::Dist> object. + +=cut + +sub init { + my $dist = shift; + my $status = $dist->status; + + $status->mk_accessors(qw[makefile make test created installed uninstalled + bin_make _prepare_args _create_args _install_args] + ); + + return 1; +} + +=pod $bool = $dist->prepare([perl => '/path/to/perl', makemakerflags => 'EXTRA=FLAGS', force => BOOL, verbose => BOOL]) + +C<prepare> preps a distribution for installation. This means it will +run C<perl Makefile.PL> and determine what prerequisites this distribution +declared. + +If you set C<force> to true, it will go over all the stages of the +C<prepare> process again, ignoring any previously cached results. + +When running C<perl Makefile.PL>, the environment variable +C<PERL5_CPANPLUS_IS_EXECUTING> will be set to the full path of the +C<Makefile.PL> that is being executed. This enables any code inside +the C<Makefile.PL> to know that it is being installed via CPANPLUS. + +Returns true on success and false on failure. + +You may then call C<< $dist->create >> on the object to create the +installable files. + +=cut + +sub prepare { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $args; + my( $force, $verbose, $perl, @mmflags, $prereq_target, $prereq_format, + $prereq_build ); + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + perl => { default => $^X, store => \$perl }, + makemakerflags => { default => + $conf->get_conf('makemakerflags') || '', + store => \$mmflags[0] }, + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + prereq_target => { default => '', store => \$prereq_target }, + prereq_format => { default => '', + store => \$prereq_format }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + + ### maybe we already ran a create on this object? ### + return 1 if $dist->status->prepared && !$force; + + ### store the arguments, so ->install can use them in recursive loops ### + $dist->status->_prepare_args( $args ); + + ### chdir to work directory ### + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + my $fail; + RUN: { + + ### we resolve 'configure requires' here, so we can run the 'perl + ### Makefile.PL' command + ### XXX for tests: mock f_c_r to something that *can* resolve and + ### something that *doesnt* resolve. Check the error log for ok + ### on this step or failure + ### XXX make a seperate tarball to test for this scenario: simply + ### containing a makefile.pl/build.pl for test purposes? + { my $configure_requires = $dist->find_configure_requires; + my $ok = $dist->_resolve_prereqs( + format => $prereq_format, + verbose => $verbose, + prereqs => $configure_requires, + target => $prereq_target, + force => $force, + prereq_build => $prereq_build, + ); + + unless( $ok ) { + + #### use $dist->flush to reset the cache ### + error( loc( "Unable to satisfy '%1' for '%2' " . + "-- aborting install", + 'configure_requires', $self->module ) ); + $dist->status->prepared(0); + $fail++; + last RUN; + } + ### end of prereq resolving ### + } + + + + ### don't run 'perl makefile.pl' again if there's a makefile already + if( -e MAKEFILE->() && (-M MAKEFILE->() < -M $dir) && !$force ) { + msg(loc("'%1' already exists, not running '%2 %3' again ". + " unless you force", + MAKEFILE->(), $perl, MAKEFILE_PL->() ), $verbose ); + + } else { + unless( -e MAKEFILE_PL->() ) { + msg(loc("No '%1' found - attempting to generate one", + MAKEFILE_PL->() ), $verbose ); + + $dist->write_makefile_pl( + verbose => $verbose, + force => $force + ); + + ### bail out if there's no makefile.pl ### + unless( -e MAKEFILE_PL->() ) { + error( loc( "Could not find '%1' - cannot continue", + MAKEFILE_PL->() ) ); + + ### mark that we screwed up ### + $dist->status->makefile(0); + $fail++; last RUN; + } + } + + ### you can turn off running this verbose by changing + ### the config setting below, although it is really not + ### recommended + my $run_verbose = $verbose || + $conf->get_conf('allow_build_interactivity') || + 0; + + ### this makes MakeMaker use defaults if possible, according + ### to schwern. See ticket 8047 for details. + local $ENV{PERL_MM_USE_DEFAULT} = 1 unless $run_verbose; + + ### turn off our PERL5OPT so no modules from CPANPLUS::inc get + ### included in the makefile.pl -- it should build without + ### also, modules that run in taint mode break if we leave + ### our code ref in perl5opt + ### XXX we've removed the ENV settings from cp::inc, so only need + ### to reset the @INC + #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt || ''; + + ### make sure it's a string, so that mmflags that have more than + ### one key value pair are passed as is, rather than as: + ### perl Makefile.PL "key=val key=>val" + + + #### XXX this needs to be the absolute path to the Makefile.PL + ### since cpanp-run-perl uses 'do' to execute the file, and do() + ### checks your @INC.. so, if there's _another_ makefile.pl in + ### your @INC, it will execute that one... + my $makefile_pl = MAKEFILE_PL->( $cb->_safe_path( path => $dir ) ); + + ### setting autoflush to true fixes issue from rt #8047 + ### XXX this means that we need to keep the path to CPANPLUS + ### in @INC, stopping us from resolving dependencies on CPANPLUS + ### at bootstrap time properly. + + ### XXX this fails under ipc::run due to the extra quotes, + ### but it works in ipc::open3. however, ipc::open3 doesn't work + ### on win32/cygwin. XXX TODO get a windows box and sort this out + # my $cmd = qq[$perl -MEnglish -le ] . + # QUOTE_PERL_ONE_LINER->( + # qq[\$OUTPUT_AUTOFLUSH++,do(q($makefile_pl))] + # ) + # . $mmflags; + + # my $flush = OPT_AUTOFLUSH; + # my $cmd = "$perl $flush $makefile_pl $mmflags"; + + my $run_perl = $conf->get_program('perlwrapper'); + my $cmd = [$perl, $run_perl, $makefile_pl, @mmflags]; + + ### set ENV var to tell underlying code this is what we're + ### executing. + my $captured; + my $rv = do { + my $env = ENV_CPANPLUS_IS_EXECUTING; + local $ENV{$env} = $makefile_pl; + scalar run( command => $cmd, + buffer => \$captured, + verbose => $run_verbose, # may be interactive + ); + }; + + unless( $rv ) { + error( loc( "Could not run '%1 %2': %3 -- cannot continue", + $perl, MAKEFILE_PL->(), $captured ) ); + + $dist->status->makefile(0); + $fail++; last RUN; + } + + ### put the output on the stack, don't print it + msg( $captured, 0 ); + } + + ### so, nasty feature in Module::Build, that when a Makefile.PL + ### is a disguised Build.PL, it generates a Build file, not a + ### Makefile. this breaks everything :( see rt bug #19741 + if( not -e MAKEFILE->( $dir ) and -e BUILD_PL->( $dir ) ) { + error(loc( + "We just ran '%1' without errors, but no '%2' is ". + "present. However, there is a '%3' file, so this may ". + "be related to bug #19741 in %4, which describes a ". + "fake '%5' which generates a '%6' file instead of a '%7'. ". + "You could try to work around this issue by setting '%8' ". + "to false and trying again. This will attempt to use the ". + "'%9' instead.", + "$^X ".MAKEFILE_PL->(), MAKEFILE->(), BUILD_PL->(), + 'Module::Build', MAKEFILE_PL->(), 'Build', MAKEFILE->(), + 'prefer_makefile', BUILD_PL->() + )); + + $fail++, last RUN; + } + + ### if we got here, we managed to make a 'makefile' ### + $dist->status->makefile( MAKEFILE->($dir) ); + + ### start resolving prereqs ### + my $prereqs = $self->status->prereqs; + + ### a hashref of prereqs on success, undef on failure ### + $prereqs ||= $dist->_find_prereqs( + verbose => $verbose, + file => $dist->status->makefile + ); + + unless( $prereqs ) { + error( loc( "Unable to scan '%1' for prereqs", + $dist->status->makefile ) ); + + $fail++; last RUN; + } + } + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + ### save where we wrote this stuff -- same as extract dir in normal + ### installer circumstances + $dist->status->distdir( $self->status->extract ); + + return $dist->status->prepared( $fail ? 0 : 1); +} + +=pod + +=head2 $href = $dist->_find_prereqs( file => '/path/to/Makefile', [verbose => BOOL]) + +Parses a C<Makefile> for C<PREREQ_PM> entries and distills from that +any prerequisites mentioned in the C<Makefile> + +Returns a hash with module-version pairs on success and false on +failure. + +=cut + +sub _find_prereqs { + my $dist = shift; + my $self = $dist->parent; + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my ($verbose, $file); + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + file => { required => 1, allow => FILE_READABLE, store => \$file }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + ### see if we got prereqs from MYMETA + my $prereqs = $dist->find_mymeta_requires(); + + ### we found some prereqs, we'll trust MYMETA + ### but we do need to run it through the callback + return $cb->_callbacks->filter_prereqs->( $cb, $prereqs ) if keys %$prereqs; + + my $fh = FileHandle->new(); + unless( $fh->open( $file ) ) { + error( loc( "Cannot open '%1': %2", $file, $! ) ); + return; + } + + my %p; + while( local $_ = <$fh> ) { + my ($found) = m|^[\#]\s+PREREQ_PM\s+=>\s+(.+)|; + + next unless $found; + + while( $found =~ m/(?:\s)([\w\:]+)=>(?:q\[(.*?)\],?|undef)/g ) { + if( defined $p{$1} ) { + my $ver = $cb->_version_to_number(version => $2); + $p{$1} = $ver + if $cb->_vcmp( $ver, $p{$1} ) > 0; + } + else { + $p{$1} = $cb->_version_to_number(version => $2); + } + } + last; + } + + my $href = $cb->_callbacks->filter_prereqs->( $cb, \%p ); + + $self->status->prereqs( $href ); + + ### just to make sure it's not the same reference ### + return { %$href }; +} + +=pod + +=head2 $bool = $dist->create([perl => '/path/to/perl', make => '/path/to/make', makeflags => 'EXTRA=FLAGS', prereq_target => TARGET, skiptest => BOOL, force => BOOL, verbose => BOOL]) + +C<create> creates the files necessary for installation. This means +it will run C<make> and C<make test>. This will also scan for and +attempt to satisfy any prerequisites the module may have. + +If you set C<skiptest> to true, it will skip the C<make test> stage. +If you set C<force> to true, it will go over all the stages of the +C<make> process again, ignoring any previously cached results. It +will also ignore a bad return value from C<make test> and still allow +the operation to return true. + +Returns true on success and false on failure. + +You may then call C<< $dist->install >> on the object to actually +install it. + +=cut + +sub create { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $args; + my( $force, $verbose, $make, $makeflags, $skiptest, $prereq_target, $perl, + @mmflags, $prereq_format, $prereq_build); + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + perl => { default => $^X, store => \$perl }, + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + make => { default => $conf->get_program('make'), + store => \$make }, + makeflags => { default => $conf->get_conf('makeflags'), + store => \$makeflags }, + skiptest => { default => $conf->get_conf('skiptest'), + store => \$skiptest }, + prereq_target => { default => '', store => \$prereq_target }, + ### don't set the default prereq format to 'makemaker' -- wrong! + prereq_format => { #default => $self->status->installer_type, + default => '', + store => \$prereq_format }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + ### maybe we already ran a create on this object? + ### make sure we add to include path again, just in case we came from + ### ->save_state, at which point we need to restore @INC/$PERL5LIB + if( $dist->status->created && !$force ) { + $self->add_to_includepath; + return 1; + } + + ### store the arguments, so ->install can use them in recursive loops ### + $dist->status->_create_args( $args ); + + unless( $dist->status->prepared ) { + error( loc( "You have not successfully prepared a '%2' distribution ". + "yet -- cannot create yet", __PACKAGE__ ) ); + return; + } + + + ### chdir to work directory ### + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + my $fail; my $prereq_fail; my $test_fail; + RUN: { + ### this will set the directory back to the start + ### dir, so we must chdir /again/ + my $ok = $dist->_resolve_prereqs( + format => $prereq_format, + verbose => $verbose, + prereqs => $self->status->prereqs, + target => $prereq_target, + force => $force, + prereq_build => $prereq_build, + ); + + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + unless( $ok ) { + + #### use $dist->flush to reset the cache ### + error( loc( "Unable to satisfy prerequisites for '%1' " . + "-- aborting install", $self->module ) ); + $dist->status->make(0); + $fail++; $prereq_fail++; + last RUN; + } + ### end of prereq resolving ### + + my $captured; + + ### 'make' section ### + if( -d BLIB->($dir) && (-M BLIB->($dir) < -M $dir) && !$force ) { + msg(loc("Already ran '%1' for this module [%2] -- " . + "not running again unless you force", + $make, $self->module ), $verbose ); + } else { + unless(scalar run( command => [$make, $makeflags], + buffer => \$captured, + verbose => $verbose ) + ) { + error( loc( "MAKE failed: %1 %2", $!, $captured ) ); + $dist->status->make(0); + $fail++; last RUN; + } + + ### put the output on the stack, don't print it + msg( $captured, 0 ); + + $dist->status->make(1); + + ### add this directory to your lib ### + $self->add_to_includepath(); + + ### dont bail out here, there's a conditional later on + #last RUN if $skiptest; + } + + ### 'make test' section ### + unless( $skiptest ) { + + ### turn off our PERL5OPT so no modules from CPANPLUS::inc get + ### included in make test -- it should build without + ### also, modules that run in taint mode break if we leave + ### our code ref in perl5opt + ### XXX CPANPLUS::inc functionality is now obsolete. + #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt || ''; + + ### you can turn off running this verbose by changing + ### the config setting below, although it is really not + ### recommended + my $run_verbose = + $verbose || + $conf->get_conf('allow_build_interactivity') || + 0; + + ### XXX need to add makeflags here too? + ### yes, but they should really be split out -- see bug #4143 + if( scalar run( + command => [$make, 'test', $makeflags], + buffer => \$captured, + verbose => $run_verbose, + ) ) { + ### tests might pass because it doesn't have any tests defined + ### log this occasion non-verbosely, so our test reporter can + ### pick up on this + if ( NO_TESTS_DEFINED->( $captured ) ) { + msg( NO_TESTS_DEFINED->( $captured ), 0 ) + } else { + msg( loc( "MAKE TEST passed: %1", $captured ), 0 ); + } + + $dist->status->test(1); + } else { + error( loc( "MAKE TEST failed: %1 %2", $!, $captured ) ); + + ### send out error report here? or do so at a higher level? + ### --higher level --kane. + $dist->status->test(0); + + ### mark specifically *test* failure.. so we dont + ### send success on force... + $test_fail++; + + if( !$force and !$cb->_callbacks->proceed_on_test_failure->( + $self, $captured ) + ) { + $fail++; last RUN; + } + } + } + } #</RUN> + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + ### send out test report? + ### only do so if the failure is this module, not its prereq + if( $conf->get_conf('cpantest') and not $prereq_fail) { + $cb->_send_report( + module => $self, + failed => $test_fail || $fail, + buffer => CPANPLUS::Error->stack_as_string, + verbose => $verbose, + force => $force, + ) or error(loc("Failed to send test report for '%1'", + $self->module ) ); + } + + return $dist->status->created( $fail ? 0 : 1); +} + +=pod + +=head2 $bool = $dist->install([make => '/path/to/make', makemakerflags => 'EXTRA=FLAGS', force => BOOL, verbose => BOOL]) + +C<install> runs the following command: + make install + +Returns true on success, false on failure. + +=cut + +sub install { + + ### just in case you did the create with ANOTHER dist object linked + ### to the same module object + my $dist = shift(); + my $self = $dist->parent; + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + + unless( $dist->status->created ) { + error(loc("You have not successfully created a '%2' distribution yet " . + "-- cannot install yet", __PACKAGE__ )); + return; + } + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $args; + my($force,$verbose,$make,$makeflags); + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + make => { default => $conf->get_program('make'), + store => \$make }, + makeflags => { default => $conf->get_conf('makeflags'), + store => \$makeflags }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + ### value set and false -- means failure ### + if( defined $self->status->installed && + !$self->status->installed && !$force + ) { + error( loc( "Module '%1' has failed to install before this session " . + "-- aborting install", $self->module ) ); + return; + } + + + $dist->status->_install_args( $args ); + + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + my $fail; my $captured; + + ### 'make install' section ### + ### XXX need makeflags here too? + ### yes, but they should really be split out.. see bug #4143 + my $cmd = [$make, 'install', $makeflags]; + my $sudo = $conf->get_program('sudo'); + unshift @$cmd, $sudo if $sudo and $>; + + $cb->flush('lib'); + unless(scalar run( command => $cmd, + verbose => $verbose, + buffer => \$captured, + ) ) { + error( loc( "MAKE INSTALL failed: %1 %2", $!, $captured ) ); + $fail++; + } + + ### put the output on the stack, don't print it + msg( $captured, 0 ); + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + return $dist->status->installed( $fail ? 0 : 1 ); + +} + +=pod + +=head2 $bool = $dist->write_makefile_pl([force => BOOL, verbose => BOOL]) + +This routine can write a C<Makefile.PL> from the information in a +module object. It is used to write a C<Makefile.PL> when the original +author forgot it (!!). + +Returns 1 on success and false on failure. + +The file gets written to the directory the module's been extracted +to. + +=cut + +sub write_makefile_pl { + ### just in case you already did a call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my ($force, $verbose); + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my $file = MAKEFILE_PL->($dir); + if( -s $file && !$force ) { + msg(loc("Already created '%1' - not doing so again without force", + $file ), $verbose ); + return 1; + } + + ### due to a bug with AS perl 5.8.4 built 810 (and maybe others) + ### opening files with content in them already does nasty things; + ### seek to pos 0 and then print, but not truncating the file + ### bug reported to activestate on 19 sep 2004: + ### http://bugs.activestate.com/show_bug.cgi?id=34051 + unlink $file if $force; + + my $fh = new FileHandle; + unless( $fh->open( ">$file" ) ) { + error( loc( "Could not create file '%1': %2", $file, $! ) ); + return; + } + + my $mf = MAKEFILE_PL->(); + my $name = $self->module; + my $version = $self->version; + my $author = $self->author->author; + my $href = $self->status->prereqs; + my $prereqs = join ",\n", map { + (' ' x 25) . "'$_'\t=> '$href->{$_}'" + } keys %$href; + $prereqs ||= ''; # just in case there are none; + + print $fh qq| + ### Auto-generated $mf by CPANPLUS ### + + use ExtUtils::MakeMaker; + + WriteMakefile( + NAME => '$name', + VERSION => '$version', + AUTHOR => '$author', + PREREQ_PM => { +$prereqs + }, + ); + \n|; + + $fh->close; + return 1; +} + +sub dist_dir { + ### just in case you already did a call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $make; my $verbose; + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + make => { default => $conf->get_program('make'), + store => \$make }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + }; + + check( $tmpl, \%hash ) or return; + } + + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + ### chdir to work directory ### + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + my $fail; my $distdir; + TRY: { + $dist->prepare( @_ ) or (++$fail, last TRY); + + + my $captured; + unless(scalar run( command => [$make, 'distdir'], + buffer => \$captured, + verbose => $verbose ) + ) { + error( loc( "MAKE DISTDIR failed: %1 %2", $!, $captured ) ); + ++$fail, last TRY; + } + + ### /path/to/Foo-Bar-1.2/Foo-Bar-1.2 + $distdir = File::Spec->catdir( $dir, $self->package_name . '-' . + $self->package_version ); + + unless( -d $distdir ) { + error(loc("Do not know where '%1' got created", 'distdir')); + ++$fail, last TRY; + } + } + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir to start directory '%1'", $orig ) ); + return; + } + + return if $fail; + return $distdir; +} + + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Sample.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Sample.pm new file mode 100644 index 00000000000..0b0939208ff --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Sample.pm @@ -0,0 +1,16 @@ +package CPANPLUS::Dist::Sample; + +=pod + +=head1 NAME + +CPANPLUS::Dist::Sample -- Sample code to create your own Dist::* plugin + +=head1 Description. + +This document is B<Obsolete>. Please read the documentation and code +in C<CPANPLUS::Dist::Base>. + +=cut + +1; |