This queue is for tickets about the Module-Install CPAN distribution.

Report information
The Basics
Id:
73868
Status:
open
Priority:
Low/Low

People
Owner:
Nobody in particular
Requestors:
florent.angly [...] gmail.com
Cc:
AdminCc:

BugTracker
Severity:
(no value)
Broken in:
1.04
Fixed in:
(no value)



Subject: [PATCH] Module::Install::Bundle improvements
Hi, Please find attached a patched I made from revision 15101 of the development repository at http://svn.ali.as/cpan/trunk/Module-Install/. This patch prevents inc/BUNDLES to be deleted everytime "perl Makefile.PL" is called. This allows authors to more easily maintain their set of bundled distributions: they can add custom distributions not on CPAN, distributions they have patched or specific versions of distributions without having Module::Install::Bundle delete that work. I reworked the output so that it is clearer and more concise. The output contains additional warnings to inform authors: that there is a newer version of a bundled distribution on CPAN, that some bundled distributions are not needed anymore, ... Also, I implemented code that checks that the bundled distributions match the minimum version required by the author. Please consider merging this patch as the changes it implements make it more convenient to bundle distributions using Module::Install::Bundle. Thanks, Florent
Subject: bundle_patch.diff
Index: lib/Module/Install/Bundle.pm =================================================================== --- lib/Module/Install/Bundle.pm (revision 1) +++ lib/Module/Install/Bundle.pm (revision 18) @@ -1,63 +1,88 @@ package Module::Install::Bundle; use strict; +use version; use File::Spec; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { - $VERSION = '1.04'; - @ISA = 'Module::Install::Base'; - $ISCORE = 1; + $VERSION = '1.04'; + @ISA = 'Module::Install::Base'; + $ISCORE = 1; } sub auto_bundle { my $self = shift; - return $self->_install_bundled_dists unless $self->is_admin; # Flatten array of arrays into a single array my @core = map @$_, map @$_, grep ref, $self->requires; - $self->bundle(@core); + $self->admin->post_bundle(); } + sub bundle { - my $self = shift; - + my ($self, @deps) = @_; return $self->_install_bundled_dists unless $self->is_admin; - $self->admin->bundle(@_); + $self->admin->bundle(@deps); } + sub auto_bundle_deps { my $self = shift; - return $self->_install_bundled_dists unless $self->is_admin; # Flatten array of arrays into a single array my @core = map @$_, map @$_, grep ref, $self->requires; + my @deps = (); while (my ($name, $version) = splice(@core, 0, 2)) { next unless $name; - $self->bundle_deps($name, $version); + push @deps, ($name, $version); } + + $self->bundle_deps(@deps); + $self->admin->post_bundle(); } + sub bundle_deps { - my ($self, $pkg, $version) = @_; - + my ($self, @deps) = @_; return $self->_install_bundled_dists unless $self->is_admin; - my $deps = $self->admin->scan_dependencies($pkg); - if (scalar keys %$deps == 0) { - # Probably a user trying to install the package, read the dependencies from META.yml - %$deps = ( map { $$_[0] => undef } (@{$self->requires()}) ); + my %all_deps = (); + while (my ($pkg, $version) = splice(@deps, 0, 2)) { + my $mod_deps = $self->admin->scan_dependencies($pkg); + + if (scalar keys %$mod_deps == 0) { + # Probably a user trying to install the package, read the dependencies from META.yml + %$mod_deps = ( map { $$_[0] => undef } (@{$self->requires()}) ); + } + + while ( my ($key, undef) = each %$mod_deps ) { + my $version1 = $all_deps{$key} || 0; # existing version requirement + my $version2 = ($key eq $pkg) ? $version : 0; # new version requirement + my $version3; # resulting version + if ( $version1 && $version2 ) { + # Two specific versions were requested, take the highest + $version3 = (version->parse($version1)->numify > + version->parse($version2)->numify) ? + $version1 : $version2; + } else { + # Use a specific version + $version3 = $version1 || $version2; + } + $all_deps{$key} = $version3; + } + } - foreach my $key (sort keys %$deps) { - $self->bundle($key, ($key eq $pkg) ? $version : 0); - } + + $self->bundle(%all_deps); } + sub _install_bundled_dists { my $self = shift; @@ -68,7 +93,7 @@ # process all dists bundled in inc/BUNDLES/ my $bundle_dir = $self->_top->{bundle}; - foreach my $sub_dir (glob File::Spec->catfile($bundle_dir,"*")) { + for my $sub_dir (glob File::Spec->catfile($bundle_dir,"*")) { next if -f $sub_dir; @@ -94,6 +119,7 @@ $self->{bundle_processed} = 1; } + 1; __END__ @@ -134,16 +160,33 @@ Allows installation of bundled distributions when CPAN is unavailable Allows installation of bundled distributions when networking is unavailable Allows everything your distribution needs to be packaged in one place + Allows to keep specific versions or patched versions of modules Bundling differs from auto-installation in that when it comes time to install, a bundled distribution will be installed based on the distribution -bundled with your distribution, whereas with auto-installation the distibution +bundled with your distribution, whereas with auto-installation the distribution to be installed will be acquired from CPAN and then installed. +Simply run "perl Makefile.PL" to bundle the distributions that you require in +your Makefile. Bundled distributions are kept in F<inc/BUNDLES/>. After creation +of your initial bundle, subsequent attempts to bundle distributions will not +delete or fetch distributions that you have already bundled, even if there is a +newer version on CPAN. This is so that you can maintain bundles with +distributions that are not on CPAN, with specific versions of distributions, or +distributions that you have patched. Simply remove distributions from +F<inc/BUNDLES/> if you want to get their latest version. + =head1 METHODS =over 4 +=item * bundle($name1, $version1, $name2, $version2, ...) + +Takes a list of key/value pairs specifying a distribution name and version +number. When you, as a module author, do a perl Makefile.PL the distributions +that you specified with C<bundle()> will be acquired from CPAN and placed in +F<inc/BUNDLES/>. + =item * auto_bundle() Takes no arguments, will bundle every distribution specified by a C<requires()>. @@ -151,15 +194,8 @@ the distributions to be bundled will be acquired from CPAN and placed in F<inc/BUNDLES/>. -=item * bundle($name, $version) +=item * bundle_deps($name1, $version1, $name2, $version2, ...) -Takes a list of key/value pairs specifying a distribution name and version -number. When you, as a module author, do a perl Makefile.PL the distributions -that you specified with C<bundle()> will be acquired from CPAN and placed in -F<inc/BUNDLES/>. - -=item * bundle_deps($name, $version) - Same as C<bundle>, except that all dependencies of the bundled modules are also detected and bundled. To use this function, you need to declare the minimum supported perl version first, like this: Index: lib/Module/Install/Admin/Bundle.pm =================================================================== --- lib/Module/Install/Admin/Bundle.pm (revision 1) +++ lib/Module/Install/Admin/Bundle.pm (revision 18) @@ -4,22 +4,28 @@ use Module::Install::Base; use Module::CoreList; use LWP::UserAgent; +use File::Spec::Functions; +use File::Basename; +use version; use vars qw{$VERSION @ISA}; BEGIN { - $VERSION = '1.04'; - @ISA = qw{Module::Install::Base}; + $VERSION = '1.04'; + @ISA = qw{Module::Install::Base}; } sub bundle { - my $self = shift; + my ($self, @modules) = @_; + + # Create output directory if not present my $bundle_dir = $self->_top->{bundle}; + if (not -d $bundle_dir) { + mkdir( $bundle_dir, 0777 ) + or die "*** Could not create directory $bundle_dir: $!\n"; + } - require Cwd; require CPANPLUS::Backend; - my $cwd = Cwd::getcwd(); - # This code is what we _should_ be doing, but CPANPLUS doesn't # let you have multiple Backends in one program. # my $cp = CPANPLUS::Backend->new; @@ -31,45 +37,105 @@ my $conf = $cp->configure_object; my $modtree = $cp->module_tree; - $conf->set_conf( verbose => 1 ); + $conf->set_conf( verbose => 0 ); # not too verbose $conf->set_conf( signature => 0 ); $conf->set_conf( md5 => 0 ); - mkdir( $bundle_dir, 0777 ); + my %modules_hash = @modules; + for my $req_name ( sort keys %modules_hash ) { # sort modules for a nicer output + my $req_version = $modules_hash{$req_name}; - while ( my ( $name, $version ) = splice( @_, 0, 2 ) ) { - my $mod = $cp->module_tree($name); + # Find CPAN distribution + print "Bundling $req_name"; + print " version >= $req_version" if $req_version; + my $mod = $cp->module_tree($req_name); + + # Skip unknown modules if (not $mod) { - warn "Warning: Could not find distribution for module $name on CPAN. Bundle it manually.\n"; + print "\n"; + warn "Warning: Could not find distribution for module $req_name on". + " CPAN. Bundle it manually.\n"; next; } - if ( $mod->package_is_perl_core or $self->{already_bundled}{$mod->package} ) { + # Skip modules from packages we already processed + my $dist_file = $mod->package; + print " (from $dist_file)\n"; + my ($dist_name, $dist_version, $dist_ext) = $cp->_split_package_string( package => $dist_file ); + # Deal with weird versions, see Bio-ASN1-EntrezGene-1.10-withoutworldwriteables.tar.gz + ($dist_version) = split '-', $dist_version; + if ( $self->{already_processed}{$dist_name.'-'.$dist_version} ) { next; } + # Warn if module (not distribution) version requirement was unmet. Modules + # may not have the same version as their distribution, e.g. distribution + # libnet-1.22.tar.gz has module Net::Cmd at version 2.29 + my $mod_version = $mod->version; + if ( version->parse($req_version)->numify > version->parse($mod_version)->numify ) { + warn "Warning: The latest version of $req_name found on CPAN is ". + "$mod_version but version $req_version was required. Bundle it". + " manually.\n"; + $self->{already_processed}{$dist_name.'-'.$dist_version}++; + next; + } + + # Skip Perl core modules + if ( $mod->package_is_perl_core ) { + $self->{already_processed}{$dist_name.'-'.$dist_version}++; + next; + } + + # Skip distributions previously bundled by the author + my ($existing_dir) = glob catfile($bundle_dir, $dist_name).'-*'; + if (defined $existing_dir) { + my ($existing_name, $existing_version, $existing_ext) = + $cp->_split_package_string( package => basename($existing_dir) ); + if ( version->parse($dist_version)->numify > version->parse($existing_version)->numify ) { + warn "Warning: Distribution $dist_name version $existing_version". + " was previously bundled but the latest version is $dist_version.". + " Upgrade it manually if needed.\n"; + } + $self->{already_processed}{$dist_name.'-'.$dist_version}++; + next; + } + + # Download distribution my $where = $mod->fetch( fetchdir => $bundle_dir, ); unless ($where) { warn "Warning: Could not download distribution $bundle_dir. Download it manually.\n"; next; } + + # Extract distribution my $file = Cwd::abs_path($where); - my $extract_result = $mod->extract( files => [ $file ], extractdir => $bundle_dir, ); - unlink $file; unless ($extract_result) { warn "Warning: Could not extract distribution $bundle_dir. Extract it manually.\n"; next; } - - $self->{already_bundled}{ $mod->package }++; + $self->{already_processed}{$dist_name.'-'.$dist_version}++; } - chdir $cwd; } + +sub post_bundle { + my ($self) = @_; + # Report bundled distributions that are not needed anymore + for my $dir (glob catfile($self->_top->{bundle}, '*')) { + next if not -d $dir; + my $string = ( File::Spec->splitdir($dir) )[-1]; + if (not exists $self->{already_processed}->{$string}) { + warn "Warning: The distribution in folder $dir is not needed ". + "anymore. Remove it manually.\n" + } + } +} + + 1; Index: lib/Module/Install/Admin/ScanDeps.pm =================================================================== --- lib/Module/Install/Admin/ScanDeps.pm (revision 1) +++ lib/Module/Install/Admin/ScanDeps.pm (revision 18) @@ -4,8 +4,8 @@ use Module::Install::Base (); use vars qw{$VERSION @ISA}; BEGIN { - $VERSION = '1.04'; - @ISA = qw(Module::Install::Base); + $VERSION = '1.04'; + @ISA = qw(Module::Install::Base); } sub scan_dependencies { @@ -40,7 +40,6 @@ files => \@files, recurse => 0, ); - @files = (); foreach my $key (keys %$deps) { @@ -68,15 +67,19 @@ next if $dep_pkg =~ /^(?:DB|(?:Auto|Dyna|XS)Loader|threads|warnings)\b/i; next if exists $result{$dep_pkg}; - $result{$dep_pkg} = $deps->{$key}{file}; - push @files, $deps->{$key}{file}; + my $file_path = $deps->{$key}{file}; + $result{$dep_pkg} = $file_path; + push @files, $file_path; + } } while (my($k,$v) = each %result) { delete $result{$k} unless defined $v; } + return \%result; } + 1; Index: lib/inc/Module/Install.pm =================================================================== --- lib/inc/Module/Install.pm (revision 1) +++ lib/inc/Module/Install.pm (revision 18) @@ -30,8 +30,8 @@ _check_update($modified_at); } $Module::Install::AUTHOR = 1; - require File::Path; - File::Path::rmtree('inc'); + # Remove inc but keep what the author bundled (inc/BUNDLES) + _clean_inc(); } } else { $Module::Install::AUTHOR = 1; @@ -41,6 +41,16 @@ local $^W; require Module::Install; +sub _clean_inc { + require File::Path; + my $exception = 'inc/BUNDLES'; + for my $element (glob 'inc/*') { + next if $element eq $exception; + File::Path::remove_tree($element) + or die "Could not delete $element\n$!\n"; + } +} + sub _check_update { my $modified_at = shift; Index: lib/inc/Module/Install/DSL.pm =================================================================== --- lib/inc/Module/Install/DSL.pm (revision 1) +++ lib/inc/Module/Install/DSL.pm (revision 18) @@ -26,7 +26,8 @@ if ( -d $author ) { $Module::Install::AUTHOR = 1; require File::Path; - File::Path::rmtree('inc'); + # Remove inc but keep what the author bundled (inc/BUNDLES) + _clean_inc(); } } else { $Module::Install::AUTHOR = 1; @@ -36,6 +37,16 @@ require inc::Module::Install; require Module::Install::DSL; +sub _clean_inc { + require File::Path; + my $exception = 'inc/BUNDLES'; + for my $element (glob 'inc/*') { + next if $element eq $exception; + File::Path::remove_tree($element) + or die "Could not delete $element\n$!\n"; + } +} + # Tie our import to the main one sub import { goto &Module::Install::DSL::import; Index: Makefile.PL =================================================================== --- Makefile.PL (revision 1) +++ Makefile.PL (revision 18) @@ -34,7 +34,8 @@ requires 'ExtUtils::ParseXS' => '2.19'; requires 'Module::Build' => '0.29'; requires 'LWP::UserAgent' => '5.812'; -requires 'Module::Metadata' => '1.000007'; +requires 'Module::Metadata' => '1.000007'; +requires 'version' => '0.77'; test_requires 'Test::Harness' => '3.13'; test_requires 'Test::More' => '0.86';
I just updated the patch in an attempt to make authors aware that Build.PL -based distributions are not supported. I think this is an unfortunate caveat. Exactly what would be needed to add compatibility with Build.PL modules?? Cheers, Florent
Subject: bundle_patch.diff
Index: lib/Module/Install/Bundle.pm =================================================================== --- lib/Module/Install/Bundle.pm (revision 1) +++ lib/Module/Install/Bundle.pm (revision 19) @@ -1,63 +1,88 @@ package Module::Install::Bundle; use strict; +use version; use File::Spec; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { - $VERSION = '1.04'; - @ISA = 'Module::Install::Base'; - $ISCORE = 1; + $VERSION = '1.04'; + @ISA = 'Module::Install::Base'; + $ISCORE = 1; } sub auto_bundle { my $self = shift; - return $self->_install_bundled_dists unless $self->is_admin; # Flatten array of arrays into a single array my @core = map @$_, map @$_, grep ref, $self->requires; - $self->bundle(@core); + $self->admin->post_bundle(); } + sub bundle { - my $self = shift; - + my ($self, @deps) = @_; return $self->_install_bundled_dists unless $self->is_admin; - $self->admin->bundle(@_); + $self->admin->bundle(@deps); } + sub auto_bundle_deps { my $self = shift; - return $self->_install_bundled_dists unless $self->is_admin; # Flatten array of arrays into a single array my @core = map @$_, map @$_, grep ref, $self->requires; + my @deps = (); while (my ($name, $version) = splice(@core, 0, 2)) { next unless $name; - $self->bundle_deps($name, $version); + push @deps, ($name, $version); } + + $self->bundle_deps(@deps); + $self->admin->post_bundle(); } + sub bundle_deps { - my ($self, $pkg, $version) = @_; - + my ($self, @deps) = @_; return $self->_install_bundled_dists unless $self->is_admin; - my $deps = $self->admin->scan_dependencies($pkg); - if (scalar keys %$deps == 0) { - # Probably a user trying to install the package, read the dependencies from META.yml - %$deps = ( map { $$_[0] => undef } (@{$self->requires()}) ); + my %all_deps = (); + while (my ($pkg, $version) = splice(@deps, 0, 2)) { + my $mod_deps = $self->admin->scan_dependencies($pkg); + + if (scalar keys %$mod_deps == 0) { + # Probably a user trying to install the package, read the dependencies from META.yml + %$mod_deps = ( map { $$_[0] => undef } (@{$self->requires()}) ); + } + + while ( my ($key, undef) = each %$mod_deps ) { + my $version1 = $all_deps{$key} || 0; # existing version requirement + my $version2 = ($key eq $pkg) ? $version : 0; # new version requirement + my $version3; # resulting version + if ( $version1 && $version2 ) { + # Two specific versions were requested, take the highest + $version3 = (version->parse($version1)->numify > + version->parse($version2)->numify) ? + $version1 : $version2; + } else { + # Use a specific version + $version3 = $version1 || $version2; + } + $all_deps{$key} = $version3; + } + } - foreach my $key (sort keys %$deps) { - $self->bundle($key, ($key eq $pkg) ? $version : 0); - } + + $self->bundle(%all_deps); } + sub _install_bundled_dists { my $self = shift; @@ -68,7 +93,7 @@ # process all dists bundled in inc/BUNDLES/ my $bundle_dir = $self->_top->{bundle}; - foreach my $sub_dir (glob File::Spec->catfile($bundle_dir,"*")) { + for my $sub_dir (glob File::Spec->catfile($bundle_dir,"*")) { next if -f $sub_dir; @@ -78,14 +103,16 @@ # EU::MM can't handle Build.PL based distributions if (-f File::Spec->catfile($sub_dir, 'Build.PL')) { - warn "Skipped: $sub_dir has Build.PL."; + warn "Warning: Cannot install Build-based distributions. Skipping ". + "$sub_dir...\n"; next; } # EU::MM can't handle distributions without Makefile.PL # (actually this is to cut blib in a wrong directory) if (!-f File::Spec->catfile($sub_dir, 'Makefile.PL')) { - warn "Skipped: $sub_dir has no Makefile.PL."; + warn "Warning: Cannot install distributions lacking a Makefile.PL\n". + "file. Skipping $sub_dir\n"; next; } push @{ $self->makemaker_args->{DIR} }, $sub_dir; @@ -94,6 +121,7 @@ $self->{bundle_processed} = 1; } + 1; __END__ @@ -134,16 +162,33 @@ Allows installation of bundled distributions when CPAN is unavailable Allows installation of bundled distributions when networking is unavailable Allows everything your distribution needs to be packaged in one place + Allows to keep specific versions or patched versions of modules Bundling differs from auto-installation in that when it comes time to install, a bundled distribution will be installed based on the distribution -bundled with your distribution, whereas with auto-installation the distibution +bundled with your distribution, whereas with auto-installation the distribution to be installed will be acquired from CPAN and then installed. +Simply run "perl Makefile.PL" to bundle the distributions that you require in +your Makefile. Bundled distributions are kept in F<inc/BUNDLES/>. After creation +of your initial bundle, subsequent attempts to bundle distributions will not +delete or fetch distributions that you have already bundled, even if there is a +newer version on CPAN. This is so that you can maintain bundles with +distributions that are not on CPAN, with specific versions of distributions, or +distributions that you have patched. Simply remove distributions from +F<inc/BUNDLES/> if you want to get their latest version. + =head1 METHODS =over 4 +=item * bundle($name1, $version1, $name2, $version2, ...) + +Takes a list of key/value pairs specifying a distribution name and version +number. When you, as a module author, do a perl Makefile.PL the distributions +that you specified with C<bundle()> will be acquired from CPAN and placed in +F<inc/BUNDLES/>. + =item * auto_bundle() Takes no arguments, will bundle every distribution specified by a C<requires()>. @@ -151,15 +196,8 @@ the distributions to be bundled will be acquired from CPAN and placed in F<inc/BUNDLES/>. -=item * bundle($name, $version) +=item * bundle_deps($name1, $version1, $name2, $version2, ...) -Takes a list of key/value pairs specifying a distribution name and version -number. When you, as a module author, do a perl Makefile.PL the distributions -that you specified with C<bundle()> will be acquired from CPAN and placed in -F<inc/BUNDLES/>. - -=item * bundle_deps($name, $version) - Same as C<bundle>, except that all dependencies of the bundled modules are also detected and bundled. To use this function, you need to declare the minimum supported perl version first, like this: @@ -173,6 +211,11 @@ =back +=head1 CAVEAT + +Only distributions that contain a Makefile.PL file can be deployed from a bundle. +B<Distributions based on the Build.PL system are not compatible.> + =head1 BUGS Please report any bugs to (patches welcome): Index: lib/Module/Install/Admin/Bundle.pm =================================================================== --- lib/Module/Install/Admin/Bundle.pm (revision 1) +++ lib/Module/Install/Admin/Bundle.pm (revision 19) @@ -4,22 +4,28 @@ use Module::Install::Base; use Module::CoreList; use LWP::UserAgent; +use File::Spec::Functions; +use File::Basename; +use version; use vars qw{$VERSION @ISA}; BEGIN { - $VERSION = '1.04'; - @ISA = qw{Module::Install::Base}; + $VERSION = '1.04'; + @ISA = qw{Module::Install::Base}; } sub bundle { - my $self = shift; + my ($self, @modules) = @_; + + # Create output directory if not present my $bundle_dir = $self->_top->{bundle}; + if (not -d $bundle_dir) { + mkdir( $bundle_dir, 0777 ) + or die "*** Could not create directory $bundle_dir: $!\n"; + } - require Cwd; require CPANPLUS::Backend; - my $cwd = Cwd::getcwd(); - # This code is what we _should_ be doing, but CPANPLUS doesn't # let you have multiple Backends in one program. # my $cp = CPANPLUS::Backend->new; @@ -31,45 +37,128 @@ my $conf = $cp->configure_object; my $modtree = $cp->module_tree; - $conf->set_conf( verbose => 1 ); + $conf->set_conf( verbose => 0 ); # not too verbose $conf->set_conf( signature => 0 ); $conf->set_conf( md5 => 0 ); - mkdir( $bundle_dir, 0777 ); + my %modules_hash = @modules; + for my $req_name ( sort keys %modules_hash ) { # sort modules for a nicer output + my $req_version = $modules_hash{$req_name}; - while ( my ( $name, $version ) = splice( @_, 0, 2 ) ) { - my $mod = $cp->module_tree($name); + # Find CPAN distribution + print "Bundling $req_name"; + print " version >= $req_version" if $req_version; + my $mod = $cp->module_tree($req_name); + + # Skip unknown modules if (not $mod) { - warn "Warning: Could not find distribution for module $name on CPAN. Bundle it manually.\n"; + print "\n"; + warn "Warning: Could not find distribution for module $req_name on". + " CPAN. Bundle it manually.\n"; next; } - if ( $mod->package_is_perl_core or $self->{already_bundled}{$mod->package} ) { + # Skip modules from packages we already processed + my $dist_file = $mod->package; + print " (from $dist_file)\n"; + my ($dist_name, $dist_version, $dist_ext) = + $cp->_split_package_string( package => $dist_file ); + # Deal with weird versions, see Bio-ASN1-EntrezGene-1.10-withoutworldwriteables.tar.gz + ($dist_version) = split '-', $dist_version; + if ( $self->{already_processed}{$dist_name.'-'.$dist_version} ) { next; } + # Warn if module (not distribution) version requirement was unmet. Modules + # may not have the same version as their distribution, e.g. distribution + # libnet-1.22.tar.gz has module Net::Cmd at version 2.29 + my $mod_version = $mod->version; + if ( version->parse($req_version)->numify > + version->parse($mod_version)->numify ) { + warn "Warning: The latest version of $req_name found on CPAN is ". + "$mod_version but version $req_version was required. Bundle it". + " manually.\n"; + $self->{already_processed}{$dist_name.'-'.$dist_version}++; + next; + } + + # Skip Perl core modules + if ( $mod->package_is_perl_core ) { + $self->{already_processed}{$dist_name.'-'.$dist_version}++; + next; + } + + # Skip distributions previously bundled by the author + my ($existing_dir) = glob catfile($bundle_dir, $dist_name).'-*'; + if (defined $existing_dir) { + my ($existing_name, $existing_version, $existing_ext) = + $cp->_split_package_string( package => basename($existing_dir) ); + if ( version->parse($dist_version)->numify > + version->parse($existing_version)->numify ) { + warn "Warning: Distribution $dist_name version $existing_version". + " was previously bundled but the latest version is $dist_version.". + " Upgrade it manually if needed.\n"; + } + $self->{already_processed}{$dist_name.'-'.$dist_version}++; + next; + } + + # Download distribution my $where = $mod->fetch( fetchdir => $bundle_dir, ); unless ($where) { - warn "Warning: Could not download distribution $bundle_dir. Download it manually.\n"; + warn "Warning: Could not download distribution $bundle_dir. ". + "Download it manually.\n"; next; } + + # Extract distribution my $file = Cwd::abs_path($where); - - my $extract_result = $mod->extract( + my $extract_dir = $mod->extract( files => [ $file ], extractdir => $bundle_dir, ); - unlink $file; - unless ($extract_result) { - warn "Warning: Could not extract distribution $bundle_dir. Extract it manually.\n"; + unless ($extract_dir) { + warn "Warning: Could not extract distribution $bundle_dir. Extract". + " it manually.\n"; next; } + $self->{already_processed}{$dist_name.'-'.$dist_version}++; - $self->{already_bundled}{ $mod->package }++; + # EU::MM can't handle Build.PL based distributions + if (-f File::Spec->catfile($extract_dir, 'Build.PL')) { + warn "Warning: Bundled $dist_name-$dist_version, but will not be ". + "able to deploy this distribution later because Build-based ". + "distributions are not supported.\n"; + next; + } + + # EU::MM can't handle distributions without Makefile.PL + # (actually this is to cut blib in a wrong directory) + if (!-f File::Spec->catfile($extract_dir, 'Makefile.PL')) { + warn "Warning: Bundled $dist_name-$dist_version, but will not be ". + "able to deploy this distribution later because distributions ". + "without Makefile.PL are not supported.\n"; + next; + } + } - chdir $cwd; } + +sub post_bundle { + my ($self) = @_; + # Report bundled distributions that are not needed anymore + for my $dir (glob catfile($self->_top->{bundle}, '*')) { + next if not -d $dir; + my $string = ( File::Spec->splitdir($dir) )[-1]; + if (not exists $self->{already_processed}->{$string}) { + warn "Warning: The distribution in folder $dir is not needed ". + "anymore. Remove it manually.\n" + } + } +} + + 1; Index: lib/Module/Install/Admin/ScanDeps.pm =================================================================== --- lib/Module/Install/Admin/ScanDeps.pm (revision 1) +++ lib/Module/Install/Admin/ScanDeps.pm (revision 19) @@ -4,8 +4,8 @@ use Module::Install::Base (); use vars qw{$VERSION @ISA}; BEGIN { - $VERSION = '1.04'; - @ISA = qw(Module::Install::Base); + $VERSION = '1.04'; + @ISA = qw(Module::Install::Base); } sub scan_dependencies { @@ -40,7 +40,6 @@ files => \@files, recurse => 0, ); - @files = (); foreach my $key (keys %$deps) { @@ -68,15 +67,19 @@ next if $dep_pkg =~ /^(?:DB|(?:Auto|Dyna|XS)Loader|threads|warnings)\b/i; next if exists $result{$dep_pkg}; - $result{$dep_pkg} = $deps->{$key}{file}; - push @files, $deps->{$key}{file}; + my $file_path = $deps->{$key}{file}; + $result{$dep_pkg} = $file_path; + push @files, $file_path; + } } while (my($k,$v) = each %result) { delete $result{$k} unless defined $v; } + return \%result; } + 1; Index: lib/inc/Module/Install.pm =================================================================== --- lib/inc/Module/Install.pm (revision 1) +++ lib/inc/Module/Install.pm (revision 19) @@ -30,8 +30,8 @@ _check_update($modified_at); } $Module::Install::AUTHOR = 1; - require File::Path; - File::Path::rmtree('inc'); + # Remove inc but keep what the author bundled (inc/BUNDLES) + _clean_inc(); } } else { $Module::Install::AUTHOR = 1; @@ -41,6 +41,16 @@ local $^W; require Module::Install; +sub _clean_inc { + require File::Path; + my $exception = 'inc/BUNDLES'; + for my $element (glob 'inc/*') { + next if $element eq $exception; + File::Path::remove_tree($element) + or die "Could not delete $element\n$!\n"; + } +} + sub _check_update { my $modified_at = shift; Index: lib/inc/Module/Install/DSL.pm =================================================================== --- lib/inc/Module/Install/DSL.pm (revision 1) +++ lib/inc/Module/Install/DSL.pm (revision 19) @@ -26,7 +26,8 @@ if ( -d $author ) { $Module::Install::AUTHOR = 1; require File::Path; - File::Path::rmtree('inc'); + # Remove inc but keep what the author bundled (inc/BUNDLES) + _clean_inc(); } } else { $Module::Install::AUTHOR = 1; @@ -36,6 +37,16 @@ require inc::Module::Install; require Module::Install::DSL; +sub _clean_inc { + require File::Path; + my $exception = 'inc/BUNDLES'; + for my $element (glob 'inc/*') { + next if $element eq $exception; + File::Path::remove_tree($element) + or die "Could not delete $element\n$!\n"; + } +} + # Tie our import to the main one sub import { goto &Module::Install::DSL::import; Index: Makefile.PL =================================================================== --- Makefile.PL (revision 1) +++ Makefile.PL (revision 19) @@ -34,7 +34,8 @@ requires 'ExtUtils::ParseXS' => '2.19'; requires 'Module::Build' => '0.29'; requires 'LWP::UserAgent' => '5.812'; -requires 'Module::Metadata' => '1.000007'; +requires 'Module::Metadata' => '1.000007'; +requires 'version' => '0.77'; test_requires 'Test::Harness' => '3.13'; test_requires 'Test::More' => '0.86';


This service runs on Request Tracker, is sponsored by The Perl Foundation, and maintained by Best Practical Solutions.

Please report any issues with rt.cpan.org to rt-cpan-admin@bestpractical.com.