diff options
author | David Golden <dagolden@cpan.org> | 2011-01-24 23:06:38 -0500 |
---|---|---|
committer | David Golden <dagolden@cpan.org> | 2011-01-24 23:41:45 -0500 |
commit | 7cf8bfc08bba55cf85781cc2cdb8d5ace99245ec (patch) | |
tree | 708c8bbcc6060f3955178daa2f60ab83bac7f336 /cpan/Module-Build/lib/Module/Build/Base.pm | |
parent | 313ce23f886218e9cbc159ce0f8dfdff84e48128 (diff) | |
download | perl-7cf8bfc08bba55cf85781cc2cdb8d5ace99245ec.tar.gz |
Update Module::Build to CPAN version 0.3622
[DELTA]
0.3622 - Mon Jan 24 21:06:50 EST 2011
- No changes from 0.36_21
0.36_21 - Fri Jan 21 11:01:28 EST 2011
- Changed YAML::Tiny references to the new CPAN::Meta::YAML module
instead, which is the YAML-variant that is going into the Perl core
0.36_20 - Fri Dec 10 15:36:03 EST 2010
*** DEPRECATIONS ***
- Module::Build::Version has been deprecated. Module::Build now depends
directly upon version.pm. A pure-perl version has been bundled in inc/
solely for bootstrapping in case configure_requires is not supported.
M::B::Version remains as a wrapper around version.pm.
- Module::Build::ModuleInfo has been deprecated. Module::Build now
depends directly upon Module::Metadata (which is an extraction of
M::B::ModuleInfo intended for general reuse). A pure-perl version has
been bundled in inc/ solely for bootstrapping in case
configure_requires is not supported. M::B::ModuleInfo remains as a
wrapper around Module::Metadata.
- Module::Build::YAML has been deprecated. Module::Build now depends
directly upon YAML::Tiny. M::B::YAML remains as a subclass wrapper.
The YAML_support feature has been removed, as YAML is now an ordinary
dependency.
0.36_19 - Tue Dec 7 13:43:42 EST 2010
Bug fixes:
- Perl::OSType is declared as a 'configure_requires' dependency, but is
also bundled in inc (and loaded if needed) [David Golden]
0.36_18 - Mon Dec 6 16:46:49 EST 2010
Changes:
- Added dependency on Perl::OSType to refactor and centralize
management of OS type mapping [David Golden]
- When parsing a version number out of a file, any trailing alphabetical
characters will be dropped to avoid fatal errors when comparing version
numbers. These would have been dropped (with a warning) anyway during
an ordinary numeric comparison. (RT#56071) [David Golden]
Bug fixes:
- A Perl interpreter mismatch between running Build.PL and running Build
is now a fatal error, not a warning (RT#55183) [David Golden]
- Bundled Module::Build::Version updated to bring into sync with CPAN
version.pm 0.86 [David Golden]
- No longer uses fake user 'foo' in t/tilde (RT#61793) [David Golden]
- Won't fail tests if an ancient Tie::IxHash is installed
[Christopher J. Madsen]
- Correctly report missing metafile field names [David Golden]
- Suppress uninitialized value errors during Pod creation
on ActiveState Perl [David Golden]
- Return to starting directory after install action; this is
an attempt to fix an install.t heisenbug (RT#63003) [David Golden]
- A broken version.pm load won't cause Module::Build::Version to
die trying to install itself as a mock version (RT#59499)
[Eric Wilhelm and David Golden]
- PERL_DL_NONLAZY is now always set when tests are run
(RT#56055) [Dmitry Karasik]
- 'fakeinstall' will use .modulebuildrc actions for 'install' if
no specific 'fakeinstall' options are provided (RT#57279)
[David Golden]
- Add install*script to search path for installdeps client
and search site, then vendor, then core paths
- Skip noexec tmpdir check on Windows (RT#55667) [Jan Dubois]
- Arguments with key value pairs may now have keys with "-" in them
(RT#53050) [David Golden]
- Add quotemeta to t/tilde.t test to fix Cygwin fails
[Chris Williams and David Golden]
- Build script now checks that M::B is at least the same version
of M::B as provided in 'configure_requires' in META
(RT#54954) [David Golden]
0.36_17 - Wed Oct 27 18:08:36 EDT 2010
Enhancements:
- Added 'distinstall' action to run 'Build install' inside the
generated distribution directory [Jeff Thalhammer]
0.36_16 - Thu Aug 26 12:44:07 EDT 2010
Bug fixes:
- Better error message in case package declaration is not found
when searching for version. [Alexandr Ciornii]
- Skips 'release_status' tests on perl < 5.8.1 due to buggy
treatment of dotted-decimal version numbers [David Golden]
0.36_15 - Wed Aug 25 10:41:28 EDT 2010
Bug fixes:
- Added a mock Software::License to prevent t/properties/license.t
from failing.
0.36_14 - Sun Aug 22 22:56:50 EDT 2010
Enhancements:
- Adds 'release_status' and 'dist_suffix' properties in preparation
for adding CPAN Meta Spec 2 support. 'dist_suffix' will be set
to 'TRIAL' automatically when necessary. [David Golden]
- Makes 'license' more liberal. You can now specify either a license
key from the approved list (c.f. Module::Build::API) or just a
Software::License subclass name (e.g. 'Perl_5'). This should
provide better support for custom or proprietary licenses.
[David Golden]
0.36_13 - Wed Jul 28 22:40:25 EDT 2010
Bug-fixes:
- Bundled Module::Build::Version updated to bring into sync with CPAN
version.pm 0.82 [David Golden]
0.36_12 - Tue Jul 27 00:08:51 EDT 2010
Enhancements:
- Module::Build::Compat will now convert dotted-decimal prereqs into
decimal rather than dying (and will warn about this). [Apocalypse]
Bug fixes:
- Caches case-sensitivity checks to boost performance, fixes
RT#55162 and RT#56513 [Reini Urban]
- Won't try to use ActivePerl doc generation tools without confirming
that they are indeed installed. [David Golden]
- Sets temporary $ENV{HOME} in testing to an absolute path, which fixes
some issues when tested as part of the Perl core [Nicholas Clark]
- Module::Build::ModuleInfo now warns instead of dying when a module
has an invalid version. ->version now just returns undef
(RT#59593) [David Golden]
Changes:
- When authors do not specify Module::Build in configure_requires and
Module::Build is automatically added, a warning will be issued
showing the added prerequisite [David Golden]
- Moved automatic configure_requires generation into get_metadata()
and added an 'auto' argument to toggle it (on for META and off
for MYMETA) [David Golden]
0.36_11 - Thu May 27 09:41:23 EDT 2010
Bug fixes:
- Handle META/MYMETA reading and writing within Module::Build to ensure
utf8 mode on filehandles. Now passes/gets only strings to YAML::Tiny
or Module::Build::YAML
0.36_10 - Wed May 19 18:36:06 EDT 2010
Bug fixes:
- Fix failing t/manifypods.t on Windows from 0.36_09 changes [Klaus
Eichner]
0.36_09 - Tue May 11 09:19:12 EDT 2010
Bug fixes:
- Improve HTML documentation generation on ActivePerl (RT#53478)
[Scott Renner and Klaus Eichner]
0.36_08 - Mon Apr 26 08:00:15 EDT 2010
Enhancements:
- Give a list of valid licenses when given one we don't recognize
(RT#55951) [Yanick Champoux]
- Added 'Build manifest_skip' action to generate a default MANIFEST.SKIP
[David Golden]
Changes:
- When temporarily generating a MANIFEST.SKIP when none exists, it will
be removed on exit instead of hanging around until 'Build clean'. This
is less surprising/confusing and the 'Build manifest_skip' action
is now available instead to bootstrap the file [David Golden]
Bug fixes:
- Fixed runtime error on cygwin when searching for an executable command
during installdeps testing [David Golden]
Diffstat (limited to 'cpan/Module-Build/lib/Module/Build/Base.pm')
-rw-r--r-- | cpan/Module-Build/lib/Module/Build/Base.pm | 633 |
1 files changed, 472 insertions, 161 deletions
diff --git a/cpan/Module-Build/lib/Module/Build/Base.pm b/cpan/Module-Build/lib/Module/Build/Base.pm index 45205e8abf..d42c8af4da 100644 --- a/cpan/Module-Build/lib/Module/Build/Base.pm +++ b/cpan/Module-Build/lib/Module/Build/Base.pm @@ -4,7 +4,7 @@ package Module::Build::Base; use strict; use vars qw($VERSION); -$VERSION = '0.3607'; +$VERSION = '0.3622'; $VERSION = eval $VERSION; BEGIN { require 5.00503 } @@ -62,6 +62,7 @@ EOF $self->dist_name; $self->dist_version; + $self->release_status; $self->_guess_module_name unless $self->module_name; $self->_find_nested_builds; @@ -95,8 +96,12 @@ sub resume { unless ($self->_perl_is_same($self->{properties}{perl})) { my $perl = $self->find_perl_interpreter; - $self->log_warn(" * WARNING: Configuration was initially created with '$self->{properties}{perl}',\n". - " but we are now using '$perl'.\n"); + die(<<"DIEFATAL"); +* FATAL ERROR: Perl interpreter mismatch. Configuration was initially + created with '$self->{properties}{perl}' + but we are now using '$perl'. You must + run 'Build realclean' or 'make realclean' and re-configure. +DIEFATAL } $self->cull_args(@ARGV); @@ -105,7 +110,7 @@ sub resume { my $mb_version = $Module::Build::VERSION; if ( $mb_version ne $self->{properties}{mb_version} ) { $self->log_warn(<<"MISMATCH"); -* WARNING: Configuration was initially created with Module::Build +* WARNING: Configuration was initially created with Module::Build version '$self->{properties}{mb_version}' but we are now using version '$mb_version'. If errors occur, you must re-run the Build.PL or Makefile.PL script. MISMATCH @@ -201,15 +206,15 @@ sub _construct { sub log_info { my $self = shift; - print @_ unless(ref($self) and $self->quiet); + print @_ if ref($self) && ( $self->verbose || ! $self->quiet ); } sub log_verbose { my $self = shift; - $self->log_info(@_) if(ref($self) and $self->verbose); + print @_ if ref($self) && $self->verbose; } sub log_debug { my $self = shift; - print @_ if ref $self && $self->debug; + print @_ if ref($self) && $self->debug; } sub log_warn { @@ -926,8 +931,7 @@ __PACKAGE__->add_property( ); { - my $Is_ActivePerl = eval {require ActivePerl::DocTools}; - __PACKAGE__->add_property(html_css => $Is_ActivePerl ? 'Active.css' : ''); + __PACKAGE__->add_property(html_css => ''); } { @@ -964,6 +968,7 @@ __PACKAGE__->add_property($_) for qw( dist_abstract dist_author dist_name + dist_suffix dist_version dist_version_from extra_compiler_flags @@ -984,6 +989,7 @@ __PACKAGE__->add_property($_) for qw( program_name quiet recursive_test_files + release_status script_files scripts share_dir @@ -1124,6 +1130,41 @@ sub dist_name { return $p->{dist_name}; } +sub release_status { + my ($self) = @_; + my $p = $self->{properties}; + + if ( ! defined $p->{release_status} ) { + $p->{release_status} = $self->_is_dev_version ? 'testing' : 'stable'; + } + + unless ( $p->{release_status} =~ qr/\A(?:stable|testing|unstable)\z/ ) { + die "Illegal value '$p->{release_status}' for release_status\n"; + } + + if ( $p->{release_status} eq 'stable' && $self->_is_dev_version ) { + my $version = $self->dist_version; + die "Illegal value '$p->{release_status}' with version '$version'\n"; + } + return $p->{release_status}; +} + +sub dist_suffix { + my ($self) = @_; + my $p = $self->{properties}; + return $p->{dist_suffix} if defined $p->{dist_suffix}; + + if ( $self->release_status eq 'stable' ) { + $p->{dist_suffix} = ""; + } + else { + # non-stable release but non-dev version number needs '-TRIAL' appended + $p->{dist_suffix} = $self->_is_dev_version ? "" : "TRIAL" ; + } + + return $p->{dist_suffix}; +} + sub dist_version_from { my ($self) = @_; my $p = $self->{properties}; @@ -1144,7 +1185,11 @@ sub dist_version { my $version_from = File::Spec->catfile( split( qr{/}, $dist_version_from ) ); my $pm_info = Module::Build::ModuleInfo->new_from_file( $version_from ) or die "Can't find file $version_from to determine version"; + #$p->{dist_version} is undef here $p->{dist_version} = $self->normalize_version( $pm_info->version() ); + unless (defined $p->{dist_version}) { + die "Can't determine distribution version from $version_from"; + } } die ("Can't determine distribution version, must supply either 'dist_version',\n". @@ -1154,6 +1199,16 @@ sub dist_version { return $p->{dist_version}; } +sub _is_dev_version { + my ($self) = @_; + my $dist_version = $self->dist_version; + my $version_obj = eval { Module::Build::Version->new( $dist_version ) }; + # assume it's normal if the version string is fatal -- in this case + # the author might be doing something weird so should play along and + # assume they'll specify all necessary behavior + return $@ ? 0 : $version_obj->is_alpha; +} + sub dist_author { shift->_pod_parse('author') } sub dist_abstract { shift->_pod_parse('abstract') } @@ -1182,6 +1237,26 @@ sub find_module_by_name { # Method provided for backwards compatibility return Module::Build::ModuleInfo->find_module_by_name(@_[1,2]); } +{ + # $unlink_list_for_pid{$$} = [ ... ] + my %unlink_list_for_pid; + + sub _unlink_on_exit { + my $self = shift; + for my $f ( @_ ) { + push @{$unlink_list_for_pid{$$}}, $f if -f $f; + } + return 1; + } + + END { + for my $f ( map glob($_), @{ $unlink_list_for_pid{$$} || [] } ) { + next unless -e $f; + File::Path::rmtree($f, 0, 0); + } + } +} + sub add_to_cleanup { my $self = shift; my %files = map {$self->localize_file_path($_), 1} @_; @@ -1389,8 +1464,8 @@ sub _feature_deps_msg { return $log_text; } -# Automatically detect and add prerequisites based on configuration -sub auto_require { +# Automatically detect configure_requires prereqs +sub auto_config_requires { my ($self) = @_; my $p = $self->{properties}; @@ -1401,6 +1476,10 @@ sub auto_require { && ! exists $p->{configure_requires}{'Module::Build'} ) { (my $ver = $VERSION) =~ s/^(\d+\.\d\d).*$/$1/; # last major release only + $self->log_warn(<<EOM); +Module::Build was not found in configure_requires! Adding it now +automatically as: configure_requires => { 'Module::Build' => $ver } +EOM $self->_add_prereq('configure_requires', 'Module::Build', $ver); } @@ -1415,6 +1494,14 @@ sub auto_require { } } + return; +} + +# Automatically detect and add prerequisites based on configuration +sub auto_require { + my ($self) = @_; + my $p = $self->{properties}; + # If needs_compiler is not explictly set, automatically set it # If set, we need ExtUtils::CBuilder (and a compiler) my $xs_files = $self->find_xs_files; @@ -1555,6 +1642,24 @@ sub _parse_conditions { } } +sub try_require { + my ($self, $modname, $spec) = @_; + my $status = $self->check_installed_status($modname, defined($spec) ? $spec : 0); + return unless $status->{ok}; + my $path = $modname; + $path =~ s{::}{/}g; + $path .= ".pm"; + if ( defined $INC{$path} ) { + return 1; + } + elsif ( exists $INC{$path} ) { # failed before, don't try again + return; + } + else { + return eval "require $modname"; + } +} + sub check_installed_status { my ($self, $modname, $spec) = @_; my %status = (need => $spec); @@ -1572,7 +1677,7 @@ sub check_installed_status { return \%status; } - $status{have} = $pm_info->version(); + $status{have} = eval { $pm_info->version() }; if ($spec and !defined($status{have})) { @status{ qw(have message) } = (undef, "Couldn't find a \$VERSION in prerequisite $modname"); return \%status; @@ -1684,11 +1789,15 @@ sub print_build_script { my $closedata=""; + my $config_requires; + if ( -f $self->metafile ) { + my $meta = eval { $self->read_metafile( $self->metafile ) }; + $config_requires = $meta && $meta->{configure_requires}{'Module::Build'}; + } + $config_requires ||= 0; + my %q = map {$_, $self->$_()} qw(config_dir base_dir); - my $case_tolerant = 0+(File::Spec->can('case_tolerant') - && File::Spec->case_tolerant); - $q{base_dir} = uc $q{base_dir} if $case_tolerant; $q{base_dir} = Win32::GetShortPathName($q{base_dir}) if $self->is_windowsish; $q{magic_numfile} = $self->config_file('magicnum'); @@ -1744,6 +1853,7 @@ $quoted_INC close(*DATA) unless eof(*DATA); # ensure no open handles to this script use $build_package; +Module::Build->VERSION(q{$config_requires}); # Some platforms have problems setting \$^X in shebang contexts, fix it up here \$^X = Module::Build->find_perl_interpreter; @@ -1783,8 +1893,8 @@ sub create_mymeta { # if we read META OK, just update it if ( defined $mymeta ) { my $prereqs = $self->_normalize_prereqs; - for my $t ( keys %$prereqs ) { - $mymeta->{$t} = $prereqs->{$t}; + for my $t ( 'configure_requires', @{$self->prereq_action_types} ) { + $mymeta->{$t} = $prereqs->{$t} if $prereqs->{$t}; } } # but generate from scratch, ignoring errors if META doesn't exist @@ -1797,7 +1907,8 @@ sub create_mymeta { # Note which M::B created it $mymeta->{generated_by} = "Module::Build version $Module::Build::VERSION"; - $self->write_metafile( $mymetafile, $mymeta ); + $self->write_metafile( $mymetafile, $mymeta ) or + $self->log_warn("Could not create MYMETA.yml\n"); return 1; } @@ -1958,7 +2069,6 @@ sub _translate_option { create_readme extra_compiler_flags extra_linker_flags - html_css install_base install_path meta_add @@ -2068,7 +2178,7 @@ sub read_args { $args{$_} ||= []; $args{$_} = [ $args{$_} ] unless ref $args{$_}; foreach my $arg ( @{$args{$_}} ) { - $arg =~ /(\w+)=(.*)/ + $arg =~ /($opt_re)=(.*)/ or die "Malformed '$_' argument: '$arg' should be something like 'foo=bar'"; $hash{$1} = $2; } @@ -2208,6 +2318,11 @@ sub read_modulebuildrc { my ($global_opts) = $self->read_args( $self->split_like_shell( $options{'*'} || '' ) ); + + # let fakeinstall act like install if not provided + if ( $action eq 'fakeinstall' && ! exists $options{fakeinstall} ) { + $action = 'install'; + } my ($action_opts) = $self->read_args( $self->split_like_shell( $options{$action} || '' ) ); @@ -2552,6 +2667,8 @@ sub do_tests { my $tests = $self->find_test_files; + local $ENV{PERL_DL_NONLAZY} = 1; + if(@$tests) { my $args = $self->tap_harness_args; if($self->use_tap_harness or ($args and %$args)) { @@ -2667,7 +2784,7 @@ sub ACTION_testcover { # testcover was run. If so, start over. if (-e 'cover_db') { my $pm_files = $self->rscan_dir - (File::Spec->catdir($self->blib, 'lib'), file_qr('\.pm$') ); + (File::Spec->catdir($self->blib, 'lib'), $self->file_qr('\.pm$') ); my $cover_files = $self->rscan_dir('cover_db', sub {-f $_ and not /\.html$/}); $self->do_system(qw(cover -delete)) @@ -2732,11 +2849,11 @@ sub process_support_files { if (ref($p->{c_source}) eq "ARRAY") { push @{$p->{include_dirs}}, @{$p->{c_source}}; for my $path (@{$p->{c_source}}) { - push @$files, @{ $self->rscan_dir($path, file_qr('\.c(c|p|pp|xx|\+\+)?$')) }; + push @$files, @{ $self->rscan_dir($path, $self->file_qr('\.c(c|p|pp|xx|\+\+)?$')) }; } } else { push @{$p->{include_dirs}}, $p->{c_source}; - $files = $self->rscan_dir($p->{c_source}, file_qr('\.c(c|p|pp|xx|\+\+)?$')); + $files = $self->rscan_dir($p->{c_source}, $self->file_qr('\.c(c|p|pp|xx|\+\+)?$')); } foreach my $file (@$files) { @@ -2860,8 +2977,10 @@ sub find_PL_files { } return unless -d 'lib'; - return { map {$_, [/^(.*)\.PL$/i ]} @{ $self->rscan_dir('lib', - file_qr('\.PL$')) } }; + return { + map {$_, [/^(.*)\.PL$/i ]} + @{ $self->rscan_dir('lib', $self->file_qr('\.PL$')) } + }; } sub find_pm_files { shift->_find_file_by_type('pm', 'lib') } @@ -2914,7 +3033,7 @@ sub _find_file_by_type { return { map {$_, $_} map $self->localize_file_path($_), grep !/\.\#/, - @{ $self->rscan_dir($dir, file_qr("\\.$type\$")) } }; + @{ $self->rscan_dir($dir, $self->file_qr("\\.$type\$")) } }; } sub localize_file_path { @@ -2987,7 +3106,7 @@ sub ACTION_testpod { my @files = sort keys %{$self->_find_pods($self->libdoc_dirs)}, keys %{$self->_find_pods ($self->bindoc_dirs, - exclude => [ file_qr('\.bat$') ])} + exclude => [ $self->file_qr('\.bat$') ])} or die "Couldn't find any POD files to test\n"; { package # hide from PAUSE @@ -3041,6 +3160,24 @@ sub _is_default_installable { ) ? 1 : 0; } +sub _is_ActivePerl { +# return 0; + my $self = shift; + unless (exists($self->{_is_ActivePerl})) { + $self->{_is_ActivePerl} = (eval { require ActivePerl::DocTools; } || 0); + } + return $self->{_is_ActivePerl}; +} + +sub _is_ActivePPM { +# return 0; + my $self = shift; + unless (exists($self->{_is_ActivePPM})) { + $self->{_is_ActivePPM} = (eval { require ActivePerl::PPM; } || 0); + } + return $self->{_is_ActivePPM}; +} + sub ACTION_manpages { my $self = shift; @@ -3049,27 +3186,21 @@ sub ACTION_manpages { $self->depends_on('code'); foreach my $type ( qw(bin lib) ) { + next unless ( $self->invoked_action eq 'manpages' || $self->_is_default_installable("${type}doc")); my $files = $self->_find_pods( $self->{properties}{"${type}doc_dirs"}, - exclude => [ file_qr('\.bat$') ] ); + exclude => [ $self->file_qr('\.bat$') ] ); next unless %$files; my $sub = $self->can("manify_${type}_pods"); - next unless defined( $sub ); - - if ( $self->invoked_action eq 'manpages' ) { - $self->$sub(); - } elsif ( $self->_is_default_installable("${type}doc") ) { - $self->$sub(); - } + $self->$sub() if defined( $sub ); } - } sub manify_bin_pods { my $self = shift; my $files = $self->_find_pods( $self->{properties}{bindoc_dirs}, - exclude => [ file_qr('\.bat$') ] ); + exclude => [ $self->file_qr('\.bat$') ] ); return unless keys %$files; my $mandir = File::Spec->catdir( $self->blib, 'bindoc' ); @@ -3153,21 +3284,11 @@ sub ACTION_html { $self->depends_on('code'); foreach my $type ( qw(bin lib) ) { - my $files = $self->_find_pods( $self->{properties}{"${type}doc_dirs"}, - exclude => - [ file_qr('\.(?:bat|com|html)$') ] ); - next unless %$files; - - if ( $self->invoked_action eq 'html' ) { - $self->htmlify_pods( $type ); - } elsif ( $self->_is_default_installable("${type}html") ) { - $self->htmlify_pods( $type ); - } + next unless ( $self->invoked_action eq 'html' || $self->_is_default_installable("${type}html")); + $self->htmlify_pods( $type ); } - } - # 1) If it's an ActiveState perl install, we need to run # ActivePerl::DocTools->UpdateTOC; # 2) Links to other modules are not being generated @@ -3176,13 +3297,10 @@ sub htmlify_pods { my $type = shift; my $htmldir = shift || File::Spec->catdir($self->blib, "${type}html"); - require Module::Build::PodParser; - require Pod::Html; - $self->add_to_cleanup('pod2htm*'); my $pods = $self->_find_pods( $self->{properties}{"${type}doc_dirs"}, - exclude => [ file_qr('\.(?:bat|com|html)$') ] ); + exclude => [ $self->file_qr('\.(?:bat|com|html)$') ] ); return unless %$pods; # nothing to do unless ( -d $htmldir ) { @@ -3192,21 +3310,51 @@ sub htmlify_pods { my @rootdirs = ($type eq 'bin') ? qw(bin) : $self->installdirs eq 'core' ? qw(lib) : qw(site lib); + my $podroot = $self->original_prefix('core'); + + my $htmlroot = $self->install_sets('core')->{libhtml}; + my @podpath = (map { File::Spec->abs2rel($_ ,$podroot) } grep { -d } + ( $self->install_sets('core', 'lib'), # lib + $self->install_sets('core', 'bin'), # bin + $self->install_sets('site', 'lib'), # site/lib + ),File::Spec->rel2abs($self->blib) + ); - my $podpath = join ':', - map $_->[1], - grep -e $_->[0], - map [File::Spec->catdir($self->blib, $_), $_], - qw( script lib ); + my $podpath = join(":", map { tr,:\\,|/,; $_ } @podpath); + my $blibdir = join('/', File::Spec->splitdir( + (File::Spec->splitpath(File::Spec->rel2abs($htmldir),1))[1]),'' + ); + + my ($with_ActiveState, $htmltool); + + if ( $with_ActiveState = $self->_is_ActivePerl + && eval { require ActivePerl::DocTools::Pod; 1 } + ) { + my $tool_v = ActiveState::DocTools::Pod->VERSION; + $htmltool = "ActiveState::DocTools::Pod"; + $htmltool .= " $tool_v" if $tool_v && length $tool_v; + } + else { + require Module::Build::PodParser; + require Pod::Html; + $htmltool = "Pod::Html " . Pod::Html->VERSION; + } + $self->log_verbose("Converting Pod to HTML with $htmltool\n"); + + my $errors = 0; + + POD: foreach my $pod ( keys %$pods ) { my ($name, $path) = File::Basename::fileparse($pods->{$pod}, - file_qr('\.(?:pm|plx?|pod)$')); + $self->file_qr('\.(?:pm|plx?|pod)$') + ); my @dirs = File::Spec->splitdir( File::Spec->canonpath( $path ) ); pop( @dirs ) if scalar(@dirs) && $dirs[-1] eq File::Spec->curdir; - my $fulldir = File::Spec->catfile($htmldir, @rootdirs, @dirs); + my $fulldir = File::Spec->catdir($htmldir, @rootdirs, @dirs); + my $tmpfile = File::Spec->catfile($fulldir, "${name}.tmp"); my $outfile = File::Spec->catfile($fulldir, "${name}.html"); my $infile = File::Spec->abs2rel($pod); @@ -3217,38 +3365,78 @@ sub htmlify_pods { or die "Couldn't mkdir $fulldir: $!"; } - my $path2root = join( '/', ('..') x (@rootdirs+@dirs) ); - my $htmlroot = join( '/', - ($path2root, - $self->installdirs eq 'core' ? () : qw(site) ) ); - - my $fh = IO::File->new($infile) or die "Can't read $infile: $!"; - my $abstract = Module::Build::PodParser->new(fh => $fh)->get_abstract(); - - my $title = join( '::', (@dirs, $name) ); - $title .= " - $abstract" if $abstract; - - my @opts = ( - '--flush', - "--title=$title", - "--podpath=$podpath", - "--infile=$infile", - "--outfile=$outfile", - '--podroot=' . $self->blib, - "--htmlroot=$htmlroot", - ); - - if ( eval{Pod::Html->VERSION(1.03)} ) { - push( @opts, ('--header', '--backlink=Back to Top') ); - push( @opts, "--css=$path2root/" . $self->html_css) if $self->html_css; + $self->log_verbose("HTMLifying $infile -> $outfile\n"); + if ( $with_ActiveState ) { + my $depth = @rootdirs + @dirs; + my %opts = ( infile => $infile, + outfile => $tmpfile, + podpath => $podpath, + podroot => $podroot, + index => 1, + depth => $depth, + ); + eval { + ActivePerl::DocTools::Pod::pod2html(%opts); + 1; + } or $self->log_warn("[$htmltool] pod2html (" . + join(", ", map { "q{$_} => q{$opts{$_}}" } (keys %opts)) . ") failed: $@"); + } else { + my $path2root = join( '/', ('..') x (@rootdirs+@dirs) ); + my $fh = IO::File->new($infile) or die "Can't read $infile: $!"; + my $abstract = Module::Build::PodParser->new(fh => $fh)->get_abstract(); + + my $title = join( '::', (@dirs, $name) ); + $title .= " - $abstract" if $abstract; + + my @opts = ( + '--flush', + "--title=$title", + "--podpath=$podpath", + "--infile=$infile", + "--outfile=$tmpfile", + "--podroot=$podroot", + "--htmlroot=$path2root", + ); + + if ( eval{Pod::Html->VERSION(1.03)} ) { + push( @opts, ('--header', '--backlink=Back to Top') ); + } + + $self->log_verbose("P::H::pod2html @opts\n"); + eval { Pod::Html::pod2html(@opts); 1 } + or $self->log_warn("[$htmltool] pod2html( " . + join(", ", map { "q{$_}" } @opts) . ") failed: $@"); + } + # We now have to cleanup the resulting html file + if ( ! -r $tmpfile ) { + $errors++; + next POD; + } + my $fh = IO::File->new($tmpfile) or die "Can't read $tmpfile: $!"; + my $html = join('',<$fh>); + $fh->close; + if (!$self->_is_ActivePerl) { + # These fixups are already done by AP::DT:P:pod2html + # The output from pod2html is NOT XHTML! + # IE6+ will display content that is not valid for DOCTYPE + $html =~ s#^<!DOCTYPE .*?>#<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">#im; + $html =~ s#<html xmlns="http://www.w3.org/1999/xhtml">#<html>#i; + + # IE6+ will not display local HTML files with strict + # security without this comment + $html =~ s#<head>#<head>\n<!-- saved from url=(0017)http://localhost/ -->#i; } + # Fixup links that point to our temp blib + $html =~ s/\Q$blibdir\E//g; - $self->log_verbose("HTMLifying $infile -> $outfile\n"); - $self->log_verbose("pod2html @opts\n"); - eval { Pod::Html::pod2html(@opts); 1 } - or $self->log_warn("pod2html @opts failed: $@"); + $fh = IO::File->new(">$outfile") or die "Can't write $outfile: $!"; + print $fh $html; + $fh->close; + unlink($tmpfile); } + return ! $errors; + } # Adapted from ExtUtils::MM_Unix @@ -3293,7 +3481,7 @@ sub ACTION_diff { delete $installmap->{read}; delete $installmap->{write}; - my $text_suffix = file_qr('\.(pm|pod)$'); + my $text_suffix = $self->file_qr('\.(pm|pod)$'); while (my $localdir = each %$installmap) { my @localparts = File::Spec->splitdir($localdir); @@ -3331,7 +3519,35 @@ sub ACTION_install { my ($self) = @_; require ExtUtils::Install; $self->depends_on('build'); - ExtUtils::Install::install($self->install_map, $self->verbose, 0, $self->{args}{uninst}||0); + # RT#63003 suggest that odd cirmstances that we might wind up + # in a different directory than we started, so wrap with _do_in_dir to + # ensure we get back to where we started; hope this fixes it! + $self->_do_in_dir( ".", sub { + ExtUtils::Install::install( + $self->install_map, $self->verbose, 0, $self->{args}{uninst}||0 + ); + }); + if ($self->_is_ActivePerl && $self->{_completed_actions}{html}) { + $self->log_info("Building ActivePerl Table of Contents\n"); + eval { ActivePerl::DocTools::WriteTOC(verbose => $self->verbose ? 1 : 0); 1; } + or $self->log_warn("AP::DT:: WriteTOC() failed: $@"); + } + if ($self->_is_ActivePPM) { + # We touch 'lib/perllocal.pod'. There is an existing logic in subroutine _init_db() + # of 'ActivePerl/PPM/InstallArea.pm' that says that if 'lib/perllocal.pod' has a 'date-last-touched' + # greater than that of the PPM SQLite databases ('etc/ppm-perl-area.db' and/or + # 'site/etc/ppm-site-area.db') then the PPM SQLite databases are rebuilt from scratch. + + # in the following line, 'perllocal.pod' this is *always* 'lib/perllocal.pod', never 'site/lib/perllocal.pod' + my $F_perllocal = File::Spec->catfile($self->install_sets('core', 'lib'), 'perllocal.pod'); + my $dt_stamp = time; + + $self->log_info("For ActivePerl's PPM: touch '$F_perllocal'\n"); + + open my $perllocal, ">>", $F_perllocal; + close $perllocal; + utime($dt_stamp, $dt_stamp, $F_perllocal); + } } sub ACTION_fakeinstall { @@ -3398,8 +3614,13 @@ sub ACTION_installdeps { # relative command should be relative to our active Perl # so we need to locate that command if ( ! File::Spec->file_name_is_absolute( $command ) ) { + # prefer site to vendor to core + my @loc = ( 'site', 'vendor', '' ); my @bindirs = File::Basename::dirname($self->perl); - push @bindirs, map {$self->config->{"install${_}bin"}} '','site','vendor'; + push @bindirs, + map { + ($self->config->{"install${_}bin"}, $self->config->{"install${_}script"}) + } @loc; for my $d ( @bindirs ) { my $abs_cmd = $self->find_command(File::Spec->catfile( $d, $command )); if ( defined $abs_cmd ) { @@ -3484,7 +3705,6 @@ sub ACTION_ppmdist { } foreach my $type ( qw(bin lib) ) { - local $self->{properties}{html_css} = 'Active.css'; $self->htmlify_pods( $type, File::Spec->catdir($ppm, 'blib', 'html') ); } @@ -3618,7 +3838,7 @@ sub _sign_dir { sub _do_in_dir { my ($self, $dir, $do) = @_; - my $start_dir = $self->cwd; + my $start_dir = File::Spec->rel2abs($self->cwd); chdir $dir or die "Can't chdir() to $dir: $!"; eval {$do->()}; my @err = $@ ? ($@) : (); @@ -3654,7 +3874,11 @@ sub do_create_makefile_pl { my $self = shift; require Module::Build::Compat; $self->log_info("Creating Makefile.PL\n"); - Module::Build::Compat->create_makefile_pl($self->create_makefile_pl, $self, @_); + eval { Module::Build::Compat->create_makefile_pl($self->create_makefile_pl, $self, @_) }; + if ( $@ ) { + 1 while unlink 'Makefile.PL'; + die "$@\n"; + } $self->_add_to_manifest('MANIFEST', 'Makefile.PL'); } @@ -3668,19 +3892,17 @@ sub do_create_license { } my $l = $self->license - or die "No license specified"; - - my $key = $self->valid_licenses->{$l} - or die "'$l' isn't a license key we know about"; - my $class = "Software::License::$key"; + or die "Can't create LICENSE file: No license specified\n"; - eval "use $class; 1" - or die "Can't load Software::License::$key to create LICENSE file: $@"; + my $license = $self->_software_license_object + or die << "HERE"; +Can't create LICENSE file: '$l' is not a valid license key +or Software::License subclass; +HERE $self->delete_filetree('LICENSE'); my $author = join " & ", @{ $self->dist_author }; - my $license = $class->new({holder => $author}); my $fh = IO::File->new('> LICENSE') or die "Can't write LICENSE file: $!"; print $fh $license->fulltext; @@ -3779,9 +4001,6 @@ sub ACTION_distdir { $self->depends_on('distmeta'); - # Must not include MYMETA - $self->_check_mymeta_skip('MANIFEST.SKIP'); - my $dist_files = $self->_read_manifest('MANIFEST') or die "Can't create distdir without a MANIFEST file - run 'manifest' action first.\n"; delete $dist_files->{SIGNATURE}; # Don't copy, create a fresh one @@ -3797,6 +4016,7 @@ sub ACTION_distdir { $self->add_to_cleanup($dist_dir); foreach my $file (keys %$dist_files) { + next if $file =~ m{^MYMETA\.}; # Double check that we skip MYMETA.* my $new = $self->copy_if_modified(from => $file, to_dir => $dist_dir, verbose => 0); } @@ -3824,6 +4044,22 @@ sub ACTION_disttest { }); } +sub ACTION_distinstall { + my ($self, @args) = @_; + + $self->depends_on('distdir'); + + $self->_do_in_dir ( $self->dist_dir, + sub { + $self->run_perl_script('Build.PL') + or die "Error executing 'Build.PL' in dist directory: $!"; + $self->run_perl_script('Build') + or die "Error executing 'Build' in dist directory: $!"; + $self->run_perl_script('Build', [], ['install']) + or die "Error executing 'Build install' in dist directory"; + } + ); +} =begin private @@ -3882,12 +4118,33 @@ Reads $file and returns the $content. sub _slurp { my $self = shift; my $file = shift; - open my $fh, "<", $file or croak "Can't open $file: $!"; + my $mode = shift || ""; + open my $fh, "<$mode", $file or croak "Can't open $file for reading: $!"; local $/; return <$fh>; } +sub _spew { + my $self = shift; + my $file = shift; + my $content = shift || ""; + my $mode = shift || ""; + open my $fh, ">$mode", $file or croak "Can't open $file for writing: $!"; + print {$fh} $content; + close $fh; +} +sub _case_tolerant { + my $self = shift; + if ( ref $self ) { + $self->{_case_tolerant} = File::Spec->case_tolerant + unless defined($self->{_case_tolerant}); + return $self->{_case_tolerant}; + } + else { + return File::Spec->case_tolerant; + } +} sub _append_maniskip { my $self = shift; @@ -3942,7 +4199,7 @@ sub _check_manifest_skip { if ( ! -e $maniskip ) { $self->log_warn("File '$maniskip' does not exist: Creating a temporary '$maniskip'\n"); $self->_write_default_maniskip($maniskip); - $self->add_to_cleanup($maniskip); + $self->_unlink_on_exit($maniskip); } else { # MYMETA must not be added to MANIFEST, so always confirm the skip @@ -3962,14 +4219,28 @@ sub ACTION_manifest { ExtUtils::Manifest::mkmanifest(); } +sub ACTION_manifest_skip { + my ($self) = @_; + + if ( -e 'MANIFEST.SKIP' ) { + $self->log_warn("MANIFEST.SKIP already exists.\n"); + return 0; + } + $self->log_info("Creating a new MANIFEST.SKIP file\n"); + return $self->_write_default_maniskip; + return -e 'MANIFEST.SKIP' +} + # Case insensitive regex for files sub file_qr { - return File::Spec->case_tolerant ? qr($_[0])i : qr($_[0]); + return shift->{_case_tolerant} ? qr($_[0])i : qr($_[0]); } sub dist_dir { my ($self) = @_; - return join "-", $self->dist_name, $self->dist_version; + my $dir = join "-", $self->dist_name, $self->dist_version; + $dir .= "-" . $self->dist_suffix if $self->dist_suffix; + return $dir; } sub ppm_name { @@ -4067,13 +4338,13 @@ sub script_files { } my %pl_files = map { - File::Spec->canonpath( File::Spec->case_tolerant ? uc $_ : $_ ) => 1 + File::Spec->canonpath( $_ ) => 1 } keys %{ $self->PL_files || {} }; my @bin_files = $self->_files_in('bin'); my %bin_map = map { - $_ => File::Spec->canonpath( File::Spec->case_tolerant ? uc $_ : $_ ) + $_ => File::Spec->canonpath( $_ ) } @bin_files; return $_ = { map {$_ => 1} grep !$pl_files{$bin_map{$_}}, @bin_files }; @@ -4132,6 +4403,31 @@ BEGIN { *scripts = \&script_files; } } } +# use mapping or license name directly +sub _software_license_object { + my ($self) = @_; + return unless defined( my $license = $self->license ); + + my $class; + LICENSE: for my $l ( $self->valid_licenses->{ $license }, $license ) { + next unless defined $l; + my $trial = "Software::License::" . $l; + if ( eval "require Software::License; Software::License->VERSION(0.014); require $trial; 1" ) { + $class = $trial; + last LICENSE; + } + } + return unless defined $class; + + # Software::License requires a 'holder' argument + my $sl = eval { $class->new({holder=>"nobody"}) }; + if ( $@ ) { + $self->log_warn( "Error getting '$class' object: $@" ); + } + + return $sl; +} + sub _hash_merge { my ($self, $h, $k, $v) = @_; if (ref $h->{$k} eq 'ARRAY') { @@ -4145,7 +4441,6 @@ sub _hash_merge { sub ACTION_distmeta { my ($self) = @_; - $self->do_create_makefile_pl if $self->create_makefile_pl; $self->do_create_readme if $self->create_readme; $self->do_create_license if $self->create_license; @@ -4163,9 +4458,6 @@ sub do_create_metafile { $self->log_warn("No license specified, setting license = 'unknown'\n"); $p->{license} = 'unknown'; } - unless (exists $self->valid_licenses->{ $p->{license} }) { - die "Unknown license type '$p->{license}'"; - } # If we're in the distdir, the metafile may exist and be non-writable. $self->delete_filetree($metafile); @@ -4179,7 +4471,11 @@ sub do_create_metafile { push @INC, File::Spec->catdir($self->blib, 'lib'); } - if ($self->write_metafile($self->metafile,$self->get_metadata(fatal=>1))){ + if ( + $self->write_metafile( + $self->metafile,$self->get_metadata(fatal=>1, auto => 1) + ) + ){ $self->{wrote_metadata} = 1; $self->_add_to_manifest('MANIFEST', $metafile); } @@ -4187,37 +4483,30 @@ sub do_create_metafile { return 1; } +# We handle slurping from the metafile to ensure proper utf8 if possible sub read_metafile { my $self = shift; my ($metafile) = @_; - my $yaml; - my $class = $self->_mb_feature('YAML_support') - ? 'YAML::Tiny' : 'Module::Build::YAML' ; + return unless $self->try_require("CPAN::Meta::YAML", "0.002"); - eval "require $class; 1" or die $@; - my $meta = $class->read($metafile) - or $self->log_warn( "Error reading '$metafile': " . $class->errstr . "\n"); + my $string = $self->_slurp($metafile, $] < 5.8 ? "" : ":utf8"); + my $meta = CPAN::Meta::YAML->read_string($string) + or $self->log_warn( "Error parsing '$metafile': " . CPAN::Meta::YAML->errstr . "\n"); return $meta->[0] || {}; } +# We handle spewing to the metafile to ensure proper utf8 if possible sub write_metafile { my $self = shift; my ($metafile, $node) = @_; - my $yaml; - if ($self->_mb_feature('YAML_support')) { - # XXX this is probably redundant, but stick with it - require YAML::Tiny; - $yaml = YAML::Tiny->new($node); - } else { - require Module::Build::YAML; - $yaml = Module::Build::YAML->new($node); - } - my $result = $yaml->write($metafile) - or $self->log_warn( "Error writing '$metafile': " . $yaml->errstr . "\n"); - return $result; + return unless $self->try_require("CPAN::Meta::YAML", "0.002"); + + my $yaml = CPAN::Meta::YAML->new($node); + my $string = $yaml->write_string; + return $self->_spew($metafile, $string, $] < 5.8 ? "" : ":utf8") } sub normalize_version { @@ -4279,6 +4568,8 @@ sub prepare_metadata { my $fatal = $args->{fatal} || 0; my $p = $self->{properties}; + $self->auto_config_requires if $args->{auto}; + # A little helper sub my $add_node = sub { my ($name, $val) = @_; @@ -4286,11 +4577,11 @@ sub prepare_metadata { push @$keys, $name if $keys; }; - foreach (qw(dist_name dist_version dist_author dist_abstract license)) { - (my $name = $_) =~ s/^dist_//; - $add_node->($name, $self->$_()); - unless ( defined($node->{$name}) && length($node->{$name}) ) { - my $err = "ERROR: Missing required field '$_' for metafile\n"; + # validate required fields + foreach my $f (qw(dist_name dist_version dist_author dist_abstract license)) { + my $field = $self->$f(); + unless ( defined $field and length $field ) { + my $err = "ERROR: Missing required field '$f' for metafile\n"; if ( $fatal ) { die $err; } @@ -4299,33 +4590,46 @@ sub prepare_metadata { } } } + + + # add dist_* fields + foreach my $f (qw(dist_name dist_version dist_author dist_abstract)) { + (my $name = $f) =~ s/^dist_//; + $add_node->($name, $self->$f()); + } + + # normalize version $node->{version} = $self->normalize_version($node->{version}); - if (defined( my $l = $self->license )) { - unless ( exists $self->valid_licenses->{ $l } ) { - my $err = "Unknown license string '$l'"; - if ( $fatal ) { - die $err; - } - else { - $self->log_warn($err); - } - } + # validate license information + my $license = $self->license; + my ($meta_license, $meta_license_url); - if (my $key = $self->valid_licenses->{ $l }) { - my $class = "Software::License::$key"; - if (eval "require Software::License; require $class; 1") { - # S::L requires a 'holder' key - $node->{resources}{license} = $class->new({holder=>"nobody"})->url; - } - else { - $node->{resources}{license} = $self->_license_url($l); - } - } - # XXX we are silently omitting the url for any unknown license + # XXX this is still meta spec version 1 stuff + + # if Software::License::* exists, then we can use it to get normalized name + # for META files + + if ( my $sl = $self->_software_license_object ) { + $meta_license = $sl->meta_name; + $meta_license_url = $sl->url; + } + elsif ( exists $self->valid_licenses()->{$license} ) { + $meta_license = $license; + $meta_license_url = $self->_license_url( $license ); + } + else { + # if we didn't find a license from a Software::License class, + # then treat it as unknown + $self->log_warn( "Can not determine license type for '" . $self->license + . "'\nSetting META license field to 'unknown'.\n"); + $meta_license = 'unknown'; } + $node->{license} = $meta_license; + $node->{resources}{license} = $meta_license_url if defined $meta_license_url; + # add prerequisite data my $prereqs = $self->_normalize_prereqs; for my $t ( keys %$prereqs ) { $add_node->($t, $prereqs->{$t}); @@ -4802,6 +5106,13 @@ sub install_map { my $localdir = File::Spec->catdir( $blib, $type ); next unless -e $localdir; + # the line "...next if (($type eq 'bindoc'..." was one of many changes introduced for + # improving HTML generation on ActivePerl, see https://rt.cpan.org/Public/Bug/Display.html?id=53478 + # Most changes were ok, but this particular line caused test failures in t/manifypods.t on windows, + # therefore it is commented out. + + # ********* next if (($type eq 'bindoc' || $type eq 'libdoc') && not $self->is_unixish); + if (my $dest = $self->install_destination($type)) { $map{$localdir} = $dest; } else { @@ -5245,7 +5556,7 @@ sub dir_contains { return 0 if @second_dirs < @first_dirs; - my $is_same = ( File::Spec->case_tolerant + my $is_same = ( $self->_case_tolerant ? sub {lc(shift()) eq lc(shift())} : sub {shift() eq shift()} ); |