diff options
79 files changed, 4256 insertions, 1558 deletions
diff --git a/.gitignore b/.gitignore index 74b65eba75..a20fbf93e2 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ ext.libs /uudmap.h /bitcount.h +lib/inc/ lib/Win32.pm lib/Win32API/ lib/Win32CORE.pm @@ -1519,9 +1519,12 @@ cpan/MIME-Base64/t/quoted-print.t See whether MIME::QuotedPrint works cpan/MIME-Base64/t/unicode.t See whether MIME::Base64 works cpan/MIME-Base64/t/warn.t See whether MIME::Base64 works cpan/Module-Build/Changes Module::Build +cpan/Module-Build/lib/inc/latest.pm Module::Build +cpan/Module-Build/lib/inc/latest/private.pm Module::Build cpan/Module-Build/lib/Module/Build/API.pod Module::Build cpan/Module-Build/lib/Module/Build/Authoring.pod Module::Build cpan/Module-Build/lib/Module/Build/Base.pm Module::Build +cpan/Module-Build/lib/Module/Build/Bundling.pod Module::Build cpan/Module-Build/lib/Module/Build/Compat.pm Module::Build cpan/Module-Build/lib/Module/Build/Config.pm Module::Build cpan/Module-Build/lib/Module/Build/Cookbook.pm Module::Build @@ -1548,33 +1551,42 @@ cpan/Module-Build/lib/Module/Build/PPMMaker.pm Module::Build cpan/Module-Build/lib/Module/Build/Version.pm Module::Build cpan/Module-Build/lib/Module/Build/YAML.pm Module::Build cpan/Module-Build/scripts/config_data Module::Build +cpan/Module-Build/t/actions/installdeps.t Module::Build cpan/Module-Build/t/add_property.t Module::Build cpan/Module-Build/t/basic.t Module::Build -cpan/Module-Build/t/bundled/Tie/CPHash.pm Module::Build.pm +cpan/Module-Build/t/bundled/Tie/CPHash.pm Module::Build +cpan/Module-Build/t/bundle_inc.t Module::Build cpan/Module-Build/t/compat/exit.t Module::Build cpan/Module-Build/t/compat.t Module::Build -cpan/Module-Build/t/debug.t Module::Build tests +cpan/Module-Build/t/debug.t Module::Build cpan/Module-Build/t/destinations.t Module::Build cpan/Module-Build/t/extend.t Module::Build cpan/Module-Build/t/ext.t Module::Build cpan/Module-Build/t/files.t Module::Build cpan/Module-Build/t/help.t Module::Build -cpan/Module-Build/t/install_extra_target.t Module::Build tests +cpan/Module-Build/t/install_extra_target.t Module::Build cpan/Module-Build/t/install.t Module::Build cpan/Module-Build/t/lib/DistGen.pm Module::Build cpan/Module-Build/t/lib/MBTest.pm Module::Build cpan/Module-Build/t/manifypods.t Module::Build -cpan/Module-Build/t/mbyaml.t Module::Build cpan/Module-Build/t/metadata2.t Module::Build cpan/Module-Build/t/metadata.t Module::Build cpan/Module-Build/t/moduleinfo.t Module::Build +cpan/Module-Build/t/mymeta.t Module::Build cpan/Module-Build/t/new_from_context.t Module::Build cpan/Module-Build/t/notes.t Module::Build cpan/Module-Build/t/parents.t Module::Build -cpan/Module-Build/t/PL_files.t Module::Build tests +cpan/Module-Build/t/perl_mb_opt.t Module::Build +cpan/Module-Build/t/PL_files.t Module::Build cpan/Module-Build/t/pod_parser.t Module::Build cpan/Module-Build/t/ppm.t Module::Build +cpan/Module-Build/t/properties/module_name.t Module::Build +cpan/Module-Build/t/properties/needs_compiler.t Module::Build +cpan/Module-Build/t/properties/share_dir.t Module::Build +cpan/Module-Build/t/README.pod Module::Build +cpan/Module-Build/t/resume.t Module::Build cpan/Module-Build/t/runthrough.t Module::Build +cpan/Module-Build/t/sample.t Module::Build cpan/Module-Build/t/script_dist.t Module::Build cpan/Module-Build/t/test_file_exts.t Module::Build cpan/Module-Build/t/test_types.t Module::Build @@ -1582,7 +1594,7 @@ cpan/Module-Build/t/test_type.t Module::Build cpan/Module-Build/t/tilde.t Module::Build cpan/Module-Build/t/use_tap_harness.t Module::Build cpan/Module-Build/t/versions.t Module::Build -cpan/Module-Build/t/write_default_maniskip.t Module::Build tests +cpan/Module-Build/t/write_default_maniskip.t Module::Build cpan/Module-Build/t/xs.t Module::Build cpan/Module-Load-Conditional/lib/Module/Load/Conditional.pm Module::Conditional cpan/Module-Load-Conditional/t/01_Module_Load_Conditional.t Module::Conditional tests diff --git a/Porting/Maintainers.pl b/Porting/Maintainers.pl index e5db2eb5a8..5ffa715ca1 100755 --- a/Porting/Maintainers.pl +++ b/Porting/Maintainers.pl @@ -104,7 +104,7 @@ use File::Glob qw(:case); SIGNATURE THANKS TODO Todo VERSION WHATSNEW ); - + # Each entry in the %Modules hash roughly represents a distribution, # except in the case of CPAN=1, where it *exactly* represents a single # CPAN distribution. @@ -159,7 +159,7 @@ use File::Glob qw(:case); # Each key reprepresents a string prefix, with longest prefixes checked # first. The first match causes that prefix to be replaced with the # corresponding key. For example, with the following MAP: -# { +# { # 'lib/' => 'lib/', # '' => 'lib/Foo/', # }, @@ -167,7 +167,7 @@ use File::Glob qw(:case); # these files are mapped as shown: # # README becomes lib/Foo/README -# lib/Foo.pm becomes lib/Foo.pm +# lib/Foo.pm becomes lib/Foo.pm # # The default is dependent on the type of module. # For distributions which appear to be stored under ext/, it defaults to: @@ -176,7 +176,7 @@ use File::Glob qw(:case); # # otherwise, it's # -# { +# { # 'lib/' => 'lib/', # '' => 'lib/Foo/Bar/', # } @@ -1004,10 +1004,10 @@ use File::Glob qw(:case); 'Module::Build' => { 'MAINTAINER' => 'kwilliams', - 'DISTRIBUTION' => 'DAGOLDEN/Module-Build-0.35.tar.gz', + 'DISTRIBUTION' => 'DAGOLDEN/Module-Build-0.35_08.tar.gz', 'FILES' => q[cpan/Module-Build], - 'EXCLUDED' => [ qw{ t/par.t t/signature.t scripts/bundle.pl}, - qr!^contrib/! ], + 'EXCLUDED' => [ qw{ t/par.t t/signature.t }, + qr!^contrib/!, qr!^devtools! ], 'CPAN' => 1, 'UPSTREAM' => 'cpan', }, diff --git a/cpan/Module-Build/Changes b/cpan/Module-Build/Changes index df66502dbd..f0f8d1b46d 100644 --- a/cpan/Module-Build/Changes +++ b/cpan/Module-Build/Changes @@ -1,24 +1,238 @@ Revision history for Perl extension Module::Build. +0.35_08 - Mon Nov 16 22:38:28 EST 2009 + + Bug fixes: + + - Multiple tests were failing due to dependency problems. Author + dependencies have been largely removed from core 'requires' into + optional features. Feature prereq detection and messaging have been + expanded and bugs on older Perls have been removed. + +0.35_07 - Sat Nov 14 17:14:39 EST 2009 + + Bug fixes: + + - Auto-detection of abstract and author fixed for mixed-case POD headers + (RT#51117) [David Wheeler] + + - resume() was not restoring additions to @INC added in Build.PL + (RT#50145) [David Golden] + + - When tarball paths are less than 100 characters, disables 'prefix' + mode of Archive::Tar for maximum compatibility (RT#50571) [David Golden] + +0.35_06 - Fri Nov 13 14:51:28 EST 2009 + + Enhancements: + + - Added experimental inc/ bundling; see Module::Build::Bundling for + details. [David Golden and Eric Wilhelm] + + - Clarified that 'apache' in the license attribute indicates the Apache + License 2.0 and added 'apache_1_1' for the older version of the license + (RT#50614) [David Golden] + + Bug fixes: + + - Merging 'requires' and 'build_requires' in Module::Build::Compat could + lead to duplicate PREREQ_PM entries; now the highest version is used + for PREREQ_PM. (RT#50948) [David Golden] + + - Module::Build::Compat will now die with an error if advanced, + non-numeric prerequisites are given, as these are not supported by + ExtUtils::MakeMaker in PREREQ_PM [David Golden] + + - Made MYMETA generation non-fatal if fields required for META.yml + are missing [David Golden] + + - Added Pod::Simple to requirements for manpage support; avoids + problems if a user has a broken Pod::Man/Pod::Simple. (RT#50081) + [David Golden] + + - Won't die if installed Pod::Readme is broken [David Golden] + + Other: + + - Fixed Module::Build::Notes POD [David Golden] + + - Some commands had become silent by default, so added a few short status + messages so users know something actually happened [David Golden] + + - Cleaned up Changes file formatting [David Golden] + + - Removed most PERL_CORE customizations from test files due to + reorganization of dual-life modules in core (RT#49522) [David Golden] + +0.35_05 - Wed Oct 28 17:20:59 EDT 2009 + + Bug fixes: + + - Fix test failure in t/actions/installdeps.t when $^X is not the default + perl [David Golden] + + - Work around $VERSION numbers in ActiveState with multiple underscores + that prevent Module::Build from installing on Win32 [David Golden] + + - Fix bug cleaning compatibility Makefile when older ExtUtils::Manifest is + installed [David Golden with help from David Cantrell] + + Other: + + - Suppressed more warnings from tests [David Golden] + + - Add provisional support for 'package NAME VERSION' syntax added in + Perl 5.11.1 [David Golden] + +0.35_04 - Fri Oct 23 11:20:41 EDT 2009 + + Bug fixes: + + - Fix test failure if IPC::Cmd isn't installed [David Golden] + + Other: + + - Suppressed warning messages from various tests [David Golden] + +0.35_03 - Wed Oct 21 21:20:59 EDT 2009 + + *** API CHANGE *** + + - The prepare_metadata() method used to take a YAML::Node object as an + argument for modification. The method now takes no arguments and just + returns a hash reference of metadata. [David Golden] + + Enhancements + + - Command line options may be set via the PERL_MB_OPT environment + variable (similar to PERL_MM_OPT in ExtUtils::MakeMaker) + + Bug fixes: + + - Updated PPM generation to PPM v4 (RT#49600) [Olivier Mengue] + + - When c_source is specified, the directory scan will include additional, + less-common C++ extensions (RT49298) [David Golden] + + - When module_name is not supplied, no packlist was being written; fixed + by guessing module_name from dist_version_from or the directory name + (just like ExtUtils::Manifest does without NAME) [David Golden] + + - Bumped IO::File prereq to fix binmode failures in PPMMaker on Perl + prior to 5.8.8 [David Golden] + + Other: + + - Replaced use of YAML.pm with YAML::Tiny; Module::Build::YAML is now + based on YAML::Tiny as well [David Golden] + + - Reduced amount of console output under normal operation (use --verbose + to see all output) [David Golden] + +0.35_02 - Mon Sep 7 22:37:42 EDT 2009 + + Enhancements: + + - Added 'needs_compiler' property. Defaults to true if XS or c_source + exist. If true, ExtUtils::CBuilder is also added to build_requires. + [David Golden] + + - File::ShareDir automatically added to 'requires' if 'share_dir' is set + [David Golden] + + - Added 'Build installdeps' action to install needed dependencies via + a user-configurable command line program. (Defaults to 'cpan'.) + [Eric Wilhelm] + + Bug fixes: + + - Failure to detect a compiler will now warn during Build.PL and be a + fatal error when trying to compile during Build. (RT#48918) [David + Golden] + + - Fixed directory sorting failure in share_dir.t [David Golden] + + - Property defaults that are data structures were being assigned as + references to new objects. Changed so that defaults are cloned instead. + (This mostly affects testing, which often creates multiple objects in the + same process) [David Golden] + + - Simplified error message on exit under use_tap_harness [suggested by + David Wheeler] + + - Fixed typemap search to use a dist-level typemap if a typemap is not + found in the directory with the *.xs file; (was manifesting as warnings + in Perl 5.6 tests) [David Golden] + + Other: + + - Replaced guts of new_from_context(). Build.PL is now executed in a + separate process before resume() is called. (This is generally only of + interest to Module::Build or toolchain developers) (RT#49350) [David + Golden, Eric Wilhelm, Ken Williams] + + - Revised test helper classes to fix potential bugs and add new features + to make writing tests simpler and easier. Changes incorporated into + t/README.pod and t/sample.t as examples for new testing. [David Golden] + +0.35_01 - Mon Aug 31 12:11:10 EDT 2009 + + Enhancements: + + - Generates MYMETA.yml during Build.PL (new standard protocol for + communicating configuration results between toolchain components) + [David Golden] + + - Added 'share_dir' property to provide File::ShareDir support; + set automatically if a directory called 'share' exists + [David Golden] + + Bug fixes: + + - Fix the t/destinations.t fix. [David Golden, with thanks to Eric Wilhelm] + + - Fix recursive test files in generated Makefile.PL (RT#49254) [Sawyer X] + + - Guard against trying :utf8 when :utf8 isn't available + + - The "test" action now dies when using the 'use_tap_harness' + option and tests fail, matching the behavior under Test::Harness. + (RT#49080) [initial patch from David Wheeler; revised by David Golden] + + Other: + + - Added t/README.pod and t/sample.t to guide developers writing new tests + [David Golden, with some code from Eric Wilhelm] + + - Module::Build::Compat 'passthrough' style has been deprecated. Using + 'passthrough' will issue warnings on Makefile.PL generation. See + Module::Build::Compat documentation for rationale. + 0.35 - Thu Aug 27 09:12:02 EDT 2009 Bug fixes: - - Fix t/destinations.t segfault on 5.6.2 + + - Fix t/destinations.t segfault on 5.6.2 [David Golden] 0.34_06 - Sat Aug 22 21:58:26 EDT 2009 Bug fixes: + - Multiple test fixes for OS2 [Ilya Zakharevich] + - Generated.ppd files use :utf8 if possible (RT#48827) [Olivier Mengue] + - Fixed preservation of custom install_paths on resume (RT#41166) [David Golden] + - Warn instead of crashing when Pod::Man tries to create files with colons on vfat partitions on unix (RT#45544) [David Golden] 0.34_05 - Sun Aug 9 22:31:37 EDT 2009 Bug fixes: - - When auto_configure_requires is true (the default), Module::Build will + + - When auto_configure_requires is true (the default), Module::Build will only add last 'major' version of Module:Build (e.g. 0.XX) to configure_requires to avoid specifying a minor development release not available on CPAN [David Golden] @@ -26,6 +240,7 @@ Revision history for Perl extension Module::Build. 0.34_04 - Sat Aug 8 11:02:24 EDT 2009 Other: + - Added documentation warning that 'get_options' should be capitalized to avoid conflicting with future Module::Build options and changed the examples accordingly. @@ -33,12 +248,17 @@ Revision history for Perl extension Module::Build. 0.34_03 - Sat Aug 8 07:39:16 EDT 2009 Bug fixes: + - Fixed failing xs.t if /tmp is mounted noexec (RT#47331) [David Golden] + - Fixed failing debug.t on VMS (RT#48362) [Craig Berry] + - Prevent par.t from dying on error in .zip extraction [David Golden] + - Fixed potential runthrough.t failure on 5.6.2 [David Golden] Other: + - Archive::Tar changed from 'requires' to 'recommends' so non-authors without IO::Zlib can still use Module::Build to install modules [reported by Matt Trout, fix by David Golden] @@ -46,22 +266,26 @@ Revision history for Perl extension Module::Build. 0.340201 - Sun Aug 9 22:11:04 EDT 2009 Other: + - Version bump for Perl core for 5.10.1 release; no other changes 0.34_02 - Sun Jul 26 22:50:40 EDT 2009 Bug-fixes: + - Bundled Module::Build::Version updated to bring into sync with CPAN version.pm 0.77 [John Peacock] 0.34_01 - Sat Jul 18 16:32:09 EDT 2009 Enhancements: + - Added --debug flag to trace Build action execution (RT#47933) [David Golden] Bug-fixes: - - Bundled Module::Build::Version version code updated to fix unsafe use + + - Bundled Module::Build::Version version code updated to fix unsafe use of $@ (RT#47980) [John Peacock] 0.34 - Tue Jul 7 16:56:47 EDT 2009 @@ -71,27 +295,33 @@ Revision history for Perl extension Module::Build. 0.33_06 - Sun Jul 5 10:11:40 EDT 2009 Bug-fixes: + - Bundled version code will use pure Perl on 5.10.0 to work around a corner case involving eval and locale [John Peacock] + - Reversed VMS patch from 0.33_03 [Craig Berry] + - PL_files in Build.PL that are in the bin/scripts directory should not be - installed as if they are scripts (fixed for case-tolerant systems). + installed as if they are scripts (fixed for case-tolerant systems). [David Golden, reported by Craig Berry] 0.33_05 - Sun Jun 28 22:06:49 EDT 2009 Enhancements: + - New 'auto_configure_requires' parameter (default 1) controls whether Module::Build should add itself to configure_requires in META.yml if not specified in Build.PL [David Golden] Bug-fixes: + - The default MANIFEST.SKIP created by the "manifest" action was out of date. It will now use the installed MANIFEST.SKIP and add some Module::Build and distribution specific items to it. [Michael Schwern] Other: + - configure_requires do not necessarily need to be in requires or build_requires; warning to that effect has been removed [David Golden] @@ -99,99 +329,141 @@ Revision history for Perl extension Module::Build. 0.33_04 - Fri Jun 26 07:09:06 EDT 2009 Bug-fixes: + - Don't try utf8 YAML I/O on Perl 5.6 [David Golden] Other: + - configure_requires added to prereq report (RT#47254) [Curtis Jewell] + - updated Module::Build::Version to match forthcoming version.pm 0.77 (RT#47256) [John Peacock] + - skips xs.t and ppm.t when perl was not compiled with dynamic loading - since Module::Buld does not support static linking (RT#46178) + since Module::Buld does not support static linking (RT#46178) [David Golden] + - skip failing test in par.t if Archive::Zip is broken [David Golden] + - Added YAML utf8 patch in 0.33_03 changes list + - Added attribution for patches in 0.33_03 changes list 0.33_03 - Mon Jun 22 17:22:56 EDT 2009 Bug-fixes: - - Removes Module::Build from its own configure/build_requires + + - Removes Module::Build from its own configure/build_requires [David Golden] + - ConfigData->feature() confirms that modules actually load successfully, not just that they are present. (RT#43557) [David Golden] - - Module::Build::Compat handling of INSTALL*LIB (RT#43827) + + - Module::Build::Compat handling of INSTALL*LIB (RT#43827) [Tony Payne, David Golden] + - Module::Build::Compat and recursive test files (RT#39171) [Dave Rolsky] + - Fixed bug linking non-standard XS names on Windows (RT#38065) ["snaury"] - - Run PL files that don't generate any file (RT#39365) + + - Run PL files that don't generate any file (RT#39365) [Matisse Enzer, David Golden] + - HTML generation failure no longer fatal (RT#36660) [David Golden] - - realclean might not delete Build.bat on Windows (RT#43863) + + - realclean might not delete Build.bat on Windows (RT#43863) [Roy Ivy, David Golden] + - include_dirs parameter now works correctly when given a single string argument (RT#40177) [David Wheeler] + - Lots of spelling fixes in the POD (RT#45528r) [Lars Dieckow] + - On Unix-like systems, tilde expansion is more liberal in username characters accepted (RT#33492) [Jon Jensen] Other + - On MSWin32, bumped File::Spec prereq to 3.30 for a variety of fixes + - Add support for VMS in Unix compatibility mode (RT#42157) [John E. Malmberg - - Added a can_action($name) method (RT#45172) [brian d foy] + + - Added a can_action($name) method (RT#45172) [brian d foy] + - Documented that subclass methods should not permanently change current directory (RT#46919) [David Wheeler] + - META.yml encoded in UTF-8 (RT#43765) [Olivier Mengue] 0.33_02 - Mon Jun 15 12:23:55 EDT 2009 Bug-fixes: + - Fixed tests for bleadperl 0.33_01 - Sat Jun 13 20:24:42 EDT 2009 Bug-fixes: + - Fixed RT#42724: consolidated VMS fixes [patch by Craig Berry] + - Fixed RT#46338: passthrough Makefile.PL cleans Makefile during distclean + - Fixed RT#45700: t/compat.t for HP/UX make Other: - - Adds current Module::Build to configure_requires (and build_requires) + + - Adds current Module::Build to configure_requires (and build_requires) if no configure_requires is specified + - Always normalizes version number tuples in META.yml (e.g. 'v1.2.0') - (Partially addresses RT#46150) - - Normalizes a generated dist_version (e.g. from a .pm file) -- + (Partially addresses RT#46150) + + - Normalizes a generated dist_version (e.g. from a .pm file) -- dist_version set manually in Build.PL is not normalized + - Documentation update for create_license + - Minor POD cleanup 0.33 - Sun May 3 20:16:34 PDT 2009 Bug-fixes: + - Fixed RT#45462: Compat.pm needs to reference 'Build.com' on VMS [patch from John Malmberg] + - Fixed RT#45461: ext.t on VMS [patch from John Malmberg] + - Fixed RT#43861: Module::Build::PPMMaker has broken PPD name versioning for v5.10+ 0.32_01 - Tue Apr 14 17:14:22 PDT 2009 Bug-fixes: + - Module::Build::Compat had stopped adding "PL_FILES => {}" when no PL_files property was set in Build.PL; restored old behavior and fixed tests and documentation related to this issue [David Golden] - - Caches ExtUtils::CBuilder object in a temporary stash instead of properties + + - Caches ExtUtils::CBuilder object in a temporary stash instead of properties + - Fixed undef resources->license in META.yml (RT #44453). + - Use $^X instead of 'perl' in t/ext.t [David Golden] (RT #43485) Other: + - Generated META.yml will indicate version 1.4 of the specification (RT #37478) [patch from Alexandr Ciornii] + - Archive::Tar now the default for generating tarballs on all platforms (avoids problems with incompatible tar binaries) + - dist_dir() now uses dist_name() and dist_version() accessors rather than using its properties directly. [brian d foy] (RT #45038) - + 0.32 - Wed Feb 25 17:40:02 PST 2009 No changes since 0.31_04. @@ -199,100 +471,129 @@ Revision history for Perl extension Module::Build. 0.31_04 - Fri Feb 20 11:04:59 PST 2009 Other - - Bumped Test::Harness prereq to 3.16 for latest PERL5LIB fixes (solves + +- Bumped Test::Harness prereq to 3.16 for latest PERL5LIB fixes (solves test failures when installing Module::Build using CPANPLUS::Dist::Build) [David Golden] 0.31_03 - Sun Feb 8 14:54:01 PST 2009 Enhancements + - added a "prereq_data" action that prints a Perl data structure of all prerequisites; can be loaded by external tools using eval() [David Golden] Bug-fixes + - 'fakeinstall' action warns and skips without ExtUtils::Install 1.32+ [David Golden, reported by Zefram] + - allows Module::Build version mismatch when installing self; works around limitations in CPANPLUS::Dist::Build [David Golden] 0.31_02 - Tue Jan 27 09:16:43 PST 2009 Other + - tests now use File::Temp (added to build_requires); appears to fix Win32 testing heisenbug on directory removal during high system loads + - use_tap_harness.t will skip unless a release version of TAP::Harness is installed + - improved diagnostics to ensure_blib() tests in t/lib/MBTest.pm Compat + - passthrough Makefile.PL will now play nice with cpantesters' on exit(0) (RT#32018) [Eric Wilhelm] Bug Fixes + - fix for doubling-up of --prefix (RT#19951) 0.31012 - Wed Jan 14 01:36:19 PST 2009 Bug Fixes + - t/tilde.t maybe actually fixed on MSWin32 now. 0.31011 - Mon Jan 12 21:57:04 PST 2009 Bug Fixes + - t/tilde.t had been failing on MSWin32 (RT#42349) 0.3101 - Mon Jan 12 13:52:36 PST 2009 Other + - added 'mirbsd' as a Unix-type OS [BinGOs] + - added 'haiku' as a Unix-type OS (backported from bleadperl) + - skips certain tests on VMS (backported from bleadperl) + - sets $^X to absolute path in tests (backported from bleadperl) 0.31 - Sat Dec 20 15:03:33 2008 Deprecations + - Use of attributes as class methods is deprecated (this was never a documented feature and appears to only have worked accidentally.) 0.30_02 - Mon Dec 15 12:23:55 PST 2008 Bug Fixes + - make Software::License dependency "softer". 0.30_01 - Thu Dec 11 18:25:53 PST 2008 New Docs + - Added a recipe for writing a new action to the Cookbook + - Added a recipe for bundling Module::Build to the Cookbook. Doc Fixes + - Clarified dist_abstract search procedure in API.pod (RT#41056) [Mario Domgoergen] Bug Fixes + - Workaround HARNESS_TIMER env issue in t/compat.t (RT#39635) + - Fix ~ expansion when $HOME is different from /etc/passwd as when running sudo. [rt.cpan.org 39662] + - Fixed a small POD error in the Cookbook. [Damyan Ivanov] + - Unset group/other write permission bits when using Archive::Tar to build the dist tarball. (RT#39804) [David Golden] Enhancements + - We now support a 'create_license' parameter to new() that will create a LICENSE file during the 'dist' phase with the full text of the license. This requires Software::License on the author's machine. + - Added lgpl2/lgpl3 entries to the supported licenses (RT#40532). + - Support for validating properties with a check subref. [David Wheeler] Test Fixes + - Defend against more stray environment variables interfering with the tests. Other + - Updated our embedded version.pm to 0.76, enhanced documentation on dist_version_from. [John Peacock] @@ -484,11 +785,11 @@ Revision history for Perl extension Module::Build. have stopped, but it didn't. Fixed. [Matthew Cast and David Golden] - - Module::Build::Compat adds "require 5.XXXXX" to Makefile.PL when + - Module::Build::Compat adds "require 5.XXXXX" to Makefile.PL when 'perl' is specified as a 'requires' prerequisite [David Golden] - - Refactored t/compat.t for modularity and transparency; added - labels for all tests; supressed subprocess output to + - Refactored t/compat.t for modularity and transparency; added + labels for all tests; supressed subprocess output to STDOUT and STDERR [David Golden] - Fixed bug in perl_version_to_float when version is already a float @@ -1015,7 +1316,7 @@ Revision history for Perl extension Module::Build. - The synonyms 'scripts' and 'prereq' for 'script_files' and 'requires' were broken in a previous version (0.27_01, probably), but now they're fixed. [David Golden] - + - Previously, we assumed that any custom subclass of Module::Build was located in _build/lib/. This is only true if the author used the subclass() method, though. We now use %INC to find where the @@ -2162,13 +2463,13 @@ Revision history for Perl extension Module::Build. - Added experimental code to build a .ppd file, in support of ActiveState's "Perl Package Manager". [original patch by Dave Rolsky] - + - For authors who use Module::Signature to sign their distributions, we now create the SIGNATURE file right in the distribution directory, rather than creating it in the top-level directory and copying it into place. This solves problems related to having files get out of date with respect to their signatures. - + - We now don't depend on Module::Info to scan for packages during the 'dist' action anymore, because it's way too aggressive about loading other modules that you may not want loaded. We now just @@ -2231,12 +2532,12 @@ Revision history for Perl extension Module::Build. - The distribution directory (e.g. Sample-Module-0.13/ ) will now be deleted during the 'clean' or 'realclean' actions. - + - During testing of modules, blib/lib and blib/arch are now added as absolute paths, not relative. This helps tests that load the modules at runtime and may change the current working directory (like Module::Build itself does during testing). - + - The $Config{cc} entry on some people's systems is something like 'ccache gcc', so we now split that string using split_like_shell(). [Richard Clamp] @@ -2266,7 +2567,7 @@ Revision history for Perl extension Module::Build. - When compiling C code, we now respect 'pollute' and 'inc' parameters. (XXX - needs docs) [Dave Rolsky] - + - Made the creation of the "install map" more generic. (XXX - needs documentation) @@ -2623,7 +2924,7 @@ Revision history for Perl extension Module::Build. - Renamed module_name_to_file() to find_module_by_name(), and added a parameter specifying the directories to search in. Previously we searched in 'lib' and @INC, which wasn't correct in all - situations. + situations. - Patched the docs to change "Build test" to "./Build test" [Elizabeth Mattijsen] @@ -2817,7 +3118,7 @@ Revision history for Perl extension Module::Build. - For the 'Build dist' action, we'll use the 'tar' and 'gzip' programs (as specified by Config.pm) on Unix platforms, otherwise we'll use Archive::Tar and Compress::Zlib. - + 0.02 Wed Sep 5 00:53:04 CDT 2001 - Added POD documentation. diff --git a/cpan/Module-Build/lib/Module/Build.pm b/cpan/Module-Build/lib/Module/Build.pm index be8c1f7079..efae7f9abb 100644 --- a/cpan/Module-Build/lib/Module/Build.pm +++ b/cpan/Module-Build/lib/Module/Build.pm @@ -15,7 +15,7 @@ use Module::Build::Base; use vars qw($VERSION @ISA); @ISA = qw(Module::Build::Base); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; # Okay, this is the brute-force method of finding out what kind of @@ -167,24 +167,24 @@ This illustrates initial configuration and the running of three 'actions'. In this case the actions run are 'build' (the default action), 'test', and 'install'. Other actions defined so far include: - build manpages - clean pardist - code ppd - config_data ppmdist - diff prereq_data - dist prereq_report - distcheck pure_install - distclean realclean - distdir retest - distmeta skipcheck - distsign test - disttest testall - docs testcover - fakeinstall testdb - help testpod - html testpodcoverage - install versioninstall - manifest + build manifest + clean manpages + code pardist + config_data ppd + diff ppmdist + dist prereq_data + distcheck prereq_report + distclean pure_install + distdir realclean + distmeta retest + distsign skipcheck + disttest test + docs testall + fakeinstall testcover + help testdb + html testpod + install testpodcoverage + installdeps versioninstall You can run the 'help' action for a complete list of actions. @@ -318,7 +318,7 @@ tarball of the files listed in F<MANIFEST> and compress the tarball using GZIP compression. By default, this action will use the C<Archive::Tar> module. However, you can -force it to use binary "tar" and "gzip" executables by supplying an explicit +force it to use binary "tar" and "gzip" executables by supplying an explicit C<tar> (and optional C<gzip>) parameter: ./Build dist --tar C:\path\to\tar.exe --gzip C:\path\to\zip.exe @@ -355,8 +355,8 @@ F<META.yml> is a file containing various bits of I<metadata> about the distribution. The metadata includes the distribution name, version, abstract, prerequisites, license, and various other data about the distribution. This file is created as F<META.yml> in YAML format. -It is recommended that the C<YAML> module be installed to create it. -If the C<YAML> module is not installed, an internal module supplied +It is recommended that the C<YAML::Tiny> module be installed to create it. +If the C<YAML::Tiny> module is not installed, an internal module supplied with Module::Build will be used to write the META.yml file, and this will most likely be fine. @@ -445,6 +445,24 @@ This can be a good idea, as it helps prevent multiple versions of a module from being present on your system, which can be a confusing situation indeed. +=item installdeps + +[version 0.36] + +This action will use the C<cpan_client> parameter as a command to install +missing prerequisites. You will be prompted whether to install +optional dependencies. + +The C<cpan_client> option defaults to 'cpan' but can be set as an option or in +F<.modulebuildrc>. It must be a shell command that takes a list of modules to +install as arguments (e.g. 'cpanp -i' for CPANPLUS). If the program part is a +relative path (e.g. 'cpan' or 'cpanp'), it will be located relative to the perl +program that executed Build.PL. + + /opt/perl/5.8.9/bin/perl Build.PL + ./Build installdeps --cpan_client 'cpanp -i' + # installs to 5.8.9 + =item manifest [version 0.05] @@ -541,7 +559,7 @@ for a bug report. [version 0.28] This action is identical to the C<install> action. In the future, -though, when C<install> starts writing to the file +though, when C<install> starts writing to the file F<$(INSTALLARCHLIB)/perllocal.pod>, C<pure_install> won't, and that will be the only difference between them. @@ -666,7 +684,7 @@ argument. [version 0.25] -This checks all the files described in the C<docs> action and +This checks all the files described in the C<docs> action and produces C<Test::Harness>-style output. If you are a module author, this is useful to run before creating a new release. @@ -674,7 +692,7 @@ this is useful to run before creating a new release. [version 0.28] -This checks the pod coverage of the distribution and +This checks the pod coverage of the distribution and produces C<Test::Harness>-style output. If you are a module author, this is useful to run before creating a new release. @@ -731,15 +749,20 @@ C<no> or C<no-> (e.g. C<--noverbose> or C<--no-verbose>). Suppress informative messages on output. +=item verbose + +Display extra information about the Build on output. + +=item cpan_client + +Sets the C<cpan_client> command for use with the C<installdeps> action. +See C<installdeps> for more details. + =item use_rcfile Load the F<~/.modulebuildrc> option file. This option can be set to false to prevent the custom resource file from being loaded. -=item verbose - -Display extra information about the Build on output. - =item allow_mb_mismatch Suppresses the check upon startup that the version of Module::Build @@ -754,7 +777,6 @@ executed build actions. =back - =head2 Default Options File (F<.modulebuildrc>) [version 0.28] @@ -782,15 +804,35 @@ key C<*> (asterisk) denotes any global options that should be applied to all actions, and the key 'Build_PL' specifies options to be applied when you invoke C<perl Build.PL>. - * verbose=1 # global options - diff flags=-u - install --install_base /home/ken - --install_path html=/home/ken/docs/html + * verbose=1 # global options + diff flags=-u + install --install_base /home/ken + --install_path html=/home/ken/docs/html + installdeps --cpan_client 'cpanp -i' If you wish to locate your resource file in a different location, you can set the environment variable C<MODULEBUILDRC> to the complete absolute path of the file containing your options. +=head2 Environment variables + +=over + +=item MODULEBUILDRC + +[version 0.28] + +Specifies an alternate location for a default options file as described above. + +=item PERL_MB_OPT + +[version 0.36] + +Command line options that are applied to Build.PL or any Build action. The +string is split as the shell would (e.g. whitespace) and the result is +prepended to any actual command-line arguments. + +=back =head1 INSTALL PATHS @@ -1091,7 +1133,7 @@ modify it under the same terms as Perl itself. =head1 SEE ALSO perl(1), L<Module::Build::Cookbook>, L<Module::Build::Authoring>, -L<Module::Build::API>, L<ExtUtils::MakeMaker>, L<YAML> +L<Module::Build::API>, L<ExtUtils::MakeMaker>, L<YAML::Tiny> F<META.yml> Specification: L<http://module-build.sourceforge.net/META-spec-current.html> diff --git a/cpan/Module-Build/lib/Module/Build/API.pod b/cpan/Module-Build/lib/Module/Build/API.pod index f4e4cea09d..1f5d51f777 100644 --- a/cpan/Module-Build/lib/Module/Build/API.pod +++ b/cpan/Module-Build/lib/Module/Build/API.pod @@ -454,8 +454,13 @@ Specifies the licensing terms of your distribution. Valid options include: =item apache -The distribution is licensed under the Apache Software License -(L<http://opensource.org/licenses/apachepl.php>). +The distribution is licensed under the Apache License, Version 2.0 +(L<http://apache.org/licenses/LICENSE-2.0>). + +=item apache_1_1 + +The distribution is licensed under the Apache Software License, Version 1.1 +(L<http://apache.org/licenses/LICENSE-1.1>). =item artistic @@ -580,6 +585,18 @@ used to set C<dist_version>. Setting C<module_name> won't override a C<dist_*> parameter you specify explicitly. +=item needs_compiler + +[version 0.36] + +The C<needs_compiler> parameter indicates whether a compiler is required to +build the distsribution. The default is false, unless XS files are found or +the C<c_source> parameter is set, in which case it is true. If true, +L<ExtUtils::CBuilder> is automatically added to C<build_requires> if needed. + +For a distribution where a compiler is I<optional>, e.g. a dual XS/pure-Perl +distribution, C<needs_compiler> should explicitly be set to a false value. + =item PL_files [version 0.06] @@ -737,6 +754,35 @@ For backward compatibility, you may use the parameter C<scripts> instead of C<script_files>. Please consider this usage deprecated, though it will continue to exist for several version releases. +=item share_dir + +[version 0.36] + +An optional parameter specifying directories of static data files to +be installed as read-only files for use with L<File::ShareDir>. The +C<share_dir> property supports both distribution-level and +module-level share files. + +The default when C<share_dir> is not set is for any files in a F<share> +directory at the top level of the distribution to be installed in +distribution-level share directory. Alternatively, C<share_dir> can be set to +a directory name or an arrayref of directory names containing files to be +installed in the distribution-level share directory. + +If C<share_dir> is a hashref, it may have C<dist> or C<module> keys +providing full flexibility in defining share directories to install. + + share_dir => { + dist => [ 'examples', 'more_examples' ], + module => { + Foo::Templates => ['share/html', 'share/text'], + Foo::Config => 'share/config', + } + } + +If C<share_dir> is set (manually or automatically), then File::ShareDir +will automatically be added to the C<requires> hash. + =item sign [version 0.16] @@ -802,25 +848,23 @@ files in your distribution. [version 0.28] -When called from a directory containing a F<Build.PL> script and a -F<META.yml> file (in other words, the base directory of a -distribution), this method will run the F<Build.PL> and return the -resulting C<Module::Build> object to the caller. Any key-value -arguments given to C<new_from_context()> are essentially like -command line arguments given to the F<Build.PL> script, so for example -you could pass C<< verbose => 1 >> to this method to turn on -verbosity. +When called from a directory containing a F<Build.PL> script (in other words, +the base directory of a distribution), this method will run the F<Build.PL> and +call C<resume()> to return the resulting C<Module::Build> object to the caller. +Any key-value arguments given to C<new_from_context()> are essentially like +command line arguments given to the F<Build.PL> script, so for example you +could pass C<< verbose => 1 >> to this method to turn on verbosity. =item resume() [version 0.03] -You'll probably never call this method directly, it's only called from -the auto-generated C<Build> script. The C<new()> method is only -called once, when the user runs C<perl Build.PL>. Thereafter, when -the user runs C<Build test> or another action, the C<Module::Build> -object is created using the C<resume()> method to re-instantiate with -the settings given earlier to C<new()>. +You'll probably never call this method directly, it's only called from the +auto-generated C<Build> script (and the C<new_from_context> method). The +C<new()> method is only called once, when the user runs C<perl Build.PL>. +Thereafter, when the user runs C<Build test> or another action, the +C<Module::Build> object is created using the C<resume()> method to +re-instantiate with the settings given earlier to C<new()>. =item subclass() @@ -1527,22 +1571,25 @@ Assigning the value C<undef> to an element causes it to be removed. =item prepare_metadata() -[version 0.28] +[version 0.36] -This method is provided for authors to override to customize the -fields of F<META.yml>. It is passed a YAML::Node node object which can -be modified as desired and then returned. E.g. +This method returns a hash reference of metadata that can be used to create a +YAML datastream. It is provided for authors to override or customize the fields +of F<META.yml>. E.g. package My::Builder; use base 'Module::Build'; sub prepare_metadata { my $self = shift; - my $node = $self->SUPER::prepare_metadata( shift ); - $node->{custom_field} = 'foo'; - return $node; + my $data = $self->SUPER::prepare_metadata(); + $data->{custom_field} = 'foo'; + return $data; } +Prior to version 0.36, this method took a YAML::Node as an argument to hold +assembled metadata. + =item prereq_failures() [version 0.11] @@ -1782,6 +1829,10 @@ accessor methods for the following properties: =item build_script() +=item bundle_inc() + +=item bundle_inc_preload() + =item c_source() =item config_dir() @@ -1790,6 +1841,8 @@ accessor methods for the following properties: =item conflicts() +=item cpan_client() + =item create_license() =item create_makefile_pl() @@ -1830,6 +1883,10 @@ accessor methods for the following properties: =item module_name() +=item mymetafile() + +=item needs_compiler() + =item orig_dir() =item perl() @@ -1920,7 +1977,7 @@ modify it under the same terms as Perl itself. =head1 SEE ALSO perl(1), L<Module::Build>(3), L<Module::Build::Authoring>(3), -L<Module::Build::Cookbook>(3), L<ExtUtils::MakeMaker>(3), L<YAML>(3) +L<Module::Build::Cookbook>(3), L<ExtUtils::MakeMaker>(3), L<YAML::Tiny>(3) F<META.yml> Specification: L<http://module-build.sourceforge.net/META-spec-current.html> diff --git a/cpan/Module-Build/lib/Module/Build/Base.pm b/cpan/Module-Build/lib/Module/Build/Base.pm index 531c35487e..abeea2ef0a 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.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; BEGIN { require 5.00503 } @@ -23,6 +23,7 @@ use Text::ParseWords (); use Module::Build::ModuleInfo; use Module::Build::Notes; use Module::Build::Config; +use Module::Build::Version; #################### Constructors ########################### @@ -31,16 +32,37 @@ sub new { $self->{invoked_action} = $self->{action} ||= 'Build_PL'; $self->cull_args(@ARGV); - + die "Too early to specify a build action '$self->{action}'. Do 'Build $self->{action}' instead.\n" if $self->{action} && $self->{action} ne 'Build_PL'; $self->check_manifest; - $self->check_prereq; - $self->check_autofeatures; + $self->auto_require; + if ( $self->check_prereq + $self->check_autofeatures != 2) { + $self->log_warn(<<EOF); + +ERRORS/WARNINGS FOUND IN PREREQUISITES. You may wish to install the versions +of the modules indicated above before proceeding with this installation + +EOF + unless ( + $self->dist_name eq 'Module-Build' || + $ENV{PERL5_CPANPLUS_IS_RUNNING} || $ENV{PERL5_CPAN_IS_RUNNING} + ) { + $self->log_warn( + "Run 'Build installdeps' to install missing prerequisites.\n\n" + ); + } + } + + # record for later use in resume; + $self->{properties}{_added_to_INC} = [ $self->_added_to_INC ]; + + $self->set_bundle_inc; $self->dist_name; $self->dist_version; + $self->_guess_module_name unless $self->module_name; $self->_find_nested_builds; @@ -52,6 +74,8 @@ sub resume { my $self = $package->_construct(@_); $self->read_config; + unshift @INC, @{ $self->{properties}{_added_to_INC} || [] }; + # If someone called Module::Build->current() or # Module::Build->new_from_context() and the correct class to use is # actually a *subclass* of Module::Build, we may need to load that @@ -72,7 +96,7 @@ sub resume { $self->log_warn(" * WARNING: Configuration was initially created with '$self->{properties}{perl}',\n". " but we are now using '$perl'.\n"); } - + $self->cull_args(@ARGV); unless ($self->allow_mb_mismatch) { @@ -82,7 +106,7 @@ sub resume { " or use --allow_mb_mismatch 1 to skip this version check.\n") if $mb_version ne $self->{properties}{mb_version}; } - + $self->{invoked_action} = $self->{action} ||= 'build'; return $self; @@ -90,18 +114,8 @@ sub resume { sub new_from_context { my ($package, %args) = @_; - - # XXX Read the META.yml and see whether we need to run the Build.PL? - - # Run the Build.PL. We use do() rather than run_perl_script() so - # that it runs in this process rather than a subprocess, because we - # need to make sure that the environment is the same during Build.PL - # as it is during resume() (and thereafter). - { - local @ARGV = $package->unparse_args(\%args); - do './Build.PL'; - die $@ if $@; - } + + $package->run_perl_script('Build.PL',[],[$package->unparse_args(\%args)]); return $package->resume; } @@ -497,6 +511,28 @@ sub _discover_perl_interpreter { "in (@paths)\n"; } +# Adapted from IPC::Cmd::can_run() +sub find_command { + my ($self, $command) = @_; + + if( File::Spec->file_name_is_absolute($command) ) { + return $self->_maybe_command($command); + + } else { + for my $dir ( File::Spec->path ) { + my $abs = File::Spec->catfile($dir, $command); + return $abs if $abs = $self->_maybe_command($abs); + } + } +} + +# Copied from ExtUtils::MM_Unix::maybe_command +sub _maybe_command { + my($self,$file) = @_; + return $file if -x $file && ! -d $file; + return; +} + sub _is_interactive { return -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT)) ; # Pipe? } @@ -588,10 +624,18 @@ sub features { } if (my $info = $ph->{auto_features}->access($key)) { - my $failures = $self->prereq_failures($info); - my $disabled = grep( /^(?:\w+_)?(?:requires|conflicts)$/, - keys %$failures ) ? 1 : 0; - return !$disabled; + my $disabled; + for my $type ( @{$self->prereq_action_types} ) { + next if $type eq 'description' || $type eq 'recommends' || ! exists $info->{$type}; + my $prereqs = $info->{$type}; + for my $modname ( sort keys %$prereqs ) { + my $spec = $prereqs->{$modname}; + my $status = $self->check_installed_status($modname, $spec); + if ((!$status->{ok}) xor ($type =~ /conflicts$/)) { return 0; } + if ( ! eval "require $modname; 1" ) { return 0; } + } + } + return 1; } return $ph->{features}->access($key, @_); @@ -614,7 +658,7 @@ BEGIN { *feature = \&features } # Alias sub _mb_feature { my $self = shift; - + if (($self->module_name || '') eq 'Module::Build') { # We're building Module::Build itself, so ...::ConfigData isn't # valid, but $self->features() should be. @@ -625,6 +669,15 @@ sub _mb_feature { } } +sub _warn_mb_feature_deps { + my $self = shift; + my $name = shift; + $self->log_warn( + "The '$name' feature is not available. Please install missing\n" . + "feature dependencies and try again.\n". + $self->_feature_deps_msg($name) . "\n" + ); +} sub add_build_element { my ($self, $elem) = @_; @@ -635,7 +688,7 @@ sub add_build_element { sub ACTION_config_data { my $self = shift; return unless $self->has_config_data; - + my $module_name = $self->module_name or die "The config_data feature requires that 'module_name' be set"; my $notes_name = $module_name . '::ConfigData'; # TODO: Customize name ??? @@ -646,7 +699,7 @@ sub ACTION_config_data { $self->config_file('features') ], $notes_pm); - $self->log_info("Writing config notes to $notes_pm\n"); + $self->log_verbose("Writing config notes to $notes_pm\n"); File::Path::mkpath(File::Basename::dirname($notes_pm)); Module::Build::Notes->write_config_data @@ -661,7 +714,7 @@ sub ACTION_config_data { } ######################################################################## -{ # enclosing these lexicals -- TODO +{ # enclosing these lexicals -- TODO my %valid_properties = ( __PACKAGE__, {} ); my %additive_properties; @@ -681,10 +734,10 @@ sub ACTION_config_data { sub valid_properties_defaults { my %out; - for (reverse shift->_mb_classes) { - @out{ keys %{ $valid_properties{$_} } } = map { + for my $class (reverse shift->_mb_classes) { + @out{ keys %{ $valid_properties{$class} } } = map { $_->() - } values %{ $valid_properties{$_} }; + } values %{ $valid_properties{$class} }; } return \%out; } @@ -710,9 +763,11 @@ sub ACTION_config_data { my %p = @_ == 1 ? ( default => shift ) : @_; my $type = ref $p{default}; - $valid_properties{$class}{$property} = $type eq 'CODE' - ? $p{default} - : sub { $p{default} }; + $valid_properties{$class}{$property} = + $type eq 'CODE' ? $p{default} : + $type eq 'HASH' ? sub { return { %{ $p{default} } } } : + $type eq 'ARRAY'? sub { return [ @{ $p{default} } ] } : + sub { return $p{default} } ; push @{$additive_properties{$class}->{$type}}, $property if $type; @@ -831,12 +886,16 @@ sub _make_accessor { __PACKAGE__->add_property(auto_configure_requires => 1); __PACKAGE__->add_property(blib => 'blib'); __PACKAGE__->add_property(build_class => 'Module::Build'); -__PACKAGE__->add_property(build_elements => [qw(PL support pm xs pod script)]); +__PACKAGE__->add_property(build_elements => [qw(PL support pm xs share_dir pod script)]); __PACKAGE__->add_property(build_script => 'Build'); __PACKAGE__->add_property(build_bat => 0); +__PACKAGE__->add_property(bundle_inc => []); +__PACKAGE__->add_property(bundle_inc_preload => []); __PACKAGE__->add_property(config_dir => '_build'); __PACKAGE__->add_property(include_dirs => []); +__PACKAGE__->add_property(license => 'unknown'); __PACKAGE__->add_property(metafile => 'META.yml'); +__PACKAGE__->add_property(mymetafile => 'MYMETA.yml'); __PACKAGE__->add_property(recurse_into => []); __PACKAGE__->add_property(use_rcfile => 1); __PACKAGE__->add_property(create_packlist => 1); @@ -844,6 +903,7 @@ __PACKAGE__->add_property(allow_mb_mismatch => 0); __PACKAGE__->add_property(config => undef); __PACKAGE__->add_property(test_file_exts => ['.t']); __PACKAGE__->add_property(use_tap_harness => 0); +__PACKAGE__->add_property(cpan_client => 'cpan'); __PACKAGE__->add_property(tap_harness_args => {}); __PACKAGE__->add_property( 'installdirs', @@ -906,10 +966,10 @@ __PACKAGE__->add_property($_) for qw( has_config_data install_base libdoc_dirs - license magic_number mb_version module_name + needs_compiler orig_dir perl pm_files @@ -921,6 +981,7 @@ __PACKAGE__->add_property($_) for qw( recursive_test_files script_files scripts + share_dir sign test_files verbose @@ -993,14 +1054,14 @@ sub subclass { $opts{code} ||= ''; $opts{class} ||= 'MyModuleBuilder'; - + my $filename = File::Spec->catfile($build_dir, 'lib', split '::', $opts{class}) . '.pm'; my $filedir = File::Basename::dirname($filename); - $pack->log_info("Creating custom builder $filename in $filedir\n"); - + $pack->log_verbose("Creating custom builder $filename in $filedir\n"); + File::Path::mkpath($filedir); die "Can't create directory $filedir: $!" unless -d $filedir; - + my $fh = IO::File->new("> $filename") or die "Can't create $filename: $!"; print $fh <<EOF; package $opts{class}; @@ -1010,7 +1071,7 @@ $opts{code} 1; EOF close $fh; - + unshift @INC, File::Spec->catdir(File::Spec->rel2abs($build_dir), 'lib'); eval "use $opts{class}"; die $@ if $@; @@ -1018,16 +1079,43 @@ EOF return $opts{class}; } +sub _guess_module_name { + my $self = shift; + my $p = $self->{properties}; + return if $p->{module_name}; + if ( $p->{dist_version_from} && -e $p->{dist_version_from} ) { + my $mi = Module::Build::ModuleInfo->new_from_file($self->dist_version_from); + $p->{module_name} = $mi->name; + } + else { + my $mod_path = my $mod_name = File::Basename::basename($self->base_dir); + $mod_name =~ s{-}{::}g; + $mod_path =~ s{-}{/}g; + $mod_path .= ".pm"; + if ( -e $mod_path || -e File::Spec->catfile('lib', $mod_path) ) { + $p->{module_name} = $mod_name; + } + else { + $self->log_warn( << 'END_WARN' ); +No 'module_name' was provided and it could not be inferred +from other properties. This will prevent a packlist from +being written for this file. Please set either 'module_name' +or 'dist_version_from' in Build.PL. +END_WARN + } + } +} + sub dist_name { my $self = shift; my $p = $self->{properties}; return $p->{dist_name} if defined $p->{dist_name}; - + die "Can't determine distribution name, must supply either 'dist_name' or 'module_name' parameter" unless $self->module_name; - + ($p->{dist_name} = $self->module_name) =~ s/::/-/g; - + return $p->{dist_name}; } @@ -1069,12 +1157,12 @@ sub _pod_parse { my $p = $self->{properties}; my $member = "dist_$part"; return $p->{$member} if defined $p->{$member}; - + my $docfile = $self->_main_docfile or return; my $fh = IO::File->new($docfile) or return; - + require Module::Build::PodParser; my $parser = Module::Build::PodParser->new(fh => $fh); my $method = "get_$part"; @@ -1109,7 +1197,7 @@ sub config_file { sub read_config { my ($self) = @_; - + my $file = $self->config_file('build_params') or die "Can't find 'build_params' in " . $self->config_dir; my $fh = IO::File->new($file) or die "Can't read '$file': $!"; @@ -1128,7 +1216,7 @@ sub has_config_data { sub _write_data { my ($self, $filename, $data) = @_; - + my $file = $self->config_file($filename); my $fh = IO::File->new("> $file") or die "Can't create '$file': $!"; unless (ref($data)) { # e.g. magicnum @@ -1141,10 +1229,10 @@ sub _write_data { sub write_config { my ($self) = @_; - + File::Path::mkpath($self->{properties}{config_dir}); -d $self->{properties}{config_dir} or die "Can't mkdir $self->{properties}{config_dir}: $!"; - + my @items = @{ $self->prereq_action_types }; $self->_write_data('prereqs', { map { $_, $self->$_() } @items }); $self->_write_data('build_params', [$self->{args}, $self->{config}->values_set, $self->{properties}]); @@ -1155,13 +1243,74 @@ sub write_config { $self->{phash}{$_}->write() foreach qw(notes cleanup features auto_features config_data runtime_params); } +{ + # packfile map -- keys are guts of regular expressions; If they match, + # values are module names corresponding to the packlist + my %packlist_map = ( + '^File::Spec' => 'Cwd', + '^Devel::AssertOS' => 'Devel::CheckOS', + ); + + sub _find_packlist { + my ($self, $inst, $mod) = @_; + my $lookup = $mod; + my $packlist = eval { $inst->packlist($lookup) }; + if ( ! $packlist ) { + # try from packlist_map + while ( my ($re, $new_mod) = each %packlist_map ) { + if ( $mod =~ qr/$re/ ) { + $lookup = $new_mod; + $packlist = eval { $inst->packlist($lookup) }; + last; + } + } + } + return $packlist ? $lookup : undef; + } + + sub set_bundle_inc { + my $self = shift; + + my $bundle_inc = $self->{properties}{bundle_inc}; + my $bundle_inc_preload = $self->{properties}{bundle_inc_preload}; + # We're in author mode if inc::latest is loaded, but not from cwd + return unless inc::latest->can('loaded_modules'); + require ExtUtils::Installed; + # ExtUtils::Installed is buggy about finding additions to default @INC + my $inst = ExtUtils::Installed->new(extra_libs => [@INC]); + my @bundle_list = map { [ $_, 0 ] } inc::latest->loaded_modules; + + # XXX TODO: Need to get ordering of prerequisites correct so they are + # are loaded in the right order. Use an actual tree?! + + while( @bundle_list ) { + my ($mod, $prereq) = @{ shift @bundle_list }; + + # XXX TODO: Append prereqs to list + # skip if core or already in bundle or preload lists + # push @bundle_list, [$_, 1] for prereqs() + + # Locate packlist for bundling + my $lookup = $self->_find_packlist($inst,$mod); + if ( ! $lookup ) { + # XXX Really needs a more helpful error message here + die << "NO_PACKLIST"; +Could not find a packlist for '$mod'. If it's a core module, try +force installing it from CPAN. +NO_PACKLIST + } + else { + push @{ $prereq ? $bundle_inc_preload : $bundle_inc }, $lookup; + } + } + } # sub check_bundling +} + sub check_autofeatures { my ($self) = @_; my $features = $self->auto_features; - - return unless %$features; - $self->log_info("Checking features:\n"); + return 1 unless %$features; # TODO refactor into ::Util my $longest = sub { @@ -1177,30 +1326,117 @@ sub check_autofeatures { }; my $max_name_len = length($longest->(keys %$features)); - while (my ($name, $info) = each %$features) { - $self->log_info(" $name" . '.' x ($max_name_len - length($name) + 4)); + my ($num_disabled, $log_text) = (0, "\nChecking optional features...\n"); + for my $name ( sort keys %$features ) { + $log_text .= $self->_feature_deps_msg($name, $max_name_len); + } + + $num_disabled = () = $log_text =~ /disabled/g; + + # warn user if features disabled + if ( $num_disabled ) { + $self->log_warn( $log_text ); + return 0; + } + else { + $self->log_verbose( $log_text ); + return 1; + } +} + +sub _feature_deps_msg { + my ($self, $name, $max_name_len) = @_; + $max_name_len ||= length $name; + my $features = $self->auto_features; + my $info = $features->{$name}; + my $feature_text = "$name" . '.' x ($max_name_len - length($name) + 4); + my ($log_text, $disabled) = ('',''); if ( my $failures = $self->prereq_failures($info) ) { - my $disabled = grep( /^(?:\w+_)?(?:requires|conflicts)$/, - keys %$failures ) ? 1 : 0; - $self->log_info( $disabled ? "disabled\n" : "enabled\n" ); - - my $log_text; - while (my ($type, $prereqs) = each %$failures) { - while (my ($module, $status) = each %$prereqs) { - my $required = - ($type =~ /^(?:\w+_)?(?:requires|conflicts)$/) ? 1 : 0; - my $prefix = ($required) ? '-' : '*'; - $log_text .= " $prefix $status->{message}\n"; - } + $disabled = grep( /^(?:\w+_)?(?:requires|conflicts)$/, + keys %$failures ) ? 1 : 0; + $feature_text .= $disabled ? "disabled\n" : "enabled\n"; + + for my $type ( @{ $self->prereq_action_types } ) { + next unless exists $failures->{$type}; + $feature_text .= " $type:\n"; + my $prereqs = $failures->{$type}; + for my $module ( sort keys %$prereqs ) { + my $status = $prereqs->{$module}; + my $required = + ($type =~ /^(?:\w+_)?(?:requires|conflicts)$/) ? 1 : 0; + my $prefix = ($required) ? '!' : '*'; + $feature_text .= " $prefix $status->{message}\n"; + } } - $self->log_warn("$log_text") unless $self->quiet; } else { - $self->log_info("enabled\n"); + $feature_text .= "enabled\n"; + } + $log_text .= $feature_text if $disabled || $self->verbose; + return $log_text; +} + +# Automatically detect and add prerequisites based on configuration +sub auto_require { + my ($self) = @_; + my $p = $self->{properties}; + + # add current Module::Build to configure_requires if there + # isn't one already specified (but not ourself, so we're not circular) + if ( $self->dist_name ne 'Module-Build' + && $self->auto_configure_requires + && ! exists $p->{configure_requires}{'Module::Build'} + ) { + (my $ver = $VERSION) =~ s/^(\d+\.\d\d).*$/$1/; # last major release only + $self->_add_prereq('configure_requires', 'Module::Build', $ver); + } + + # if we're in author mode, add inc::latest modules to + # configure_requires if not already set. If we're not in author mode + # then configure_requires will have been satisfied, or we'll just + # live with what we've bundled + if ( inc::latest->can('loaded_module') ) { + for my $mod ( inc::latest->loaded_modules ) { + next if exists $p->{configure_requires}{$mod}; + $self->_add_prereq('configure_requires', $mod, $mod->VERSION); } } - $self->log_warn("\n") unless $self->quiet; + # 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; + if ( ! defined $p->{needs_compiler} ) { + $self->needs_compiler( keys %$xs_files || defined $self->c_source ); + } + if ($self->needs_compiler) { + $self->_add_prereq('build_requires', 'ExtUtils::CBuilder', 0); + if ( ! $self->have_c_compiler ) { + $self->log_warn(<<'EOM'); +Warning: ExtUtils::CBuilder not installed or no compiler detected +Proceeding with configuration, but compilation may fail during Build + +EOM + } + } + + # If using share_dir, require File::ShareDir + if ( $self->share_dir ) { + $self->_add_prereq( 'requires', 'File::ShareDir', '1.00' ); + } + + return; +} + +sub _add_prereq { + my ($self, $type, $module, $version) = @_; + my $p = $self->{properties}; + $version = 0 unless defined $version; + if ( exists $p->{$type}{$module} ) { + return if $self->compare_versions( $version, '<=', $p->{$type}{$module} ); + } + $self->log_verbose("Adding to $type\: $module => $version\n"); + $p->{$type}{$module} = $version; + return 1; } sub prereq_failures { @@ -1213,7 +1449,8 @@ sub prereq_failures { foreach my $type (@types) { my $prereqs = $info->{$type}; - while ( my ($modname, $spec) = each %$prereqs ) { + for my $modname ( keys %$prereqs ) { + my $spec = $prereqs->{$modname}; my $status = $self->check_installed_status($modname, $spec); if ($type =~ /^(?:\w+_)?conflicts$/) { @@ -1224,7 +1461,7 @@ sub prereq_failures { } elsif ($type =~ /^(?:\w+_)?recommends$/) { next if $status->{ok}; $status->{message} = (!ref($status->{have}) && $status->{have} eq '<none>' - ? "Optional prerequisite $modname is not installed" + ? "$modname is not installed" : "$modname ($status->{have}) is installed, but we prefer to have $spec"); } else { next if $status->{ok}; @@ -1253,44 +1490,29 @@ sub _enum_prereqs { sub check_prereq { my $self = shift; - # If we have XS files, make sure we can process them. - my $xs_files = $self->find_xs_files; - if (keys %$xs_files && !$self->_mb_feature('C_support')) { - $self->log_warn("Warning: this distribution contains XS files, ". - "but Module::Build is not configured with C_support. ". - "Please install ExtUtils::CBuilder to enable C_support.\n"); - } - # Check to see if there are any prereqs to check my $info = $self->_enum_prereqs; return 1 unless $info; - $self->log_info("Checking prerequisites...\n"); + my $log_text = "Checking prerequisites...\n"; my $failures = $self->prereq_failures($info); if ( $failures ) { - - while (my ($type, $prereqs) = each %$failures) { - while (my ($module, $status) = each %$prereqs) { - my $prefix = ($type =~ /^(?:\w+_)?recommends$/) ? '*' : '- ERROR:'; - $self->log_warn(" $prefix $status->{message}\n"); + $self->log_warn($log_text); + for my $type ( @{ $self->prereq_action_types } ) { + my $prereqs = $failures->{$type}; + $self->log_warn(" ${type}:\n") if keys %$prereqs; + for my $module ( sort keys %$prereqs ) { + my $status = $prereqs->{$module}; + my $prefix = ($type =~ /^(?:\w+_)?recommends$/) ? "* " : "! "; + $self->log_warn(" $prefix $status->{message}\n"); } } - - $self->log_warn(<<EOF); - -ERRORS/WARNINGS FOUND IN PREREQUISITES. You may wish to install the versions -of the modules indicated above before proceeding with this installation - -EOF return 0; - } else { - - $self->log_info("Looks good\n\n"); + $self->log_verbose($log_text . "Looks good\n\n"); return 1; - } } @@ -1323,44 +1545,44 @@ sub _parse_conditions { sub check_installed_status { my ($self, $modname, $spec) = @_; my %status = (need => $spec); - + if ($modname eq 'perl') { $status{have} = $self->perl_version; - + } elsif (eval { no strict; $status{have} = ${"${modname}::VERSION"} }) { # Don't try to load if it's already loaded - + } else { my $pm_info = Module::Build::ModuleInfo->new_from_module( $modname ); unless (defined( $pm_info )) { @status{ qw(have message) } = ('<none>', "$modname is not installed"); return \%status; } - + $status{have} = $pm_info->version(); if ($spec and !defined($status{have})) { @status{ qw(have message) } = (undef, "Couldn't find a \$VERSION in prerequisite $modname"); return \%status; } } - + my @conditions = $self->_parse_conditions($spec); - + foreach (@conditions) { my ($op, $version) = /^\s* (<=?|>=?|==|!=) \s* ([\w.]+) \s*$/x or die "Invalid prerequisite condition '$_' for $modname"; - + $version = $self->perl_version_to_float($version) if $modname eq 'perl'; - + next if $op eq '>=' and !$version; # Module doesn't have to actually define a $VERSION - + unless ($self->compare_versions( $status{have}, $op, $version )) { $status{message} = "$modname ($status{have}) is installed, but we need version $op $version"; return \%status; } } - + $status{ok} = 1; return \%status; } @@ -1368,7 +1590,7 @@ sub check_installed_status { sub compare_versions { my $self = shift; my ($v1, $op, $v2) = @_; - $v1 = Module::Build::Version->new($v1) + $v1 = Module::Build::Version->new($v1) unless UNIVERSAL::isa($v1,'Module::Build::Version'); my $eval_str = "\$v1 $op \$v2"; @@ -1381,14 +1603,14 @@ sub compare_versions { # I wish I could set $! to a string, but I can't, so I use $@ sub check_installed_version { my ($self, $modname, $spec) = @_; - + my $status = $self->check_installed_status($modname, $spec); - + if ($status->{ok}) { return $status->{have} if $status->{have} and "$status->{have}" ne '<none>'; return '0 but true'; } - + $@ = $status->{message}; return 0; } @@ -1430,23 +1652,23 @@ sub _added_to_INC { sub _default_INC { my $self = shift; return @default_inc if @default_inc; - + local $ENV{PERL5LIB}; # this is not considered part of the default. - + my $perl = ref($self) ? $self->perl : $self->find_perl_interpreter; - + my @inc = $self->_backticks($perl, '-le', 'print for @INC'); chomp @inc; - + return @default_inc = @inc; } } sub print_build_script { my ($self, $fh) = @_; - + my $build_package = $self->build_class; - + my $closedata=""; my %q = map {$_, $self->$_()} qw(config_dir base_dir); @@ -1532,20 +1754,29 @@ EOF sub create_build_script { my ($self) = @_; $self->write_config; - + + # Create MYMETA.yml + my $mymetafile = $self->mymetafile; + if ( $self->delete_filetree($mymetafile) ) { + $self->log_verbose("Removed previous '$mymetafile'\n"); + } + $self->log_info("Creating new '$mymetafile' with configuration results\n"); + $self->write_metafile( $mymetafile, $self->prepare_metadata( fatal => 0 ) ); + + # Create Build my ($build_script, $dist_name, $dist_version) = map $self->$_(), qw(build_script dist_name dist_version); - + if ( $self->delete_filetree($build_script) ) { - $self->log_info("Removed previous script '$build_script'\n\n"); + $self->log_verbose("Removed previous script '$build_script'\n"); } $self->log_info("Creating new '$build_script' script for ", - "'$dist_name' version '$dist_version'\n"); + "'$dist_name' version '$dist_version'\n"); my $fh = IO::File->new(">$build_script") or die "Can't create '$build_script': $!"; $self->print_build_script($fh); close $fh; - + $self->make_executable($build_script); return 1; @@ -1554,20 +1785,20 @@ sub create_build_script { sub check_manifest { my $self = shift; return unless -e 'MANIFEST'; - + # Stolen nearly verbatim from MakeMaker. But ExtUtils::Manifest # could easily be re-written into a modern Perl dialect. require ExtUtils::Manifest; # ExtUtils::Manifest is not warnings clean. local ($^W, $ExtUtils::Manifest::Quiet) = (0,1); - - $self->log_info("Checking whether your kit is complete...\n"); + + $self->log_verbose("Checking whether your kit is complete...\n"); if (my @missed = ExtUtils::Manifest::manicheck()) { $self->log_warn("WARNING: the following files are missing in your kit:\n", "\t", join("\n\t", @missed), "\n", "Please inform the author.\n\n"); } else { - $self->log_info("Looks good\n\n"); + $self->log_verbose("Looks good\n\n"); } } @@ -1692,6 +1923,7 @@ sub _translate_option { use_rcfile use_tap_harness tap_harness_args + cpan_client ); # normalize only selected option names return $opt; @@ -1824,7 +2056,7 @@ sub read_args { require Module::Build::Compat; %args = (%args, Module::Build::Compat->makefile_to_build_macros); } - + return \%args, $action; } @@ -1977,7 +2209,10 @@ sub merge_args { sub cull_args { my $self = shift; - my ($args, $action) = $self->read_args(@_); + my @arg_list = @_; + unshift @arg_list, $self->split_like_shell($ENV{PERL_MB_OPT}) + if $ENV{PERL_MB_OPT}; + my ($args, $action) = $self->read_args(@arg_list); $self->merge_args($action, %$args); $self->merge_modulebuildrc( $action, %$args ); } @@ -1986,7 +2221,7 @@ sub super_classes { my ($self, $class, $seen) = @_; $class ||= ref($self) || $self; $seen ||= {}; - + no strict 'refs'; my @super = grep {not $seen->{$_}++} $class, @{ $class . '::ISA' }; return @super, map {$self->super_classes($_,$seen)} @super; @@ -1997,7 +2232,7 @@ sub known_actions { my %actions; no strict 'refs'; - + foreach my $class ($self->super_classes) { foreach ( keys %{ $class . '::' } ) { $actions{$1}++ if /^ACTION_(\w+)/; @@ -2073,7 +2308,7 @@ sub get_action_docs { $@ = "Couldn't find any docs for action '$action'"; return; } - + return join '', @docs; } @@ -2147,7 +2382,7 @@ sub prereq_report { sub ACTION_help { my ($self) = @_; my $actions = $self->known_actions; - + if (@{$self->{args}{ARGV}}) { my $msg = eval {$self->get_action_docs($self->{args}{ARGV}[0], $actions)}; print $@ ? "$@\n" : $msg; @@ -2158,10 +2393,10 @@ sub ACTION_help { Usage: $0 <action> arg1=value arg2=value ... Example: $0 test verbose=1 - + Actions defined: EOF - + print $self->_action_listing($actions); print "\nRun `Build help <action>` for details on an individual action.\n"; @@ -2174,7 +2409,7 @@ sub _action_listing { # Flow down columns, not across rows my @actions = sort keys %$actions; @actions = map $actions[($_ + ($_ % 2) * @actions) / 2], 0..$#actions; - + my $out = ''; while (my ($one, $two) = splice @actions, 0, 2) { $out .= sprintf(" %-12s %-12s\n", $one, $two||''); @@ -2184,7 +2419,7 @@ sub _action_listing { sub ACTION_retest { my ($self) = @_; - + # Protect others against our @INC changes local @INC = @INC; @@ -2232,7 +2467,7 @@ sub generic_test { my $p = $self->{properties}; my @types = ( - (exists($args{type}) ? $args{type} : ()), + (exists($args{type}) ? $args{type} : ()), (exists($args{types}) ? @{$args{types}} : ()), ); @types or croak "need some types of tests to check"; @@ -2265,6 +2500,8 @@ sub generic_test { $self->do_tests; } +# Test::Harness dies on failure but TAP::Harness does not, so we must +# die if running under TAP::Harness sub do_tests { my $self = shift; @@ -2273,7 +2510,10 @@ sub do_tests { if(@$tests) { my $args = $self->tap_harness_args; if($self->use_tap_harness or ($args and %$args)) { - $self->run_tap_harness($tests); + my $aggregate = $self->run_tap_harness($tests); + if ( $aggregate->has_errors ) { + die "Errors in testing. Cannot continue.\n"; + } } else { $self->run_test_harness($tests); @@ -2293,12 +2533,14 @@ sub run_tap_harness { # TODO allow the test @INC to be set via our API? - TAP::Harness->new({ + my $aggregate = TAP::Harness->new({ lib => [@INC], verbosity => $self->{properties}{verbose}, switches => [ $self->harness_switches ], %{ $self->tap_harness_args }, })->runtests(@$tests); + + return $aggregate; } sub run_test_harness { @@ -2382,14 +2624,14 @@ sub ACTION_testcover { my $pm_files = $self->rscan_dir (File::Spec->catdir($self->blib, 'lib'), file_qr('\.pm$') ); my $cover_files = $self->rscan_dir('cover_db', sub {-f $_ and not /\.html$/}); - + $self->do_system(qw(cover -delete)) unless $self->up_to_date($pm_files, $cover_files) && $self->up_to_date($self->test_files, $cover_files); } - local $Test::Harness::switches = - local $Test::Harness::Switches = + local $Test::Harness::switches = + local $Test::Harness::Switches = local $ENV{HARNESS_PERL_SWITCHES} = "-MDevel::Cover"; $self->depends_on('test'); @@ -2398,17 +2640,17 @@ sub ACTION_testcover { sub ACTION_code { my ($self) = @_; - + # All installable stuff gets created in blib/ . # Create blib/arch to keep blib.pm happy my $blib = $self->blib; $self->add_to_cleanup($blib); File::Path::mkpath( File::Spec->catdir($blib, 'arch') ); - + if (my $split = $self->autosplit) { $self->autosplit_file($_, $blib) for ref($split) ? @$split : ($split); } - + foreach my $element (@{$self->build_elements}) { my $method = "process_${element}_files"; $method = "process_files_by_extension" unless $self->can($method); @@ -2420,16 +2662,17 @@ sub ACTION_code { sub ACTION_build { my $self = shift; + $self->log_info("Building " . $self->dist_name . "\n"); $self->depends_on('code'); $self->depends_on('docs'); } sub process_files_by_extension { my ($self, $ext) = @_; - + my $method = "find_${ext}_files"; my $files = $self->can($method) ? $self->$method() : $self->_find_file_by_type($ext, 'lib'); - + while (my ($file, $dest) = each %$files) { $self->copy_if_modified(from => $file, to => File::Spec->catfile($self->blib, $dest) ); } @@ -2439,19 +2682,70 @@ sub process_support_files { my $self = shift; my $p = $self->{properties}; return unless $p->{c_source}; - + push @{$p->{include_dirs}}, $p->{c_source}; - - my $files = $self->rscan_dir($p->{c_source}, file_qr('\.c(pp)?$')); + + my $files = $self->rscan_dir($p->{c_source}, file_qr('\.c(c|p|pp|xx|\+\+)?$')); foreach my $file (@$files) { push @{$p->{objects}}, $self->compile_c($file); } } +sub process_share_dir_files { + my $self = shift; + my $files = $self->_find_share_dir_files; + return unless $files; + + # root for all File::ShareDir paths + my $share_prefix = File::Spec->catdir($self->blib, qw/lib auto share/); + + # copy all share files to blib + while (my ($file, $dest) = each %$files) { + $self->copy_if_modified( + from => $file, to => File::Spec->catfile( $share_prefix, $dest ) + ); + } +} + +sub _find_share_dir_files { + my $self = shift; + my $share_dir = $self->share_dir; + return unless $share_dir; + + my @file_map; + if ( $share_dir->{dist} ) { + my $prefix = File::Spec->catdir( "dist", $self->dist_name ); + push @file_map, $self->_share_dir_map( $prefix, $share_dir->{dist} ); + } + + if ( $share_dir->{module} ) { + for my $mod ( keys %{ $share_dir->{module} } ) { + (my $altmod = $mod) =~ s{::}{-}g; + my $prefix = File::Spec->catdir("module", $altmod); + push @file_map, $self->_share_dir_map($prefix, $share_dir->{module}{$mod}); + } + } + + return { @file_map }; +} + +sub _share_dir_map { + my ($self, $prefix, $list) = @_; + my %files; + for my $dir ( @$list ) { + for my $f ( @{ $self->rscan_dir( $dir, sub {-f} )} ) { + $files{File::Spec->canonpath($f)} = File::Spec->catfile( + $prefix, File::Spec->abs2rel( $f, $dir ) + ); + } + } + return %files; +} + sub process_PL_files { my ($self) = @_; my $files = $self->find_PL_files; - + while (my ($file, $to) = each %$files) { unless ($self->up_to_date( $file, $to )) { $self->run_perl_script($file, [], [@$to]) or die "$file failed"; @@ -2482,7 +2776,7 @@ sub process_script_files { my $script_dir = File::Spec->catdir($self->blib, 'script'); File::Path::mkpath( $script_dir ); - + foreach my $file (keys %$files) { my $result = $self->copy_if_modified($file, $script_dir, 'flatten') or next; $self->fix_shebang_line($result) unless $self->is_vmsish; @@ -2494,7 +2788,7 @@ sub find_PL_files { my $self = shift; if (my $files = $self->{properties}{PL_files}) { # 'PL_files' is given as a Unix file spec, so we localize_file_path(). - + if (UNIVERSAL::isa($files, 'ARRAY')) { return { map {$_, [/^(.*)\.PL$/]} map $self->localize_file_path($_), @@ -2512,7 +2806,7 @@ sub find_PL_files { die "'PL_files' must be a hash reference or array reference"; } } - + return unless -d 'lib'; return { map {$_, [/^(.*)\.PL$/i ]} @{ $self->rscan_dir('lib', file_qr('\.PL$')) } }; @@ -2529,7 +2823,7 @@ sub find_script_files { # meaningless, but we preserve if present. return { map {$self->localize_file_path($_), $files->{$_}} keys %$files }; } - + # No default location for script files return {}; } @@ -2543,10 +2837,10 @@ sub find_test_files { $files = [map { -d $_ ? $self->expand_test_dir($_) : $_ } map glob, $self->split_like_shell($files)]; - + # Always given as a Unix file spec. return [ map $self->localize_file_path($_), @$files ]; - + } else { # Find all possible tests in t/ or test.pl my @tests; @@ -2558,12 +2852,12 @@ sub find_test_files { sub _find_file_by_type { my ($self, $type, $dir) = @_; - + if (my $files = $self->{properties}{"${type}_files"}) { # Always given as a Unix file spec return { map $self->localize_file_path($_), %$files }; } - + return {} unless -d $dir; return { map {$_, $_} map $self->localize_file_path($_), @@ -2584,48 +2878,48 @@ sub localize_dir_path { sub fix_shebang_line { # Adapted from fixin() in ExtUtils::MM_Unix 1.35 my ($self, @files) = @_; my $c = ref($self) ? $self->{config} : 'Module::Build::Config'; - + my ($does_shbang) = $c->get('sharpbang') =~ /^\s*\#\!/; for my $file (@files) { my $FIXIN = IO::File->new($file) or die "Can't process '$file': $!"; local $/ = "\n"; chomp(my $line = <$FIXIN>); next unless $line =~ s/^\s*\#!\s*//; # Not a shbang file. - + my ($cmd, $arg) = (split(' ', $line, 2), ''); next unless $cmd =~ /perl/i; my $interpreter = $self->{properties}{perl}; - + $self->log_verbose("Changing sharpbang in $file to $interpreter"); my $shb = ''; $shb .= $c->get('sharpbang')."$interpreter $arg\n" if $does_shbang; - + # I'm not smart enough to know the ramifications of changing the # embedded newlines here to \n, so I leave 'em in. $shb .= qq{ eval 'exec $interpreter $arg -S \$0 \${1+"\$\@"}' if 0; # not running under some shell } unless $self->is_windowsish; # this won't work on win32, so don't - + my $FIXOUT = IO::File->new(">$file.new") or die "Can't create new $file: $!\n"; - + # Print out the new #! line (or equivalent). local $\; undef $/; # Was localized above print $FIXOUT $shb, <$FIXIN>; close $FIXIN; close $FIXOUT; - + rename($file, "$file.bak") or die "Can't rename $file to $file.bak: $!"; - + rename("$file.new", $file) or die "Can't rename $file.new to $file: $!"; - + $self->delete_filetree("$file.bak") or $self->log_warn("Couldn't clean up $file.bak, leaving it there"); - + $self->do_system($c->get('eunicefix'), $file) if $c->get('eunicefix') ne ':'; } } @@ -2634,7 +2928,7 @@ eval 'exec $interpreter $arg -S \$0 \${1+"\$\@"}' sub ACTION_testpod { my $self = shift; $self->depends_on('docs'); - + eval q{use Test::Pod 0.95; 1} or die "The 'testpod' action requires Test::Pod version 0.95"; @@ -2655,7 +2949,7 @@ sub ACTION_testpodcoverage { my $self = shift; $self->depends_on('docs'); - + eval q{use Test::Pod::Coverage 1.00; 1} or die "The 'testpodcoverage' action requires ", "Test::Pod::Coverage version 1.00"; @@ -2738,9 +3032,9 @@ sub manify_bin_pods { $self->config( 'man1ext' ); my $outfile = File::Spec->catfile($mandir, $manpage); next if $self->up_to_date( $file, $outfile ); - $self->log_info("Manifying $file -> $outfile\n"); + $self->log_verbose("Manifying $file -> $outfile\n"); eval { $parser->parse_from_file( $file, $outfile ); 1 } - or $self->log_warn("Error creating '$outfile': $@\n"); + or $self->log_warn("Error creating '$outfile': $@\n"); $files->{$file} = $outfile; } } @@ -2763,9 +3057,9 @@ sub manify_lib_pods { $self->config( 'man3ext' ); my $outfile = File::Spec->catfile( $mandir, $manpage); next if $self->up_to_date( $file, $outfile ); - $self->log_info("Manifying $file -> $outfile\n"); + $self->log_verbose("Manifying $file -> $outfile\n"); eval { $parser->parse_from_file( $file, $outfile ); 1 } - or $self->log_warn("Error creating '$outfile': $@\n"); + or $self->log_warn("Error creating '$outfile': $@\n"); $files->{$file} = $outfile; } } @@ -2790,12 +3084,12 @@ sub _find_pods { sub contains_pod { my ($self, $file) = @_; return '' unless -T $file; # Only look at text files - + my $fh = IO::File->new( $file ) or die "Can't open $file: $!"; while (my $line = <$fh>) { return 1 if $line =~ /^\=(?:head|pod|item)/; } - + return ''; } @@ -2808,7 +3102,7 @@ sub ACTION_html { foreach my $type ( qw(bin lib) ) { my $files = $self->_find_pods( $self->{properties}{"${type}doc_dirs"}, - exclude => + exclude => [ file_qr('\.(?:bat|com|html)$') ] ); next unless %$files; @@ -2897,9 +3191,9 @@ sub htmlify_pods { push( @opts, "--css=$path2root/" . $self->html_css) if $self->html_css; } - $self->log_info("HTMLifying $infile -> $outfile\n"); + $self->log_verbose("HTMLifying $infile -> $outfile\n"); $self->log_verbose("pod2html @opts\n"); - eval { Pod::Html::pod2html(@opts); 1 } + eval { Pod::Html::pod2html(@opts); 1 } or $self->log_warn("pod2html @opts failed: $@"); } @@ -2919,10 +3213,10 @@ sub man3page_name { my $self = shift; my ($vol, $dirs, $file) = File::Spec->splitpath( shift ); my @dirs = File::Spec->splitdir( File::Spec->canonpath($dirs) ); - + # Remove known exts from the base name $file =~ s/\.p(?:od|m|l)\z//i; - + return join( $self->manpage_separator, @dirs, $file ); } @@ -2942,7 +3236,7 @@ sub ACTION_diff { my @flags = @{$self->{args}{ARGV}}; @flags = $self->split_like_shell($self->{args}{flags} || '') unless @flags; - + my $installmap = $self->install_map; delete $installmap->{read}; delete $installmap->{write}; @@ -2952,22 +3246,22 @@ sub ACTION_diff { while (my $localdir = each %$installmap) { my @localparts = File::Spec->splitdir($localdir); my $files = $self->rscan_dir($localdir, sub {-f}); - + foreach my $file (@$files) { my @parts = File::Spec->splitdir($file); @parts = @parts[@localparts .. $#parts]; # Get rid of blib/lib or similar - + my $installed = Module::Build::ModuleInfo->find_module_by_name( join('::', @parts), \@myINC ); if (not $installed) { print "Only in lib: $file\n"; next; } - + my $status = File::Compare::compare($installed, $file); next if $status == 0; # Files are the same die "Can't compare $installed and $file: $!" if $status == -1; - + if ($file =~ $text_suffix) { $self->do_system('diff', @flags, $installed, $file); } else { @@ -2985,7 +3279,7 @@ sub ACTION_install { my ($self) = @_; require ExtUtils::Install; $self->depends_on('build'); - ExtUtils::Install::install($self->install_map, !$self->quiet, 0, $self->{args}{uninst}||0); + ExtUtils::Install::install($self->install_map, $self->verbose, 0, $self->{args}{uninst}||0); } sub ACTION_fakeinstall { @@ -3005,19 +3299,74 @@ sub ACTION_fakeinstall { sub ACTION_versioninstall { my ($self) = @_; - + die "You must have only.pm 0.25 or greater installed for this operation: $@\n" unless eval { require only; 'only'->VERSION(0.25); 1 }; - + $self->depends_on('build'); - + my %onlyargs = map {exists($self->{args}{$_}) ? ($_ => $self->{args}{$_}) : ()} qw(version versionlib); only::install::install(%onlyargs); } +sub ACTION_installdeps { + my ($self) = @_; + + # XXX include feature prerequisites as optional prereqs? + + my $info = $self->_enum_prereqs; + if (! $info ) { + $self->log_info( "No prerequisites detected\n" ); + return; + } + + my $failures = $self->prereq_failures($info); + if ( ! $failures ) { + $self->log_info( "All prerequisites satisfied\n" ); + return; + } + + my @install; + while (my ($type, $prereqs) = each %$failures) { + if($type =~ m/^(?:\w+_)?requires$/) { + push(@install, keys %$prereqs); + next; + } + $self->log_info("Checking optional dependencies:\n"); + while (my ($module, $status) = each %$prereqs) { + push(@install, $module) if($self->y_n("Install $module?", 'y')); + } + } + + return unless @install; + + my ($command, @opts) = $self->split_like_shell($self->cpan_client); + + # relative command should be relative to our active Perl + # so we need to locate that command + if ( ! File::Spec->file_name_is_absolute( $command ) ) { + my @bindirs = File::Basename::dirname($self->perl); + push @bindirs, map {$self->config->{"install${_}bin"}} '','site','vendor'; + for my $d ( @bindirs ) { + my $abs_cmd = $self->find_command(File::Spec->catfile( $d, $command )); + if ( defined $abs_cmd ) { + $command = $abs_cmd; + last; + } + } + } + + if ( ! -x $command ) { + die "cpan_client '$command' is not executable\n"; + } + + $self->do_system($command, @opts, @install); +} + sub ACTION_clean { my ($self) = @_; + $self->log_info("Cleaning up build files\n"); foreach my $item (map glob($_), $self->cleanup) { $self->delete_filetree($item); } @@ -3026,11 +3375,15 @@ sub ACTION_clean { sub ACTION_realclean { my ($self) = @_; $self->depends_on('clean'); - $self->delete_filetree($self->config_dir, $self->build_script); + $self->log_info("Cleaning up configuration files\n"); + $self->delete_filetree( + $self->config_dir, $self->mymetafile, $self->build_script + ); } sub ACTION_ppd { my ($self) = @_; + require Module::Build::PPMMaker; my $ppd = Module::Build::PPMMaker->new(); my $file = $ppd->make_ppd(%{$self->{args}}, build => $self); @@ -3104,7 +3457,7 @@ sub ACTION_pardist { ); return(); } - + $self->depends_on( 'build' ); return PAR::Dist::blib_to_par( @@ -3115,11 +3468,11 @@ sub ACTION_pardist { sub ACTION_dist { my ($self) = @_; - + $self->depends_on('distdir'); - + my $dist_dir = $self->dist_dir; - + $self->make_tarball($dist_dir); $self->delete_filetree($dist_dir); } @@ -3127,6 +3480,8 @@ sub ACTION_dist { sub ACTION_distcheck { my ($self) = @_; + $self->_check_manifest_skip; + require ExtUtils::Manifest; local $^W; # ExtUtils::Manifest is not warnings clean. my ($missing, $extra) = ExtUtils::Manifest::fullcheck(); @@ -3141,6 +3496,25 @@ sub ACTION_distcheck { } } +sub _check_mymeta_skip { + my $self = shift; + my $maniskip = shift || 'MANIFEST.SKIP'; + + require ExtUtils::Manifest; + local $^W; # ExtUtils::Manifest is not warnings clean. + + # older ExtUtils::Manifest had a private _maniskip + my $skip_factory = ExtUtils::Manifest->can('maniskip') + || ExtUtils::Manifest->can('_maniskip'); + + my $mymetafile = $self->mymetafile; + # we can't check it, just add it anyway to be safe + unless ( $skip_factory && $skip_factory->($maniskip)->($mymetafile) ) { + $self->log_warn("File '$maniskip' does not include '$mymetafile'. Adding it now.\n"); + $self->_append_maniskip("^$mymetafile\$", $maniskip); + } +} + sub _add_to_manifest { my ($self, $manifest, $lines) = @_; $lines = [$lines] unless ref $lines; @@ -3153,7 +3527,7 @@ sub _add_to_manifest { my $mode = (stat $manifest)[2]; chmod($mode | oct(222), $manifest) or die "Can't make $manifest writable: $!"; - + my $fh = IO::File->new("< $manifest") or die "Can't read $manifest: $!"; my $last_line = (<$fh>)[-1] || "\n"; my $has_newline = $last_line =~ /\n$/; @@ -3165,7 +3539,7 @@ sub _add_to_manifest { close $fh; chmod($mode, $manifest); - $self->log_info(map "Added to $manifest: $_\n", @$lines); + $self->log_verbose(map "Added to $manifest: $_\n", @$lines); } sub _sign_dir { @@ -3175,16 +3549,16 @@ sub _sign_dir { $self->log_warn("Couldn't load Module::Signature for 'distsign' action:\n $@\n"); return; } - + # Add SIGNATURE to the MANIFEST { my $manifest = File::Spec->catfile($dir, 'MANIFEST'); die "Signing a distribution requires a MANIFEST file" unless -e $manifest; $self->_add_to_manifest($manifest, "SIGNATURE Added here by Module::Build"); } - + # Would be nice if Module::Signature took a directory argument. - + $self->_do_in_dir($dir, sub {local $Module::Signature::Quiet = 1; Module::Signature::sign()}); } @@ -3210,7 +3584,7 @@ sub ACTION_distsign { sub ACTION_skipcheck { my ($self) = @_; - + require ExtUtils::Manifest; local $^W; # ExtUtils::Manifest is not warnings clean. ExtUtils::Manifest::skipcheck(); @@ -3218,7 +3592,7 @@ sub ACTION_skipcheck { sub ACTION_distclean { my ($self) = @_; - + $self->depends_on('realclean'); $self->depends_on('distcheck'); } @@ -3235,6 +3609,11 @@ sub do_create_license { my $self = shift; $self->log_info("Creating LICENSE file\n"); + if ( ! $self->_mb_feature('license_creation') ) { + $self->_warn_mb_feature_deps('license_creation'); + die "Aborting.\n"; + } + my $l = $self->license or die "No license specified"; @@ -3243,7 +3622,7 @@ sub do_create_license { my $class = "Software::License::$key"; eval "use $class; 1" - or die "Can't load Software::License to create LICENSE file: $@"; + or die "Can't load Software::License::$key to create LICENSE file: $@"; $self->delete_filetree('LICENSE'); @@ -3270,7 +3649,9 @@ EOF return; } - if ( eval {require Pod::Readme; 1} ) { + # work around some odd Pod::Readme->new() failures in test reports by + # confirming that new() is available + if ( eval {require Pod::Readme; Pod::Readme->can('new') } ) { $self->log_info("Creating README using Pod::Readme\n"); my $parser = Pod::Readme->new; @@ -3326,29 +3707,48 @@ sub _main_docfile { } } +sub do_create_bundle_inc { + my $self = shift; + my $dist_inc = File::Spec->catdir( $self->dist_dir, 'inc' ); + require inc::latest; + inc::latest->write($dist_inc, @{$self->bundle_inc_preload}); + inc::latest->bundle_module($_, $dist_inc) for @{$self->bundle_inc}; + return 1; +} + sub ACTION_distdir { my ($self) = @_; + if ( @{$self->bundle_inc} && ! $self->_mb_feature('inc_bundling_support') ) { + $self->_warn_mb_feature_deps('inc_bundling_support'); + die "Aborting.\n"; + } + $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"; + 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 die "No files found in MANIFEST - try running 'manifest' action?\n" unless ($dist_files and keys %$dist_files); my $metafile = $self->metafile; $self->log_warn("*** Did you forget to add $metafile to the MANIFEST?\n") unless exists $dist_files->{$metafile}; - + my $dist_dir = $self->dist_dir; $self->delete_filetree($dist_dir); $self->log_info("Creating $dist_dir\n"); $self->add_to_cleanup($dist_dir); - + foreach my $file (keys %$dist_files) { my $new = $self->copy_if_modified(from => $file, to_dir => $dist_dir, verbose => 0); } - + + $self->do_create_bundle_inc if @{$self->bundle_inc}; + $self->_sign_dir($dist_dir) if $self->{properties}{sign}; } @@ -3388,8 +3788,7 @@ sub _eumanifest_has_include { my $self = shift; require ExtUtils::Manifest; - return ExtUtils::Manifest->VERSION >= 1.50 ? 1 : 0; - return 0; + return eval { ExtUtils::Manifest->VERSION(1.50); 1 }; } @@ -3436,6 +3835,19 @@ sub _slurp { } + +sub _append_maniskip { + my $self = shift; + my $skip = shift; + my $file = shift || 'MANIFEST.SKIP'; + return unless defined $skip && length $skip; + my $fh = IO::File->new(">> $file") + or die "Can't open $file: $!"; + + print $fh "$skip\n"; + $fh->close(); +} + sub _write_default_maniskip { my $self = shift; my $file = shift || 'MANIFEST.SKIP'; @@ -3446,6 +3858,8 @@ sub _write_default_maniskip { : $self->_slurp( $self->_default_maniskip ); $content .= <<'EOF'; +# Avoid configuration metadata file +^MYMETA\.$ # Avoid Module::Build generated and utility files. \bBuild$ @@ -3466,14 +3880,27 @@ EOF return; } -sub ACTION_manifest { +sub _check_manifest_skip { my ($self) = @_; my $maniskip = 'MANIFEST.SKIP'; - unless ( -e 'MANIFEST' || -e $maniskip ) { + + if ( ! -e $maniskip ) { $self->log_warn("File '$maniskip' does not exist: Creating a default '$maniskip'\n"); $self->_write_default_maniskip($maniskip); } + else { + # MYMETA must not be added to MANIFEST, so always confirm the skip + $self->_check_mymeta_skip( $maniskip ); + } + + return; +} + +sub ACTION_manifest { + my ($self) = @_; + + $self->_check_manifest_skip; require ExtUtils::Manifest; # ExtUtils::Manifest is not warnings clean. local ($^W, $ExtUtils::Manifest::Quiet) = (0,1); @@ -3511,6 +3938,63 @@ sub _files_in { return @files; } +sub share_dir { + my $self = shift; + my $p = $self->{properties}; + + $p->{share_dir} = shift if @_; + + # Always coerce to proper hash form + if ( ! defined $p->{share_dir} ) { + # not set -- use default 'share' dir if exists + $p->{share_dir} = { dist => [ 'share' ] } if -d 'share'; + } + elsif ( ! ref $p->{share_dir} ) { + # scalar -- treat as a single 'dist' directory + $p->{share_dir} = { dist => [ $p->{share_dir} ] }; + } + elsif ( ref $p->{share_dir} eq 'ARRAY' ) { + # array -- treat as a list of 'dist' directories + $p->{share_dir} = { dist => $p->{share_dir} }; + } + elsif ( ref $p->{share_dir} eq 'HASH' ) { + # hash -- check structure + my $share_dir = $p->{share_dir}; + # check dist key + if ( defined $share_dir->{dist} ) { + if ( ! ref $share_dir->{dist} ) { + # scalar, so upgrade to arrayref + $share_dir->{dist} = [ $share_dir->{dist} ]; + } + elsif ( ref $share_dir->{dist} ne 'ARRAY' ) { + die "'dist' key in 'share_dir' must be scalar or arrayref"; + } + } + # check module key + if ( defined $share_dir->{module} ) { + my $mod_hash = $share_dir->{module}; + if ( ref $mod_hash eq 'HASH' ) { + for my $k ( keys %$mod_hash ) { + if ( ! ref $mod_hash->{$k} ) { + $mod_hash->{$k} = [ $mod_hash->{$k} ]; + } + elsif( ref $mod_hash->{$k} ne 'ARRAY' ) { + die "modules in 'module' key of 'share_dir' must be scalar or arrayref"; + } + } + } + else { + die "'module' key in 'share_dir' must be hashref"; + } + } + } + else { + die "'share_dir' must be hashref, arrayref or string"; + } + + return $p->{share_dir}; +} + sub script_files { my $self = shift; @@ -3529,13 +4013,13 @@ sub script_files { } my %pl_files = map { - File::Spec->canonpath( File::Spec->case_tolerant ? uc $_ : $_ ) => 1 + File::Spec->canonpath( File::Spec->case_tolerant ? uc $_ : $_ ) => 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( File::Spec->case_tolerant ? uc $_ : $_ ) } @bin_files; return $_ = { map {$_ => 1} grep !$pl_files{$bin_map{$_}}, @bin_files }; @@ -3546,6 +4030,7 @@ BEGIN { *scripts = \&script_files; } my %licenses = ( perl => 'Perl_5', apache => 'Apache_2_0', + apache_1_1 => 'Apache_1_1', artistic => 'Artistic_1_0', artistic_2 => 'Artistic_2_0', lgpl => 'LGPL_2_1', @@ -3568,6 +4053,7 @@ BEGIN { *scripts = \&script_files; } my %license_urls = ( perl => 'http://dev.perl.org/licenses/', apache => 'http://apache.org/licenses/LICENSE-2.0', + apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', artistic => 'http://opensource.org/licenses/artistic-license.php', artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', lgpl => 'http://opensource.org/licenses/lgpl-license.php', @@ -3615,10 +4101,10 @@ sub ACTION_distmeta { sub do_create_metafile { my $self = shift; return if $self->{wrote_metadata}; - + my $p = $self->{properties}; my $metafile = $self->metafile; - + unless ($p->{license}) { $self->log_warn("No license specified, setting license = 'unknown'\n"); $p->{license} = 'unknown'; @@ -3639,7 +4125,7 @@ sub do_create_metafile { push @INC, File::Spec->catdir($self->blib, 'lib'); } - if ( $self->write_metafile( $self->metafile, $self->generate_metadata ) ) { + if ( $self->write_metafile( $self->metafile, $self->prepare_metadata( fatal => 1 ) ) ) { $self->{wrote_metadata} = 1; $self->_add_to_manifest('MANIFEST', $metafile); } @@ -3647,42 +4133,22 @@ sub do_create_metafile { return 1; } -sub generate_metadata { - my $self = shift; - my $node = {}; - - if ($self->_mb_feature('YAML_support')) { - require YAML; - require YAML::Node; - # We use YAML::Node to get the order nice in the YAML file. - $self->prepare_metadata( $node = YAML::Node->new({}) ); - } else { - require Module::Build::YAML; - my @order_keys; - $self->prepare_metadata($node, \@order_keys); - $node->{_order} = \@order_keys; - } - return $node; -} - 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; - require YAML::Node; - delete $node->{_order}; # XXX also probably redundant, but for safety - # YAML API changed after version 0.30 - my $yaml_sub = $YAML::VERSION le '0.30' ? \&YAML::StoreFile : \&YAML::DumpFile; - $yaml_sub->( $metafile, $node ); + require YAML::Tiny; + $yaml = YAML::Tiny->new($node); } else { - # XXX probably redundant require Module::Build::YAML; - &Module::Build::YAML::DumpFile($metafile, $node); + $yaml = Module::Build::YAML->new($node); } - return 1; + my $result = $yaml->write($metafile) + or $self->log_warn( "Error writing '$metafile': " . $yaml->errstr . "\n"); + return $result; } sub normalize_version { @@ -3690,7 +4156,7 @@ sub normalize_version { if ( $version =~ /[=<>!,]/ ) { # logic, not just version # take as is without modification } - elsif ( ref $version eq 'version' || + elsif ( ref $version eq 'version' || ref $version eq 'Module::Build::Version' ) { # version objects $version = $version->is_qv ? $version->normal : $version->stringify; } @@ -3705,31 +4171,46 @@ sub normalize_version { } sub prepare_metadata { - my ($self, $node, $keys) = @_; + my ($self, %args) = @_; + my $fatal = $args{fatal} || 0; my $p = $self->{properties}; + my $node = {}; # A little helper sub my $add_node = sub { my ($name, $val) = @_; $node->{$name} = $val; - push @$keys, $name if $keys; }; foreach (qw(dist_name dist_version dist_author dist_abstract license)) { (my $name = $_) =~ s/^dist_//; $add_node->($name, $self->$_()); - die "ERROR: Missing required field '$_' for META.yml\n" - unless defined($node->{$name}) && length($node->{$name}); + unless ( defined($node->{$name}) && length($node->{$name}) ) { + my $err = "ERROR: Missing required field '$_' for metafile\n"; + if ( $fatal ) { + die $err; + } + else { + $self->log_warn($err); + } + } } - $node->{version} = $self->normalize_version($node->{version}); + $node->{version} = $self->normalize_version($node->{version}); if (defined( my $l = $self->license )) { - die "Unknown license string '$l'" - unless exists $self->valid_licenses->{ $l }; + unless ( exists $self->valid_licenses->{ $l } ) { + my $err = "Unknown license string '$l'"; + if ( $fatal ) { + die $err; + } + else { + $self->log_warn($err); + } + } if (my $key = $self->valid_licenses->{ $l }) { my $class = "Software::License::$key"; - if (eval "use $class; 1") { + if (eval "require Software::License; require $class; 1") { # S::L requires a 'holder' key $node->{resources}{license} = $class->new({holder=>"nobody"})->url; } @@ -3743,24 +4224,14 @@ sub prepare_metadata { # copy prereq data structures so we can modify them before writing to META my %prereq_types; for my $type ( 'configure_requires', @{$self->prereq_action_types} ) { - if (exists $p->{$type}) { + if (exists $p->{$type}) { for my $mod ( keys %{ $p->{$type} } ) { - $prereq_types{$type}{$mod} = + $prereq_types{$type}{$mod} = $self->normalize_version($p->{$type}{$mod}); } } } - # add current Module::Build to configure_requires if there - # isn't one already specified (but not ourself, so we're not circular) - if ( $self->dist_name ne 'Module-Build' - && $self->auto_configure_requires - && ! exists $prereq_types{'configure_requires'}{'Module::Build'} - ) { - (my $ver = $VERSION) =~ s/^(\d+\.\d\d).*$/$1/; # last major release only - $prereq_types{configure_requires}{'Module::Build'} = $ver; - } - for my $t ( keys %prereq_types ) { $add_node->($t, $prereq_types{$t}); } @@ -3771,7 +4242,7 @@ sub prepare_metadata { my $pkgs = eval { $self->find_dist_packages }; if ($@) { $self->log_warn("$@\nWARNING: Possible missing or corrupt 'MANIFEST' file.\n" . - "Nothing to enter for 'provides' field in META.yml\n"); + "Nothing to enter for 'provides' field in metafile.\n"); } else { $node->{provides} = $pkgs if %$pkgs; } @@ -3782,7 +4253,7 @@ sub prepare_metadata { $add_node->('generated_by', "Module::Build version $Module::Build::VERSION"); - $add_node->('meta-spec', + $add_node->('meta-spec', {version => '1.4', url => 'http://module-build.sourceforge.net/META-spec-v1.4.html', }); @@ -3815,21 +4286,28 @@ sub find_dist_packages { # private stock. my $manifest = $self->_read_manifest('MANIFEST') - or die "Can't find dist packages without a MANIFEST file - run 'manifest' action first"; + or die "Can't find dist packages without a MANIFEST file\nRun 'Build manifest' to generate one\n"; # Localize my %dist_files = map { $self->localize_file_path($_) => $_ } keys %$manifest; - my @pm_files = grep {exists $dist_files{$_}} keys %{ $self->find_pm_files }; + my @pm_files = grep { $_ !~ m{^t} } # skip things in t/ + grep {exists $dist_files{$_}} + keys %{ $self->find_pm_files }; + + return $self->find_packages_in_files(\@pm_files, \%dist_files); +} + +sub find_packages_in_files { + my ($self, $file_list, $filename_map) = @_; # First, we enumerate all packages & versions, # separating into primary & alternative candidates my( %prime, %alt ); - foreach my $file (@pm_files) { - next if $dist_files{$file} =~ m{^t/}; # Skip things in t/ - - my @path = split( /\//, $dist_files{$file} ); + foreach my $file (@{$file_list}) { + my $mapped_filename = $filename_map->{$file}; + my @path = split( /\//, $mapped_filename ); (my $prime_package = join( '::', @path[1..$#path] )) =~ s/\.pm$//; my $pm_info = Module::Build::ModuleInfo->new_from_file( $file ); @@ -3841,18 +4319,18 @@ sub find_dist_packages { my $version = $pm_info->version( $package ); if ( $package eq $prime_package ) { - if ( exists( $prime{$package} ) ) { - # M::B::ModuleInfo will handle this conflict - die "Unexpected conflict in '$package'; multiple versions found.\n"; - } else { - $prime{$package}{file} = $dist_files{$file}; + if ( exists( $prime{$package} ) ) { + # M::B::ModuleInfo will handle this conflict + die "Unexpected conflict in '$package'; multiple versions found.\n"; + } else { + $prime{$package}{file} = $mapped_filename; $prime{$package}{version} = $version if defined( $version ); } } else { - push( @{$alt{$package}}, { - file => $dist_files{$file}, - version => $version, - } ); + push( @{$alt{$package}}, { + file => $mapped_filename, + version => $version, + } ); } } } @@ -3972,24 +4450,29 @@ sub _resolve_module_versions { sub make_tarball { my ($self, $dir, $file) = @_; $file ||= $dir; - + $self->log_info("Creating $file.tar.gz\n"); - + if ($self->{args}{tar}) { my $tar_flags = $self->verbose ? 'cvf' : 'cf'; $self->do_system($self->split_like_shell($self->{args}{tar}), $tar_flags, "$file.tar", $dir); $self->do_system($self->split_like_shell($self->{args}{gzip}), "$file.tar") if $self->{args}{gzip}; } else { - eval { require Archive::Tar && Archive::Tar->VERSION(1.08); 1 } - or die "You must install Archive::Tar to make a distribution tarball\n". + eval { require Archive::Tar && Archive::Tar->VERSION(1.09); 1 } + or die "You must install Archive::Tar 1.09+ to make a distribution tarball\n". "or specify a binary tar program with the '--tar' option.\n". "See the documentation for the 'dist' action.\n"; + my $files = $self->rscan_dir($dir); + # Archive::Tar versions >= 1.09 use the following to enable a compatibility # hack so that the resulting archive is compatible with older clients. - $Archive::Tar::DO_NOT_USE_PREFIX = 0; + # If no file path is 100 chars or longer, we disable the prefix field + # for maximum compatibility. If there are any long file paths then we + # need the prefix field after all. + $Archive::Tar::DO_NOT_USE_PREFIX = + (grep { length($_) >= 100 } @$files) ? 0 : 1; - my $files = $self->rscan_dir($dir); my $tar = Archive::Tar->new; $tar->add_files(@$files); for my $f ($tar->get_files) { @@ -4055,7 +4538,7 @@ sub original_prefix { # or original_prefix('lib' => $value); my ($self, $key, $value) = @_; # update property before merging with defaults - if ( @_ == 3 && defined $key) { + if ( @_ == 3 && defined $key) { # $value can be undef; will mask default $self->{properties}{original_prefix}{$key} = $value; } @@ -4263,7 +4746,7 @@ sub install_map { } } } - + $map{read} = ''; # To keep ExtUtils::Install quiet return \%map; @@ -4284,7 +4767,7 @@ sub rscan_dir { !ref($pattern) || (ref $pattern eq 'Regexp') ? sub {push @result, $File::Find::name if /$pattern/} : ref($pattern) eq 'CODE' ? sub {push @result, $File::Find::name if $pattern->()} : die "Unknown pattern type"; - + File::Find::find({wanted => $subr, no_chdir => 1}, $dir); return \@result; } @@ -4294,7 +4777,7 @@ sub delete_filetree { my $deleted = 0; foreach (@_) { next unless -e $_; - $self->log_info("Deleting $_\n"); + $self->log_verbose("Deleting $_\n"); File::Path::rmtree($_, 0, 0); die "Couldn't remove '$_': $!\n" if -e $_; $deleted++; @@ -4327,21 +4810,25 @@ sub cbuilder { sub have_c_compiler { my ($self) = @_; - + my $p = $self->{properties}; - return $p->{have_compiler} if defined $p->{have_compiler}; - + return $p->{_have_c_compiler} if defined $p->{_have_c_compiler}; + $self->log_verbose("Checking if compiler tools configured... "); my $b = eval { $self->cbuilder }; - my $have = $b && $b->have_compiler; + my $have = $b && eval { $b->have_compiler }; $self->log_verbose($have ? "ok.\n" : "failed.\n"); - return $p->{have_compiler} = $have; + return $p->{_have_c_compiler} = $have; } sub compile_c { my ($self, $file, %args) = @_; - my $b = $self->cbuilder; + if ( ! $self->have_c_compiler ) { + die "Error: no compiler detected to compile '$file'. Aborting\n"; + } + + my $b = $self->cbuilder; my $obj_file = $b->object_file($file); $self->add_to_cleanup($obj_file); return $obj_file if $self->up_to_date($file, $obj_file); @@ -4381,11 +4868,11 @@ sub link_c { sub compile_xs { my ($self, $file, %args) = @_; - - $self->log_info("$file -> $args{outfile}\n"); + + $self->log_verbose("$file -> $args{outfile}\n"); if (eval {require ExtUtils::ParseXS; 1}) { - + ExtUtils::ParseXS::process_file( filename => $file, prototypes => 0, @@ -4393,26 +4880,26 @@ sub compile_xs { ); } else { # Ok, I give up. Just use backticks. - + my $xsubpp = Module::Build::ModuleInfo->find_module_by_name('ExtUtils::xsubpp') or die "Can't find ExtUtils::xsubpp in INC (@INC)"; - + my @typemaps; push @typemaps, Module::Build::ModuleInfo->find_module_by_name( 'ExtUtils::typemap', \@INC ); my $lib_typemap = Module::Build::ModuleInfo->find_module_by_name( - 'typemap', [File::Basename::dirname($file)] + 'typemap', [File::Basename::dirname($file), File::Spec->rel2abs('.')] ); push @typemaps, $lib_typemap if $lib_typemap; @typemaps = map {+'-typemap', $_} @typemaps; my $cf = $self->{config}; my $perl = $self->{properties}{perl}; - + my @command = ($perl, "-I".$cf->get('installarchlib'), "-I".$cf->get('installprivlib'), $xsubpp, '-noprototypes', @typemaps, $file); - + $self->log_info("@command\n"); my $fh = IO::File->new("> $args{outfile}") or die "Couldn't write $args{outfile}: $!"; print {$fh} $self->_backticks(@command); @@ -4422,12 +4909,12 @@ sub compile_xs { sub split_like_shell { my ($self, $string) = @_; - + return () unless defined($string); return @$string if UNIVERSAL::isa($string, 'ARRAY'); $string =~ s/^\s+|\s+$//g; return () unless length($string); - + return Text::ParseWords::shellwords($string); } @@ -4553,12 +5040,12 @@ sub process_xs { sub do_system { my ($self, @cmd) = @_; - $self->log_info("@cmd\n"); + $self->log_verbose("@cmd\n"); # Some systems proliferate huge PERL5LIBs, try to ameliorate: my %seen; my $sep = $self->config('path_sep'); - local $ENV{PERL5LIB} = + local $ENV{PERL5LIB} = ( !exists($ENV{PERL5LIB}) ? '' : length($ENV{PERL5LIB}) < 500 ? $ENV{PERL5LIB} @@ -4587,8 +5074,8 @@ sub copy_if_modified { unless (defined $file and length $file) { die "No 'from' parameter given to copy_if_modified"; } - - # makes no sense to replicate an absolute path, so assume flatten + + # makes no sense to replicate an absolute path, so assume flatten $args{flatten} = 1 if File::Spec->file_name_is_absolute( $file ); my $to_path; @@ -4601,7 +5088,7 @@ sub copy_if_modified { } else { die "No 'to' or 'to_dir' parameter given to copy_if_modified"; } - + return if $self->up_to_date($file, $to_path); # Already fresh { @@ -4611,9 +5098,9 @@ sub copy_if_modified { # Create parent directories File::Path::mkpath(File::Basename::dirname($to_path), 0, oct(777)); - - $self->log_info("Copying $file -> $to_path\n") if $args{verbose}; - + + $self->log_verbose("Copying $file -> $to_path\n"); + if ($^O eq 'os2') {# copy will not overwrite; 0x1 = overwrite chmod 0666, $to_path; File::Copy::syscopy($file, $to_path, 0x1) or die "Can't copy('$file', '$to_path'): $!"; @@ -4644,7 +5131,7 @@ sub up_to_date { } $most_recent_source = -M _ if -M _ < $most_recent_source; } - + foreach my $derived (@$derived) { return 0 if -M $derived > $most_recent_source; } @@ -4655,21 +5142,21 @@ sub dir_contains { my ($self, $first, $second) = @_; # File::Spec doesn't have an easy way to check whether one directory # is inside another, unfortunately. - + ($first, $second) = map File::Spec->canonpath($_), ($first, $second); my @first_dirs = File::Spec->splitdir($first); my @second_dirs = File::Spec->splitdir($second); return 0 if @second_dirs < @first_dirs; - + my $is_same = ( File::Spec->case_tolerant ? sub {lc(shift()) eq lc(shift())} : sub {shift() eq shift()} ); - + while (@first_dirs) { return 0 unless $is_same->(shift @first_dirs, shift @second_dirs); } - + return 1; } diff --git a/cpan/Module-Build/lib/Module/Build/Bundling.pod b/cpan/Module-Build/lib/Module/Build/Bundling.pod new file mode 100644 index 0000000000..0a60d8f70d --- /dev/null +++ b/cpan/Module-Build/lib/Module/Build/Bundling.pod @@ -0,0 +1,154 @@ +=head1 NAME + +Module::Build::Bundling - How to bundle Module::Build with a distribution + +=head1 SYNOPSIS + + # Build.PL + use lib '.'; + use inc::latest 'Module::Build'; + + Module::Build->new( + module_name => 'Foo::Bar', + license => 'perl', + )->create_build_script; + +=head1 DESCRIPTION + +B<WARNING -- THIS IS AN EXPERIMENTAL FEATURE> + +In order to install a distribution using Module::Build, users must +have Module::Build available on their systems. There are two ways +to do this. The first way is to include Module::Build in the +C<configure_requires> metadata field. This field is supported by +recent versions L<CPAN> and L<CPANPLUS> and is a standard feature +in the Perl core as of Perl 5.10.1. Module::Build now adds itself +to C<configure_requires> by default. + +The second way supports older Perls that have not upgraded CPAN or +CPANPLUS and involves bundling an entire copy of Module::Build +into the distribution's C<inc/> directory. This is the same approach +used by L<Module::Install>, a modern wrapper around ExtUtils::MakeMaker +for Makefile.PL based distributions. + +The "trick" to making this work for Module::Build is making sure the +highest version Module::Build is used, whether this is in C<inc/> or +already installed on the user's system. This ensures that all necessary +features are available as well as any new bug fixes. This is done using +the new L<inc::latest> module. + +A "normal" Build.PL looks like this (with only the minimum required +fields): + + use Module::Build; + + Module::Build->new( + module_name => 'Foo::Bar', + license => 'perl', + )->create_build_script; + +A "bundling" Build.PL replaces the initial "use" line with a nearly +transparent replacement: + + use lib '.'; + use inc::latest 'Module::Build'; + + Module::Build->new( + module_name => 'Foo::Bar', + license => 'perl', + )->create_build_script; + +The inital C<lib> line ensures that the top-level distribution directory is +added to C<@INC> so that C<inc::latest> loads from C<./inc/latest.pm>. You +SHOULD NOT add 'inc' to C<@INC> (unless you have other special reasons for +doing so) -- that's not how C<inc::latest> works. + +For I<authors>, when "Build dist" is run, Module::Build will be +automatically bundled into C<inc> according to the rules for +L<inc::latest>. + +For I<users>, inc::latest will load the latest Module::Build, whether +installed or bundled in C<inc/>. + +=head1 BUNDLING OTHER CONFIGURATION DEPENDENCIES + +The same approach works for other configuration dependencies -- modules +that I<must> be available for Build.PL to run. All other dependencies can +be specified as usual in the Build.PL and CPAN or CPANPLUS will install +them after Build.PL finishes. + +For example, to bundle the L<Devel::AssertOS::Unix> module (which ensures a +"Unix-like" operating system), one could do this: + + use inc::latest 'Devel::AssertOS::Unix'; + use inc::latest 'Module::Build'; + + Module::Build->new( + module_name => 'Foo::Bar', + license => 'perl', + )->create_build_script; + +The C<inc::latest> module creates bundled directories based on the packlist +file of an installed distribution. Even though C<inc::latest> takes module +name arguments, it is better to think of it as bundling and making +available entire I<distributions>. When a module is loaded through +C<inc::latest>, it looks in all bundled distributions in C<inc/> for a +newer module than can be found in the existing C<@INC> array. + +Thus, the module-name provided should usually be the "top-level" module +name of a distribution, though this is not strictly required. For example, +L<Module::Build> has a number of heuristics to map module names to +packlists, allowing users to do things like this: + + use inc::latest 'Devel::AssertOS::Unix'; + +even though Devel::AssertOS::Unix is contained within the Devel-CheckOS +distribution. + +At the current time, packlists are required. Thus, bundling dual-core +modules, I<including Module::Build>, may require a 'forced install' over +versions in the latest version of perl in order to create the necessary +packlist for bundling. This limitation will hopefully be addressed in a +future version of Module::Build. + +=head2 WARNING -- How to Manage Dependency Chains + +Before bundling a distribution you must ensure that all prerequisites are +also bundled and load in the correct order. For Module::Build itself, this +should not be necessary, but it is necessary for any other distribution. +(A future release of Module::Build will hopefully address this deficiency.) + +For example, if you need C<Wibble>, but C<Wibble> depends on C<Wobble>, +your Build.PL might look like this: + + use inc::latest 'Wobble'; + use inc::latest 'Wibble'; + use inc::latest 'Module::Build'; + + Module::Build->new( + module_name => 'Foo::Bar', + license => 'perl', + )->create_build_script; + +Authors are strongly suggested to limit the bundling of additional +dependencies if at all possible and to carefully test their distribution +tarballs on older versions of Perl before uploading to CPAN. + +=head1 AUTHOR + +David Golden <dagolden@cpan.org> + +Development questions, bug reports, and patches should be sent to the +Module-Build mailing list at <module-build@perl.org>. + +Bug reports are also welcome at +<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Module-Build>. + +=head1 SEE ALSO + +perl(1), L<inc::latest>, L<Module::Build>(3), L<Module::Build::API>(3), +L<Module::Build::Cookbook>(3), + +=cut + +# vim: tw=75 diff --git a/cpan/Module-Build/lib/Module/Build/Compat.pm b/cpan/Module-Build/lib/Module/Build/Compat.pm index dfe75d5e1a..ebe1b129cf 100644 --- a/cpan/Module-Build/lib/Module/Build/Compat.pm +++ b/cpan/Module-Build/lib/Module/Build/Compat.pm @@ -2,7 +2,7 @@ package Module::Build::Compat; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; use File::Basename (); use File::Spec; @@ -18,7 +18,7 @@ my %convert_installdirs = ( VENDOR => 'vendor', ); -my %makefile_to_build = +my %makefile_to_build = ( TEST_VERBOSE => 'verbose', VERBINST => 'verbose', @@ -64,13 +64,50 @@ my %macro_to_build = %makefile_to_build; # "LIB=foo make" is not the same as "perl Makefile.PL LIB=foo" delete $macro_to_build{LIB}; +sub _simple_prereq { + return $_[0] =~ /^[0-9_]+\.?[0-9_]*$/; # crudly, a decimal literal +} + +sub _merge_prereq { + my ($req, $breq) = @_; + $req ||= {}; + $breq ||= {}; + + # validate formats + for my $p ( $req, $breq ) { + for my $k (keys %$p) { + die "Prereq '$p->{$k}' for '$k' is not supported by Module::Build::Compat\n" + unless _simple_prereq($p->{$k}); + } + } + # merge + my $merge = { %$req }; + for my $k ( keys %$breq ) { + my $v1 = $merge->{$k} || 0; + my $v2 = $breq->{$k}; + $merge->{$k} = $v1 > $v2 ? $v1 : $v2; + } + return %$merge; +} + sub create_makefile_pl { my ($package, $type, $build, %args) = @_; - + die "Don't know how to build Makefile.PL of type '$type'" unless $type =~ /^(small|passthrough|traditional)$/; + if ($type eq 'passthrough') { + $build->log_warn(<<"HERE"); + +IMPORTANT NOTE: The '$type' style of Makefile.PL is deprecated and +may be removed in a future version of Module::Build in favor of the +'configure_requires' property. See Module::Build::Compat +documentation for details. + +HERE + } + my $fh; if ($args{fh}) { $fh = $args{fh}; @@ -83,7 +120,7 @@ sub create_makefile_pl { print {$fh} "# Note: this file was auto-generated by ", __PACKAGE__, " version $VERSION\n"; - # Minimum perl version should be specified as "require 5.XXXXXX" in + # Minimum perl version should be specified as "require 5.XXXXXX" in # Makefile.PL my $requires = $build->requires; if ( my $minimum_perl = $requires->{perl} ) { @@ -123,41 +160,41 @@ EOF } elsif ($type eq 'passthrough') { printf {$fh} <<'EOF', $subclass_load, ref($build), ref($build); - + unless (eval "use Module::Build::Compat 0.02; 1" ) { print "This module requires Module::Build to install itself.\n"; - + require ExtUtils::MakeMaker; my $yn = ExtUtils::MakeMaker::prompt (' Install Module::Build now from CPAN?', 'y'); - + unless ($yn =~ /^y/i) { die " *** Cannot install without Module::Build. Exiting ...\n"; } - + require Cwd; require File::Spec; require CPAN; - + # Save this 'cause CPAN will chdir all over the place. my $cwd = Cwd::cwd(); - + CPAN::Shell->install('Module::Build::Compat'); CPAN::Shell->expand("Module", "Module::Build::Compat")->uptodate or die "Couldn't install Module::Build, giving up.\n"; - + chdir $cwd or die "Cannot chdir() back to $cwd: $!"; } eval "use Module::Build::Compat 0.02; 1" or die $@; %s Module::Build::Compat->run_build_pl(args => \@ARGV); - my $build_script = 'Build'; + my $build_script = 'Build'; $build_script .= '.com' if $^O eq 'VMS'; exit(0) unless(-e $build_script); # cpantesters convention require %s; Module::Build::Compat->write_makefile(build_class => '%s'); EOF - + } elsif ($type eq 'traditional') { my (%MM_Args, %prereq); @@ -165,37 +202,37 @@ EOF tie %MM_Args, 'Tie::IxHash'; # Don't care if it fails here tie %prereq, 'Tie::IxHash'; # Don't care if it fails here } - + my %name = ($build->module_name ? (NAME => $build->module_name) : (DISTNAME => $build->dist_name)); - + my %version = ($build->dist_version_from ? (VERSION_FROM => $build->dist_version_from) : (VERSION => $build->dist_version) ); %MM_Args = (%name, %version); - - %prereq = ( %{$build->requires}, %{$build->build_requires} ); + + %prereq = _merge_prereq( $build->requires, $build->build_requires ); %prereq = map {$_, $prereq{$_}} sort keys %prereq; - + delete $prereq{perl}; $MM_Args{PREREQ_PM} = \%prereq; - + $MM_Args{INSTALLDIRS} = $build->installdirs eq 'core' ? 'perl' : $build->installdirs; - + $MM_Args{EXE_FILES} = [ sort keys %{$build->script_files} ] if $build->script_files; - + $MM_Args{PL_FILES} = $build->PL_files || {}; if ($build->recursive_test_files) { - $MM_Args{TESTS} = join q{ }, $package->_test_globs($build); + $MM_Args{test} = { TESTS => join q{ }, $package->_test_globs($build) }; } local $Data::Dumper::Terse = 1; my $args = Data::Dumper::Dumper(\%MM_Args); $args =~ s/\{(.*)\}/($1)/s; - + print $fh <<"EOF"; use ExtUtils::MakeMaker; WriteMakefile @@ -213,7 +250,7 @@ sub _test_globs { sub subclass_dir { my ($self, $build) = @_; - + return (Module::Build::ModuleInfo->find_module_dir_by_name(ref $build) || File::Spec->catdir($build->config_dir, 'lib')); } @@ -228,7 +265,7 @@ sub makefile_to_build_args { my @out; foreach my $arg (@_) { next if $arg eq ''; - + my ($key, $val) = ($arg =~ /^(\w+)=(.+)/ ? ($1, $2) : die "Malformed argument '$arg'"); @@ -283,7 +320,7 @@ sub makefile_to_build_macros { } } } - push @out, (config => \%config) if %config; + push @out, (config => \%config) if %config; return @out; } @@ -342,19 +379,19 @@ $action : force_do_it $perl $Build $action EOF } - + if ($self->_is_vms_mms) { # Roll our own .EXPORT as MMS/MMK don't honor that directive. - $maketext .= "\n.FIRST\n\t\@ $noop\n"; + $maketext .= "\n.FIRST\n\t\@ $noop\n"; for my $macro (keys %macro_to_build) { $maketext .= ".IFDEF $macro\n\tDEFINE $macro \"\$($macro)\"\n.ENDIF\n"; } - $maketext .= "\n"; + $maketext .= "\n"; } else { $maketext .= "\n.EXPORT : " . join(' ', keys %macro_to_build) . "\n\n"; } - + return $maketext; } @@ -363,15 +400,13 @@ sub fake_prereqs { my $fh = IO::File->new("< $file") or die "Can't read $file: $!"; my $prereqs = eval do {local $/; <$fh>}; close $fh; - + + my %merged = _merge_prereq( $prereqs->{requires}, $prereqs->{build_requires} ); my @prereq; - foreach my $section (qw/build_requires requires/) { - foreach (keys %{$prereqs->{$section}}) { - next if $_ eq 'perl'; - push @prereq, "$_=>q[$prereqs->{$section}{$_}]"; - } + foreach (sort keys %merged) { + next if $_ eq 'perl'; + push @prereq, "$_=>q[$merged{$_}]"; } - return unless @prereq; return "# PREREQ_PM => { " . join(", ", @prereq) . " }\n\n"; } @@ -414,7 +449,7 @@ Module::Build::Compat - Compatibility with ExtUtils::MakeMaker my $build = Module::Build->new ( module_name => 'Foo::Bar', license => 'perl', - create_makefile_pl => 'passthrough' ); + create_makefile_pl => 'traditional' ); ... @@ -448,6 +483,18 @@ The currently supported styles are: =over 4 +=item traditional + +A F<Makefile.PL> will be created in the "traditional" style, i.e. it will +use C<ExtUtils::MakeMaker> and won't rely on C<Module::Build> at all. +In order to create the F<Makefile.PL>, we'll include the C<requires> and +C<build_requires> dependencies as the C<PREREQ_PM> parameter. + +You don't want to use this style if during the C<perl Build.PL> stage +you ask the user questions, or do some auto-sensing about the user's +environment, or if you subclass C<Module::Build> to do some +customization, because the vanilla F<Makefile.PL> won't do any of that. + =item small A small F<Makefile.PL> will be created that passes all functionality @@ -455,24 +502,22 @@ through to the F<Build.PL> script in the same directory. The user must already have C<Module::Build> installed in order to use this, or else they'll get a module-not-found error. -=item passthrough +=item passthrough (DEPRECATED) This is just like the C<small> option above, but if C<Module::Build> is not already installed on the user's system, the script will offer to use C<CPAN.pm> to download it and install it before continuing with the build. -=item traditional - -A F<Makefile.PL> will be created in the "traditional" style, i.e. it will -use C<ExtUtils::MakeMaker> and won't rely on C<Module::Build> at all. -In order to create the F<Makefile.PL>, we'll include the C<requires> and -C<build_requires> dependencies as the C<PREREQ_PM> parameter. +This option has been deprecated and may be removed in a future version +of Module::Build. Modern CPAN.pm and CPANPLUS will recognize the +C<configure_requires> metadata property and install Module::Build before +running Build.PL if Module::Build is listed and Module::Build now +adds itself to configure_requires by default. -You don't want to use this style if during the C<perl Build.PL> stage -you ask the user questions, or do some auto-sensing about the user's -environment, or if you subclass C<Module::Build> to do some -customization, because the vanilla F<Makefile.PL> won't do any of that. +Perl 5.10.1 includes C<configure_requires> support. In the future, when +C<configure_requires> support is deemed sufficiently widespread, the +C<passthrough> style will be removed. =back diff --git a/cpan/Module-Build/lib/Module/Build/Config.pm b/cpan/Module-Build/lib/Module/Build/Config.pm index de8b44d092..b833e2b183 100644 --- a/cpan/Module-Build/lib/Module/Build/Config.pm +++ b/cpan/Module-Build/lib/Module/Build/Config.pm @@ -2,7 +2,7 @@ package Module::Build::Config; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Config; diff --git a/cpan/Module-Build/lib/Module/Build/Cookbook.pm b/cpan/Module-Build/lib/Module/Build/Cookbook.pm index 82c8e01d67..42054d1744 100644 --- a/cpan/Module-Build/lib/Module/Build/Cookbook.pm +++ b/cpan/Module-Build/lib/Module/Build/Cookbook.pm @@ -1,7 +1,7 @@ package Module::Build::Cookbook; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; =head1 NAME @@ -487,7 +487,7 @@ Next, add this to the top of your F<Build.PL>. # Find out what version of Module::Build is installed or fail quietly. # This should be cross-platform. - my $Installed_MB = + my $Installed_MB = `$^X -e "eval q{require Module::Build; print Module::Build->VERSION} or exit 1"; # some operating systems put a newline at the end of every print. diff --git a/cpan/Module-Build/lib/Module/Build/Dumper.pm b/cpan/Module-Build/lib/Module/Build/Dumper.pm index 1cd8cd0e16..6f8ff7a616 100644 --- a/cpan/Module-Build/lib/Module/Build/Dumper.pm +++ b/cpan/Module-Build/lib/Module/Build/Dumper.pm @@ -1,7 +1,7 @@ package Module::Build::Dumper; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; # This is just a split-out of a wrapper function to do Data::Dumper # stuff "the right way". See: diff --git a/cpan/Module-Build/lib/Module/Build/ModuleInfo.pm b/cpan/Module-Build/lib/Module/Build/ModuleInfo.pm index 4de09b4c68..12ffa1d711 100644 --- a/cpan/Module-Build/lib/Module/Build/ModuleInfo.pm +++ b/cpan/Module-Build/lib/Module/Build/ModuleInfo.pm @@ -8,13 +8,14 @@ package Module::Build::ModuleInfo; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use File::Spec; use IO::File; use Module::Build::Version; +my $V_NUM_REGEXP = qr{v?[0-9._]+}; # crudely, a v-string or decimal my $PKG_REGEXP = qr{ # match a package declaration ^[\s\{;]* # intro chars on a line @@ -22,6 +23,8 @@ my $PKG_REGEXP = qr{ # match a package declaration \s+ # whitespace ([\w:]+) # a package name \s* # optional whitespace + ($V_NUM_REGEXP)? # optional version number + \s* # optional whitesapce ; # semicolon line terminator }x; @@ -221,10 +224,10 @@ sub _parse_fh { $self->_parse_version_expression( $line ); if ( $line =~ $PKG_REGEXP ) { - $pkg = $1; - push( @pkgs, $pkg ) unless grep( $pkg eq $_, @pkgs ); - $vers{$pkg} = undef unless exists( $vers{$pkg} ); - $need_vers = 1; + $pkg = $1; + push( @pkgs, $pkg ) unless grep( $pkg eq $_, @pkgs ); + $vers{$pkg} = (defined $2 ? $2 : undef) unless exists( $vers{$pkg} ); + $need_vers = defined $2 ? 0 : 1; # VERSION defined with full package spec, i.e. $Module::VERSION } elsif ( $vers_fullname && $vers_pkg ) { @@ -232,7 +235,7 @@ sub _parse_fh { $need_vers = 0 if $vers_pkg eq $pkg; unless ( defined $vers{$vers_pkg} && length $vers{$vers_pkg} ) { - $vers{$vers_pkg} = + $vers{$vers_pkg} = $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line ); } else { # Warn unless the user is using the "$VERSION = eval @@ -323,11 +326,22 @@ sub _evaluate_version_line { (ref($vsub) eq 'CODE') or die "failed to build version sub for $self->{filename}"; my $result = eval { $vsub->() }; + die "Could not get version from $self->{filename} by executing:\n$eval\n\nThe fatal error was: $@\n" + if $@; - die "Could not get version from $self->{filename} by executing:\n$eval\n\nThe fatal error was: $@\n" if $@; + # Activestate apparently creates custom versions like '1.23_45_01', which + # cause M::B::Version to think it's an invalid alpha. So check for that + # and strip them + my $num_dots = () = $result =~ m{\.}g; + my $num_unders = () = $result =~ m{_}g; + if ( substr($result,0,1) ne 'v' && $num_dots < 2 && $num_unders > 1 ) { + $result =~ s{_}{}g; + } # Bless it into our own version class - $result = Module::Build::Version->new($result); + eval { $result = Module::Build::Version->new($result) }; + die "Version '$result' from $self->{filename} does not appear to be valid:\n$eval\n\nThe fatal error was: $@\n" + if $@; return $result; } diff --git a/cpan/Module-Build/lib/Module/Build/Notes.pm b/cpan/Module-Build/lib/Module/Build/Notes.pm index fe98419759..a0506c64dc 100644 --- a/cpan/Module-Build/lib/Module/Build/Notes.pm +++ b/cpan/Module-Build/lib/Module/Build/Notes.pm @@ -4,7 +4,7 @@ package Module::Build::Notes; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Data::Dumper; use IO::File; @@ -33,10 +33,10 @@ sub restore { sub access { my $self = shift; return $self->read() unless @_; - + my $key = shift; return $self->read($key) unless @_; - + my $value = shift; $self->write({ $key => $value }); return $self->read($key); @@ -61,7 +61,7 @@ sub read { return $self->{new}{$key} if exists $self->{new}{$key}; return $self->{disk}{$key}; } - + # Return all data my $out = (keys %{$self->{new}} ? {%{$self->{disk}}, %{$self->{new}}} @@ -79,7 +79,7 @@ sub _same { sub write { my ($self, $href) = @_; $href ||= {}; - + @{$self->{new}}{ keys %$href } = values %$href; # Merge # Do some optimization to avoid unnecessary writes @@ -88,17 +88,17 @@ sub write { next if ref $self->{disk}{$key} or !exists $self->{disk}{$key}; delete $self->{new}{$key} if $self->_same($self->{new}{$key}, $self->{disk}{$key}); } - + if (my $file = $self->{file}) { my ($vol, $dir, $base) = File::Spec->splitpath($file); $dir = File::Spec->catpath($vol, $dir, ''); return unless -e $dir && -d $dir; # The user needs to arrange for this return if -e $file and !keys %{ $self->{new} }; # Nothing to do - - @{$self->{disk}}{ keys %{$self->{new}} } = values %{$self->{new}}; # Merge + + @{$self->{disk}}{ keys %{$self->{new}} } = values %{$self->{new}}; # Merge $self->_dump($file, $self->{disk}); - + $self->{new} = {}; } return $self->read; @@ -106,18 +106,66 @@ sub write { sub _dump { my ($self, $file, $data) = @_; - + my $fh = IO::File->new("> $file") or die "Can't create '$file': $!"; print {$fh} Module::Build::Dumper->_data_dump($data); } +my $orig_template = do { local $/; <DATA> }; +close DATA; + sub write_config_data { my ($self, %args) = @_; + my $template = $orig_template; + $template =~ s/NOTES_NAME/$args{config_module}/g; + $template =~ s/MODULE_NAME/$args{module}/g; + $template =~ s/=begin private\n//; + $template =~ s/=end private/=cut/; + + # strip out private POD markers we use to keep pod from being + # recognized for *this* source file + $template =~ s{$_\n}{} for '=begin private', '=end private'; + my $fh = IO::File->new("> $args{file}") or die "Can't create '$args{file}': $!"; + print {$fh} $template; + print {$fh} "\n__DATA__\n"; + print {$fh} Module::Build::Dumper->_data_dump([$args{config_data}, $args{feature}, $args{auto_features}]); + +} + +1; + + +=head1 NAME + +Module::Build::Notes - Create persistent distribution configuration modules + +=head1 DESCRIPTION + +This module is used internally by Module::Build to create persistent +configuration files that can be installed with a distribution. See +L<Module::Build::ConfigData> for an example. + +=head1 AUTHOR - printf $fh <<'EOF', $args{config_module}; -package %s; +Ken Williams <kwilliams@cpan.org> + +=head1 COPYRIGHT + +Copyright (c) 2001-2006 Ken Williams. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +perl(1), L<Module::Build>(3) + +=cut + +__DATA__ +package NOTES_NAME; use strict; my $arrayref = eval do {local $/; <DATA>} or die "Couldn't load ConfigData data: $@"; @@ -129,14 +177,14 @@ sub config { $config->{$_[1]} } sub set_config { $config->{$_[1]} = $_[2] } sub set_feature { $features->{$_[1]} = 0+!!$_[2] } # Constrain to 1 or 0 -sub auto_feature_names { grep !exists $features->{$_}, keys %%$auto_features } +sub auto_feature_names { grep !exists $features->{$_}, keys %$auto_features } sub feature_names { - my @features = (keys %%$features, auto_feature_names()); + my @features = (keys %$features, auto_feature_names()); @features; } -sub config_names { keys %%$config } +sub config_names { keys %$config } sub write { my $me = __FILE__; @@ -170,20 +218,20 @@ sub write { sub feature { my ($package, $key) = @_; return $features->{$key} if exists $features->{$key}; - + my $info = $auto_features->{$key} or return 0; - - # Under perl 5.005, each(%%$foo) isn't working correctly when $foo + + # Under perl 5.005, each(%$foo) isn't working correctly when $foo # was reanimated with Data::Dumper and eval(). Not sure why, but # copying to a new hash seems to solve it. - my %%info = %%$info; - + my %info = %$info; + require Module::Build; # XXX should get rid of this - while (my ($type, $prereqs) = each %%info) { + while (my ($type, $prereqs) = each %info) { next if $type eq 'description' || $type eq 'recommends'; - - my %%p = %%$prereqs; # Ditto here. - while (my ($modname, $spec) = each %%p) { + + my %p = %$prereqs; # Ditto here. + while (my ($modname, $spec) = each %p) { my $status = Module::Build->check_installed_status($modname, $spec); if ((!$status->{ok}) xor ($type =~ /conflicts$/)) { return 0; } if ( ! eval "require $modname; 1" ) { return 0; } @@ -192,36 +240,32 @@ sub feature { return 1; } -EOF - - my ($module_name, $notes_name) = ($args{module}, $args{config_module}); - printf $fh <<"EOF", $notes_name, $module_name; +=begin private =head1 NAME -$notes_name - Configuration for $module_name - +NOTES_NAME - Configuration for MODULE_NAME =head1 SYNOPSIS - use $notes_name; - \$value = $notes_name->config('foo'); - \$value = $notes_name->feature('bar'); - - \@names = $notes_name->config_names; - \@names = $notes_name->feature_names; - - $notes_name->set_config(foo => \$new_value); - $notes_name->set_feature(bar => \$new_value); - $notes_name->write; # Save changes + use NOTES_NAME; + $value = NOTES_NAME->config('foo'); + $value = NOTES_NAME->feature('bar'); + + @names = NOTES_NAME->config_names; + @names = NOTES_NAME->feature_names; + + NOTES_NAME->set_config(foo => $new_value); + NOTES_NAME->set_feature(bar => $new_value); + NOTES_NAME->write; # Save changes =head1 DESCRIPTION -This module holds the configuration data for the C<$module_name> +This module holds the configuration data for the C<MODULE_NAME> module. It also provides a programmatic interface for getting or setting that configuration data. Note that in order to actually make -changes, you'll have to have write access to the C<$notes_name> +changes, you'll have to have write access to the C<NOTES_NAME> module, and you should attempt to understand the repercussions of your actions. @@ -230,17 +274,17 @@ actions. =over 4 -=item config(\$name) +=item config($name) Given a string argument, returns the value of the configuration item by that name, or C<undef> if no such item exists. -=item feature(\$name) +=item feature($name) Given a string argument, returns the value of the feature by that name, or C<undef> if no such feature exists. -=item set_config(\$name, \$value) +=item set_config($name, $value) Sets the configuration item with the given name to the given value. The value may be any Perl scalar that will serialize correctly using @@ -248,7 +292,7 @@ C<Data::Dumper>. This includes references, objects (usually), and complex data structures. It probably does not include transient things like filehandles or sockets. -=item set_feature(\$name, \$value) +=item set_feature($name, $value) Sets the feature with the given name to the given boolean value. The value will be converted to 0 or 1 automatically. @@ -256,12 +300,12 @@ value will be converted to 0 or 1 automatically. =item config_names() Returns a list of all the names of config items currently defined in -C<$notes_name>, or in scalar context the number of items. +C<NOTES_NAME>, or in scalar context the number of items. =item feature_names() Returns a list of all the names of features currently defined in -C<$notes_name>, or in scalar context the number of features. +C<NOTES_NAME>, or in scalar context the number of features. =item auto_feature_names() @@ -273,24 +317,16 @@ a fixed value. =item write() Commits any changes from C<set_config()> and C<set_feature()> to disk. -Requires write access to the C<$notes_name> module. +Requires write access to the C<NOTES_NAME> module. =back =head1 AUTHOR -C<$notes_name> was automatically created using C<Module::Build>. +C<NOTES_NAME> was automatically created using C<Module::Build>. C<Module::Build> was written by Ken Williams, but he holds no -authorship claim or copyright claim to the contents of C<$notes_name>. - -=cut +authorship claim or copyright claim to the contents of C<NOTES_NAME>. -__DATA__ - -EOF - - print {$fh} Module::Build::Dumper->_data_dump([$args{config_data}, $args{feature}, $args{auto_features}]); -} +=end private -1; diff --git a/cpan/Module-Build/lib/Module/Build/PPMMaker.pm b/cpan/Module-Build/lib/Module/Build/PPMMaker.pm index 35b5a75317..74a5a73b07 100644 --- a/cpan/Module-Build/lib/Module/Build/PPMMaker.pm +++ b/cpan/Module-Build/lib/Module/Build/PPMMaker.pm @@ -1,8 +1,9 @@ package Module::Build::PPMMaker; use strict; +use Config; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; # This code is mostly borrowed from ExtUtils::MM_Unix 6.10_03, with a @@ -34,7 +35,6 @@ sub make_ppd { my $method = "dist_$info"; $dist{$info} = $build->$method() or die "Can't determine distribution's $info\n"; } - $dist{version} = $self->_ppd_version($dist{version}); $self->_simple_xml_escape($_) foreach $dist{abstract}, @{$dist{author}}; @@ -42,21 +42,17 @@ sub make_ppd { # various licenses my $ppd = <<"PPD"; <SOFTPKG NAME=\"$dist{name}\" VERSION=\"$dist{version}\"> - <TITLE>$dist{name}</TITLE> <ABSTRACT>$dist{abstract}</ABSTRACT> @{[ join "\n", map " <AUTHOR>$_</AUTHOR>", @{$dist{author}} ]} <IMPLEMENTATION> PPD - # TODO: We could set <IMPLTYPE VALUE="PERL" /> or maybe - # <IMPLTYPE VALUE="PERL/XS" /> ??? - # We don't include recommended dependencies because PPD has no way # to distinguish them from normal dependencies. We don't include # build_requires dependencies because the PPM installer doesn't # build or test before installing. And obviously we don't include # conflicts either. - + foreach my $type (qw(requires)) { my $prereq = $build->$type(); while (my ($modname, $spec) = each %$prereq) { @@ -73,27 +69,18 @@ PPD } } - # Another hack - dependencies are on modules, but PPD expects - # them to be on distributions (I think). - $modname =~ s/::/-/g; - - $ppd .= sprintf(<<'EOF', $modname, $self->_ppd_version($min_version)); - <DEPENDENCY NAME="%s" VERSION="%s" /> -EOF + # PPM4 spec requires a '::' for top level modules + $modname .= '::' unless $modname =~ /::/; + $ppd .= qq! <REQUIRE NAME="$modname" VERSION="$min_version" />\n!; } } # We only include these tags if this module involves XS, on the - # assumption that pure Perl modules will work on any OS. PERLCORE, - # unfortunately, seems to indicate that a module works with _only_ - # that version of Perl, and so is only appropriate when a module - # uses XS. + # assumption that pure Perl modules will work on any OS. if (keys %{$build->find_xs_files}) { my $perl_version = $self->_ppd_version($build->perl_version); - $ppd .= sprintf(<<'EOF', $perl_version, $^O, $self->_varchname($build->config) ); - <PERLCORE VERSION="%s" /> - <OS NAME="%s" /> + $ppd .= sprintf(<<'EOF', $self->_varchname($build->config) ); <ARCHITECTURE NAME="%s" /> EOF } @@ -113,7 +100,9 @@ EOF my $ppd_file = "$dist{name}.ppd"; my $fh = IO::File->new(">$ppd_file") or die "Cannot write to $ppd_file: $!"; - $fh->binmode(":utf8") if $fh->can("binmode"); + + $fh->binmode(":utf8") + if $fh->can('binmode') && $] >= 5.008 && $Config{useperlio}; print $fh $ppd; close $fh; @@ -148,7 +137,7 @@ sub _varchname { # Copied from PPM.pm '<' => '<', ); my $rx = join '|', keys %escapes; - + sub _simple_xml_escape { $_[1] =~ s/($rx)/$escapes{$1}/go; } diff --git a/cpan/Module-Build/lib/Module/Build/Platform/Amiga.pm b/cpan/Module-Build/lib/Module/Build/Platform/Amiga.pm index 5ce8cf58a2..b31a9635ec 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/Amiga.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/Amiga.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::Amiga; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Base; diff --git a/cpan/Module-Build/lib/Module/Build/Platform/Default.pm b/cpan/Module-Build/lib/Module/Build/Platform/Default.pm index df29af5f68..b0e83a3d73 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/Default.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/Default.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::Default; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Base; diff --git a/cpan/Module-Build/lib/Module/Build/Platform/EBCDIC.pm b/cpan/Module-Build/lib/Module/Build/Platform/EBCDIC.pm index d68836c1a3..4365b12b31 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/EBCDIC.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/EBCDIC.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::EBCDIC; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Base; diff --git a/cpan/Module-Build/lib/Module/Build/Platform/MPEiX.pm b/cpan/Module-Build/lib/Module/Build/Platform/MPEiX.pm index a835c30d49..c7353783dd 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/MPEiX.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/MPEiX.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::MPEiX; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Base; diff --git a/cpan/Module-Build/lib/Module/Build/Platform/MacOS.pm b/cpan/Module-Build/lib/Module/Build/Platform/MacOS.pm index 9c9281adac..2c74942857 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/MacOS.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/MacOS.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::MacOS; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Base; use vars qw(@ISA); @@ -15,17 +15,17 @@ sub have_forkpipe { 0 } sub new { my $class = shift; my $self = $class->SUPER::new(@_); - + # $Config{sitelib} and $Config{sitearch} are, unfortunately, missing. foreach ('sitelib', 'sitearch') { $self->config($_ => $self->config("install$_")) unless $self->config($_); } - + # For some reason $Config{startperl} is filled with a bunch of crap. (my $sp = $self->config('startperl')) =~ s/.*Exit \{Status\}\s//; $self->config(startperl => $sp); - + return $self; } @@ -42,7 +42,7 @@ sub dispatch { if( !@_ and !@ARGV ) { require MacPerl; - + # What comes first in the action list. my @action_list = qw(build test install); my %actions = map {+($_, 1)} $self->known_actions; @@ -53,17 +53,17 @@ sub dispatch { foreach (@action_list) { $_ .= ' *' if $toolserver{$_}; } - + my $cmd = MacPerl::Pick("What build command? ('*' requires ToolServer)", @action_list); return unless defined $cmd; $cmd =~ s/ \*$//; $ARGV[0] = ($cmd); - + my $args = MacPerl::Ask('Any extra arguments? (ie. verbose=1)', ''); return unless defined $args; push @ARGV, $self->split_like_shell($args); } - + $self->SUPER::dispatch(@_); } @@ -82,10 +82,10 @@ sub ACTION_realclean { sub ACTION_install { my $self = shift; - + return $self->SUPER::ACTION_install(@_) if eval {ExtUtils::Install->VERSION('1.30'); 1}; - + local $^W = 0; # Avoid a 'redefine' warning local *ExtUtils::Install::find = sub { my ($code, @dirs) = @_; @@ -94,7 +94,7 @@ sub ACTION_install { return File::Find::find($code, @dirs); }; - + return $self->SUPER::ACTION_install(@_); } diff --git a/cpan/Module-Build/lib/Module/Build/Platform/RiscOS.pm b/cpan/Module-Build/lib/Module/Build/Platform/RiscOS.pm index c240750c46..9deb097963 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/RiscOS.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/RiscOS.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::RiscOS; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Base; diff --git a/cpan/Module-Build/lib/Module/Build/Platform/Unix.pm b/cpan/Module-Build/lib/Module/Build/Platform/Unix.pm index 879ca3ad4e..43f585fd4f 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/Unix.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/Unix.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::Unix; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Base; diff --git a/cpan/Module-Build/lib/Module/Build/Platform/VMS.pm b/cpan/Module-Build/lib/Module/Build/Platform/VMS.pm index 3305154b2d..13d350d8ff 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/VMS.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/VMS.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::VMS; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Base; @@ -131,22 +131,22 @@ sub _quote_args { # or if we get a single arg that is an array reference, quote the # elements of it and return the reference. my ($self, @args) = @_; - my $got_arrayref = (scalar(@args) == 1 - && UNIVERSAL::isa($args[0], 'ARRAY')) - ? 1 + my $got_arrayref = (scalar(@args) == 1 + && UNIVERSAL::isa($args[0], 'ARRAY')) + ? 1 : 0; # Do not quote qualifiers that begin with '/'. - map { if (!/^\//) { + map { if (!/^\//) { $_ =~ s/\"/""/g; # escape C<"> by doubling $_ = q(").$_.q("); } } - ($got_arrayref ? @{$args[0]} + ($got_arrayref ? @{$args[0]} : @args ); - return $got_arrayref ? $args[0] + return $got_arrayref ? $args[0] : join(' ', @args); } @@ -173,6 +173,62 @@ sub _backticks { return `$cmd $args`; } +=item find_command + +Local an executable program + +=cut + +sub find_command { + my ($self, $command) = @_; + + # a lot of VMS executables have a symbol defined + # check those first + if ( $^O eq 'VMS' ) { + require VMS::DCLsym; + my $syms = VMS::DCLsym->new; + return $command if scalar $syms->getsym( uc $command ); + } + + $self->SUPER::find_command($command); +} + +# _maybe_command copied from ExtUtils::MM_VMS::maybe_command + +=item _maybe_command (override) + +Follows VMS naming conventions for executable files. +If the name passed in doesn't exactly match an executable file, +appends F<.Exe> (or equivalent) to check for executable image, and F<.Com> +to check for DCL procedure. If this fails, checks directories in DCL$PATH +and finally F<Sys$System:> for an executable file having the name specified, +with or without the F<.Exe>-equivalent suffix. + +=cut + +sub _maybe_command { + my($self,$file) = @_; + return $file if -x $file && ! -d _; + my(@dirs) = (''); + my(@exts) = ('',$Config{'exe_ext'},'.exe','.com'); + + if ($file !~ m![/:>\]]!) { + for (my $i = 0; defined $ENV{"DCL\$PATH;$i"}; $i++) { + my $dir = $ENV{"DCL\$PATH;$i"}; + $dir .= ':' unless $dir =~ m%[\]:]$%; + push(@dirs,$dir); + } + push(@dirs,'Sys$System:'); + foreach my $dir (@dirs) { + my $sysfile = "$dir$file"; + foreach my $ext (@exts) { + return $file if -x "$sysfile$ext" && ! -d _; + } + } + } + return; +} + =item do_system Override to ensure that we quote the arguments but not the command. @@ -182,7 +238,7 @@ Override to ensure that we quote the arguments but not the command. sub do_system { # The command must not be quoted but the arguments to it must be. my ($self, @cmd) = @_; - $self->log_info("@cmd\n"); + $self->log_verbose("@cmd\n"); my $cmd = shift @cmd; my $args = $self->_quote_args(@cmd); return !system("$cmd $args"); @@ -205,7 +261,7 @@ sub oneliner { =item _infer_xs_spec -Inherit the standard version but tweak the library file name to be +Inherit the standard version but tweak the library file name to be something Dynaloader can find. =cut @@ -250,7 +306,7 @@ sub rscan_dir { =item dist_dir -Inherit the standard version but replace embedded dots with underscores because +Inherit the standard version but replace embedded dots with underscores because a dot is the directory delimiter on VMS. =cut @@ -265,7 +321,7 @@ sub dist_dir { =item man3page_name -Inherit the standard version but chop the extra manpage delimiter off the front if +Inherit the standard version but chop the extra manpage delimiter off the front if there is one. The VMS version of splitdir('[.foo]') returns '', 'foo'. =cut @@ -367,7 +423,7 @@ sub _detildefy { $newdirs = File::Spec::Unix->catdir(@hdirs, @backup, @dirs); } - + # Now put the two cases back together $arg = File::Spec::Unix->catpath($hvol, $newdirs, $file); @@ -446,7 +502,7 @@ sub _unix_rpt { $unix_rpt = VMS::Feature::current("filename_unix_report"); } else { my $env_unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || ''; - $unix_rpt = $env_unix_rpt =~ /^[ET1]/i; + $unix_rpt = $env_unix_rpt =~ /^[ET1]/i; } return $unix_rpt; } @@ -459,7 +515,7 @@ sub _efs { $efs = VMS::Feature::current("efs_charset"); } else { my $env_efs = $ENV{'DECC$EFS_CHARSET'} || ''; - $efs = $env_efs =~ /^[ET1]/i; + $efs = $env_efs =~ /^[ET1]/i; } return $efs; } diff --git a/cpan/Module-Build/lib/Module/Build/Platform/VOS.pm b/cpan/Module-Build/lib/Module/Build/Platform/VOS.pm index be46a80416..2061b2cacb 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/VOS.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/VOS.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::VOS; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Base; diff --git a/cpan/Module-Build/lib/Module/Build/Platform/Windows.pm b/cpan/Module-Build/lib/Module/Build/Platform/Windows.pm index 6cf9da9cc3..fcaef5a409 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/Windows.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/Windows.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::Windows; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Config; @@ -39,7 +39,7 @@ sub ACTION_realclean { if ( lc $basename eq lc $self->build_script ) { if ( $self->build_bat ) { - $self->log_info("Deleting $basename.bat\n"); + $self->log_verbose("Deleting $basename.bat\n"); my $full_progname = $0; $full_progname =~ s/(?:\.bat)?$/.bat/i; @@ -207,22 +207,22 @@ sub split_like_shell { # into words. The algorithm below was bashed out by Randy and Ken # (mostly Randy), and there are a lot of regression tests, so we # should feel free to adjust if desired. - + (my $self, local $_) = @_; - + return @$_ if defined() && UNIVERSAL::isa($_, 'ARRAY'); - + my @argv; return @argv unless defined() && length(); - + my $arg = ''; my( $i, $quote_mode ) = ( 0, 0 ); - + while ( $i < length() ) { - + my $ch = substr( $_, $i , 1 ); my $next_ch = substr( $_, $i+1, 1 ); - + if ( $ch eq '\\' && $next_ch eq '"' ) { $arg .= '"'; $i++; @@ -249,10 +249,10 @@ sub split_like_shell { } else { $arg .= $ch; } - + $i++; } - + push( @argv, $arg ) if defined( $arg ) && length( $arg ); return @argv; } @@ -273,6 +273,27 @@ sub do_system { return !$status; } +# Copied from ExtUtils::MM_Win32 +sub _maybe_command { + my($self,$file) = @_; + my @e = exists($ENV{'PATHEXT'}) + ? split(/;/, $ENV{PATHEXT}) + : qw(.com .exe .bat .cmd); + my $e = ''; + for (@e) { $e .= "\Q$_\E|" } + chop $e; + # see if file ends in one of the known extensions + if ($file =~ /($e)$/i) { + return $file if -e $file; + } + else { + for (@e) { + return "$file$_" if -e "$file$_"; + } + } + return; +} + 1; diff --git a/cpan/Module-Build/lib/Module/Build/Platform/aix.pm b/cpan/Module-Build/lib/Module/Build/Platform/aix.pm index 45feb3cdd4..7ba3c322b6 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/aix.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/aix.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::aix; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Platform::Unix; diff --git a/cpan/Module-Build/lib/Module/Build/Platform/cygwin.pm b/cpan/Module-Build/lib/Module/Build/Platform/cygwin.pm index 62a6461ce2..8b882ed293 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/cygwin.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/cygwin.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::cygwin; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Platform::Unix; @@ -13,6 +13,22 @@ sub manpage_separator { '.' } +# Copied from ExtUtils::MM_Cygwin::maybe_command() +# If our path begins with F</cygdrive/> then we use C<ExtUtils::MM_Win32> +# to determine if it may be a command. Otherwise we use the tests +# from C<ExtUtils::MM_Unix>. + +sub _maybe_command { + my ($self, $file) = @_; + + if ($file =~ m{^/cygdrive/}i) { + require Module::Build::Platform::Win32; + return Module::Build::Platform::Win32->_maybe_command($file); + } + + return $self->SUPER::_maybe_command($file); +} + 1; __END__ diff --git a/cpan/Module-Build/lib/Module/Build/Platform/darwin.pm b/cpan/Module-Build/lib/Module/Build/Platform/darwin.pm index 39e9e36911..145933d478 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/darwin.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/darwin.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::darwin; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Platform::Unix; diff --git a/cpan/Module-Build/lib/Module/Build/Platform/os2.pm b/cpan/Module-Build/lib/Module/Build/Platform/os2.pm index ace01a3291..b6615c82c3 100644 --- a/cpan/Module-Build/lib/Module/Build/Platform/os2.pm +++ b/cpan/Module-Build/lib/Module/Build/Platform/os2.pm @@ -2,7 +2,7 @@ package Module::Build::Platform::os2; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use Module::Build::Platform::Unix; @@ -13,6 +13,16 @@ sub manpage_separator { '.' } sub have_forkpipe { 0 } +# Copied from ExtUtils::MM_OS2::maybe_command +sub _maybe_command { + my($self,$file) = @_; + $file =~ s,[/\\]+,/,g; + return $file if -x $file && ! -d _; + return "$file.exe" if -x "$file.exe" && ! -d _; + return "$file.cmd" if -x "$file.cmd" && ! -d _; + return; +} + 1; __END__ diff --git a/cpan/Module-Build/lib/Module/Build/PodParser.pm b/cpan/Module-Build/lib/Module/Build/PodParser.pm index b17b80b189..7a94e772ed 100644 --- a/cpan/Module-Build/lib/Module/Build/PodParser.pm +++ b/cpan/Module-Build/lib/Module/Build/PodParser.pm @@ -2,7 +2,7 @@ package Module::Build::PodParser; use strict; use vars qw($VERSION); -$VERSION = '0.35'; +$VERSION = '0.35_08'; $VERSION = eval $VERSION; use vars qw(@ISA); @@ -33,31 +33,31 @@ sub new { sub _myparse_from_filehandle { my ($self, $fh) = @_; - + local $_; while (<$fh>) { next unless /^=(?!cut)/ .. /^=cut/; # in POD last if ($self->{abstract}) = /^ (?: [a-z:]+ \s+ - \s+ ) (.*\S) /ix; } - + my @author; while (<$fh>) { - next unless /^=head1\s+AUTHORS?/ ... /^=/; + next unless /^=head1\s+AUTHORS?/i ... /^=/; next if /^=/; push @author, $_ if /\@/; } return unless @author; s/^\s+|\s+$//g foreach @author; - + $self->{author} = \@author; - + return; } sub get_abstract { my $self = shift; return $self->{abstract} if defined $self->{abstract}; - + $self->parse_from_filehandle($self->{fh}); return $self->{abstract}; @@ -66,7 +66,7 @@ sub get_abstract { sub get_author { my $self = shift; return $self->{author} if defined $self->{author}; - + $self->parse_from_filehandle($self->{fh}); return $self->{author} || []; @@ -92,10 +92,10 @@ sub textblock { my ($self, $text) = @_; $text =~ s/^\s+//; $text =~ s/\s+$//; - if ($self->{_head} eq 'NAME') { + if (uc $self->{_head} eq 'NAME') { my ($name, $abstract) = split( /\s+-\s+/, $text, 2 ); $self->{abstract} = $abstract; - } elsif ($self->{_head} =~ /^AUTHORS?$/) { + } elsif ($self->{_head} =~ /^AUTHORS?$/i) { push @{$self->{author}}, $text if $text =~ /\@/; } } diff --git a/cpan/Module-Build/lib/Module/Build/Version.pm b/cpan/Module-Build/lib/Module/Build/Version.pm index 0664d432ab..4a1b961fbd 100644 --- a/cpan/Module-Build/lib/Module/Build/Version.pm +++ b/cpan/Module-Build/lib/Module/Build/Version.pm @@ -81,7 +81,7 @@ sub import { map { $args{$_} = 1 } @_ } else { # no parameters at all on use line - %args = + args = ( qv => 1, 'UNIVERSAL::VERSION' => 1, @@ -89,9 +89,9 @@ sub import { } my $callpkg = caller(); - + if (exists($args{declare})) { - *{$callpkg."::declare"} = + *{$callpkg."::declare"} = sub {return $class->declare(shift) } unless defined(&{$callpkg.'::declare'}); } @@ -155,7 +155,7 @@ sub new { my ($class, $value) = @_; my $self = bless ({}, ref ($class) || $class); - + if ( ref($value) && eval('$value->isa("version")') ) { # Can copy the elements directly $self->{version} = [ @{$value->{version} } ]; @@ -193,7 +193,7 @@ sub new $value = sprintf("%.9f",$value); $value =~ s/(0+)$//; # trim trailing zeros } - + # This is not very efficient, but it is morally equivalent # to the XS code (as that is the reference implementation). # See vutil/vutil.c for details @@ -215,7 +215,7 @@ sub new } $start = $last = $pos = $s; - + # pre-scan the input string to check for decimals/underbars while ( substr($value,$pos,1) =~ /[._\d,]/ ) { if ( substr($value,$pos,1) eq '.' ) { @@ -300,7 +300,7 @@ sub new $orev = $rev; $rev += substr($value,$s,1) * $mult; $mult /= 10; - if ( abs($orev) > abs($rev) + if ( abs($orev) > abs($rev) || abs($rev) > abs($VERSION_MAX) ) { if ( warnings::enabled("overflow") ) { require Carp; @@ -320,7 +320,7 @@ sub new $orev = $rev; $rev += substr($value,$end,1) * $mult; $mult *= 10; - if ( abs($orev) > abs($rev) + if ( abs($orev) > abs($rev) || abs($rev) > abs($VERSION_MAX) ) { if ( warnings::enabled("overflow") ) { require Carp; @@ -335,15 +335,15 @@ sub new # Append revision push @{$self->{version}}, $rev; - if ( substr($value,$pos,1) eq '.' + if ( substr($value,$pos,1) eq '.' && substr($value,$pos+1,1) =~ /\d/ ) { $s = ++$pos; } - elsif ( substr($value,$pos,1) eq '_' + elsif ( substr($value,$pos,1) eq '_' && substr($value,$pos+1,1) =~ /\d/ ) { $s = ++$pos; } - elsif ( substr($value,$pos,1) eq ',' + elsif ( substr($value,$pos,1) eq ',' && substr($value,$pos+1,1) =~ /\d/ ) { $s = ++$pos; } @@ -400,7 +400,7 @@ sub new *parse = \&new; -sub numify +sub numify { my ($self) = @_; unless (_verify($self)) { @@ -441,7 +441,7 @@ sub numify return $string; } -sub normal +sub normal { my ($self) = @_; unless (_verify($self)) { @@ -484,9 +484,9 @@ sub stringify require Carp; Carp::croak("Invalid version object"); } - return exists $self->{original} - ? $self->{original} - : exists $self->{qv} + return exists $self->{original} + ? $self->{original} + : exists $self->{qv} ? $self->normal : $self->numify; } @@ -524,8 +524,8 @@ sub vcmp } # tiebreaker for alpha with identical terms - if ( $retval == 0 - && $l == $r + if ( $retval == 0 + && $l == $r && $left->{version}[$m] == $right->{version}[$m] && ( $lalpha || $ralpha ) ) { @@ -557,7 +557,7 @@ sub vcmp } } - return $retval; + return $retval; } sub vbool { @@ -565,8 +565,8 @@ sub vbool { return vcmp($self,$self->new("0"),1); } -sub vnoop { - require Carp; +sub vnoop { + require Carp; Carp::croak("operation not supported with version object"); } @@ -644,7 +644,7 @@ sub _VERSION { if ( defined $req ) { unless ( defined $version ) { require Carp; - my $msg = $] < 5.006 + my $msg = $] < 5.006 ? "$class version $req required--this is only version " : "$class does not define \$$class\::VERSION" ."--version check failed"; @@ -662,14 +662,14 @@ sub _VERSION { if ( $req > $version ) { require Carp; if ( $req->is_qv ) { - Carp::croak( + Carp::croak( sprintf ("%s version %s required--". "this is only version %s", $class, $req->normal, $version->normal) ); } else { - Carp::croak( + Carp::croak( sprintf ("%s version %s required--". "this is only version %s", $class, $req->stringify, $version->stringify) diff --git a/cpan/Module-Build/lib/Module/Build/YAML.pm b/cpan/Module-Build/lib/Module/Build/YAML.pm index 4a181ad1c9..2da91f2256 100644 --- a/cpan/Module-Build/lib/Module/Build/YAML.pm +++ b/cpan/Module-Build/lib/Module/Build/YAML.pm @@ -1,161 +1,600 @@ +# Adapted from YAML::Tiny 1.40 package Module::Build::YAML; use strict; -use vars qw($VERSION @EXPORT @EXPORT_OK); -$VERSION = "0.50"; -@EXPORT = (); -@EXPORT_OK = qw(Dump Load DumpFile LoadFile); +use Carp 'croak'; +# UTF Support? +sub HAVE_UTF8 () { $] >= 5.007003 } +BEGIN { + if ( HAVE_UTF8 ) { + # The string eval helps hide this from Test::MinimumVersion + eval "require utf8;"; + die "Failed to load UTF-8 support" if $@; + } + + # Class structure + require 5.004; + + $Module::Build::YAML::VERSION = '1.40'; + + # Error storage + $Module::Build::YAML::errstr = ''; +} + +# The character class of all characters we need to escape +# NOTE: Inlined, since it's only used once +# my $RE_ESCAPE = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f\"\n]'; + +# Printed form of the unprintable characters in the lowest range +# of ASCII characters, listed by ASCII ordinal position. +my @UNPRINTABLE = qw( + z x01 x02 x03 x04 x05 x06 a + x08 t n v f r x0e x0f + x10 x11 x12 x13 x14 x15 x16 x17 + x18 x19 x1a e x1c x1d x1e x1f +); + +# Printable characters for escapes +my %UNESCAPES = ( + z => "\x00", a => "\x07", t => "\x09", + n => "\x0a", v => "\x0b", f => "\x0c", + r => "\x0d", e => "\x1b", '\\' => '\\', +); + +# Special magic boolean words +my %QUOTE = map { $_ => 1 } qw{ + null Null NULL + y Y yes Yes YES n N no No NO + true True TRUE false False FALSE + on On ON off Off OFF +}; + +##################################################################### +# Implementation + +# Create an empty Module::Build::YAML object sub new { - my $this = shift; - my $class = ref($this) || $this; - my $self = {}; - bless $self, $class; - return($self); + my $class = shift; + bless [ @_ ], $class; } -sub Dump { - shift if ($_[0] eq __PACKAGE__ || ref($_[0]) eq __PACKAGE__); - my $yaml = ""; - foreach my $item (@_) { - $yaml .= "---\n"; - $yaml .= &_yaml_chunk("", $item); - } - return $yaml; +# Create an object from a file +sub read { + my $class = ref $_[0] ? ref shift : shift; + + # Check the file + my $file = shift or return $class->_error( 'You did not specify a file name' ); + return $class->_error( "File '$file' does not exist" ) unless -e $file; + return $class->_error( "'$file' is a directory, not a file" ) unless -f _; + return $class->_error( "Insufficient permissions to read '$file'" ) unless -r _; + + # Slurp in the file + local $/ = undef; + local *CFG; + unless ( open(CFG, $file) ) { + return $class->_error("Failed to open file '$file': $!"); + } + my $contents = <CFG>; + unless ( close(CFG) ) { + return $class->_error("Failed to close file '$file': $!"); + } + + $class->read_string( $contents ); } -sub Load { - shift if ($_[0] eq __PACKAGE__ || ref($_[0]) eq __PACKAGE__); - die "not yet implemented"; +# Create an object from a string +sub read_string { + my $class = ref $_[0] ? ref shift : shift; + my $self = bless [], $class; + my $string = $_[0]; + unless ( defined $string ) { + return $self->_error("Did not provide a string to load"); + } + + # Byte order marks + # NOTE: Keeping this here to educate maintainers + # my %BOM = ( + # "\357\273\277" => 'UTF-8', + # "\376\377" => 'UTF-16BE', + # "\377\376" => 'UTF-16LE', + # "\377\376\0\0" => 'UTF-32LE' + # "\0\0\376\377" => 'UTF-32BE', + # ); + if ( $string =~ /^(?:\376\377|\377\376|\377\376\0\0|\0\0\376\377)/ ) { + return $self->_error("Stream has a non UTF-8 BOM"); + } else { + # Strip UTF-8 bom if found, we'll just ignore it + $string =~ s/^\357\273\277//; + } + + # Try to decode as utf8 + utf8::decode($string) if HAVE_UTF8; + + # Check for some special cases + return $self unless length $string; + unless ( $string =~ /[\012\015]+\z/ ) { + return $self->_error("Stream does not end with newline character"); + } + + # Split the file into lines + my @lines = grep { ! /^\s*(?:\#.*)?\z/ } + split /(?:\015{1,2}\012|\015|\012)/, $string; + + # Strip the initial YAML header + @lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines; + + # A nibbling parser + while ( @lines ) { + # Do we have a document header? + if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) { + # Handle scalar documents + shift @lines; + if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) { + push @$self, $self->_read_scalar( "$1", [ undef ], \@lines ); + next; + } + } + + if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) { + # A naked document + push @$self, undef; + while ( @lines and $lines[0] !~ /^---/ ) { + shift @lines; + } + + } elsif ( $lines[0] =~ /^\s*\-/ ) { + # An array at the root + my $document = [ ]; + push @$self, $document; + $self->_read_array( $document, [ 0 ], \@lines ); + + } elsif ( $lines[0] =~ /^(\s*)\S/ ) { + # A hash at the root + my $document = { }; + push @$self, $document; + $self->_read_hash( $document, [ length($1) ], \@lines ); + + } else { + croak("Module::Build::YAML failed to classify the line '$lines[0]'"); + } + } + + $self; } -# This is basically copied out of YAML.pm and simplified a little. -sub DumpFile { - shift if ($_[0] eq __PACKAGE__ || ref($_[0]) eq __PACKAGE__); - my $filename = shift; - local $/ = "\n"; # reset special to "sane" - my $mode = '>'; - if ($filename =~ /^\s*(>{1,2})\s*(.*)$/) { - ($mode, $filename) = ($1, $2); - } - open my $OUT, "$mode $filename" - or die "Can't open $filename for writing: $!"; - binmode($OUT, ':utf8') if $] >= 5.008; - print $OUT Dump(@_); - close $OUT; -} - -# This is basically copied out of YAML.pm and simplified a little. -sub LoadFile { - shift if ($_[0] eq __PACKAGE__ || ref($_[0]) eq __PACKAGE__); - my $filename = shift; - open my $IN, $filename - or die "Can't open $filename for reading: $!"; - binmode($IN, ':utf8') if $] >= 5.008; - return Load(do { local $/; <$IN> }); - close $IN; -} - -sub _yaml_chunk { - my ($indent, $values) = @_; - my $yaml_chunk = ""; - my $ref = ref($values); - my ($value, @allkeys, %keyseen); - if (!$ref) { # a scalar - $yaml_chunk .= &_yaml_value($values) . "\n"; - } - elsif ($ref eq "ARRAY") { - foreach $value (@$values) { - $yaml_chunk .= "$indent-"; - $ref = ref($value); - if (!$ref) { - $yaml_chunk .= " " . &_yaml_value($value) . "\n"; - } - else { - $yaml_chunk .= "\n"; - $yaml_chunk .= &_yaml_chunk("$indent ", $value); - } - } - } - else { # assume "HASH" - if ($values->{_order} && ref($values->{_order}) eq "ARRAY") { - @allkeys = @{$values->{_order}}; - $values = { %$values }; - delete $values->{_order}; - } - push(@allkeys, sort keys %$values); - foreach my $key (@allkeys) { - next if (!defined $key || $key eq "" || $keyseen{$key}); - $keyseen{$key} = 1; - $yaml_chunk .= "$indent$key:"; - $value = $values->{$key}; - $ref = ref($value); - if (!$ref) { - $yaml_chunk .= " " . &_yaml_value($value) . "\n"; - } - else { - $yaml_chunk .= "\n"; - $yaml_chunk .= &_yaml_chunk("$indent ", $value); - } - } - } - return($yaml_chunk); -} - -sub _yaml_value { - my ($value) = @_; - # undefs become ~ - return '~' if not defined $value; - - # empty strings will become empty strings - return '""' if $value eq ''; - - # allow simple scalars (without embedded quote chars) to be unquoted - # (includes $%_+=-\;:,./) - return $value if $value !~ /["'`~\n!\@\#^\&\*\(\)\{\}\[\]\|<>\?]/; - - # quote and escape strings with special values - return "'$value'" - if $value !~ /['`~\n!\#^\&\*\(\)\{\}\[\]\|\?]/; # nothing but " or @ or < or > (email addresses) - - $value =~ s/\n/\\n/g; # handle embedded newlines - $value =~ s/"/\\"/g; # handle embedded quotes - return qq{"$value"}; +# Deparse a scalar string to the actual scalar +sub _read_scalar { + my ($self, $string, $indent, $lines) = @_; + + # Trim trailing whitespace + $string =~ s/\s*\z//; + + # Explitic null/undef + return undef if $string eq '~'; + + # Quotes + if ( $string =~ /^\'(.*?)\'\z/ ) { + return '' unless defined $1; + $string = $1; + $string =~ s/\'\'/\'/g; + return $string; + } + if ( $string =~ /^\"((?:\\.|[^\"])*)\"\z/ ) { + # Reusing the variable is a little ugly, + # but avoids a new variable and a string copy. + $string = $1; + $string =~ s/\\"/"/g; + $string =~ s/\\([never\\fartz]|x([0-9a-fA-F]{2}))/(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}/gex; + return $string; + } + + # Special cases + if ( $string =~ /^[\'\"!&]/ ) { + croak("Module::Build::YAML does not support a feature in line '$lines->[0]'"); + } + return {} if $string eq '{}'; + return [] if $string eq '[]'; + + # Regular unquoted string + return $string unless $string =~ /^[>|]/; + + # Error + croak("Module::Build::YAML failed to find multi-line scalar content") unless @$lines; + + # Check the indent depth + $lines->[0] =~ /^(\s*)/; + $indent->[-1] = length("$1"); + if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) { + croak("Module::Build::YAML found bad indenting in line '$lines->[0]'"); + } + + # Pull the lines + my @multiline = (); + while ( @$lines ) { + $lines->[0] =~ /^(\s*)/; + last unless length($1) >= $indent->[-1]; + push @multiline, substr(shift(@$lines), length($1)); + } + + my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n"; + my $t = (substr($string, 1, 1) eq '-') ? '' : "\n"; + return join( $j, @multiline ) . $t; } -1; +# Parse an array +sub _read_array { + my ($self, $array, $indent, $lines) = @_; -__END__ + while ( @$lines ) { + # Check for a new document + if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) { + while ( @$lines and $lines->[0] !~ /^---/ ) { + shift @$lines; + } + return 1; + } + + # Check the indent level + $lines->[0] =~ /^(\s*)/; + if ( length($1) < $indent->[-1] ) { + return 1; + } elsif ( length($1) > $indent->[-1] ) { + croak("Module::Build::YAML found bad indenting in line '$lines->[0]'"); + } + + if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) { + # Inline nested hash + my $indent2 = length("$1"); + $lines->[0] =~ s/-/ /; + push @$array, { }; + $self->_read_hash( $array->[-1], [ @$indent, $indent2 ], $lines ); + + } elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) { + # Array entry with a value + shift @$lines; + push @$array, $self->_read_scalar( "$2", [ @$indent, undef ], $lines ); -=head1 NAME + } elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) { + shift @$lines; + unless ( @$lines ) { + push @$array, undef; + return 1; + } + if ( $lines->[0] =~ /^(\s*)\-/ ) { + my $indent2 = length("$1"); + if ( $indent->[-1] == $indent2 ) { + # Null array entry + push @$array, undef; + } else { + # Naked indenter + push @$array, [ ]; + $self->_read_array( $array->[-1], [ @$indent, $indent2 ], $lines ); + } -Module::Build::YAML - Provides just enough YAML support so that Module::Build works even if YAML.pm is not installed + } elsif ( $lines->[0] =~ /^(\s*)\S/ ) { + push @$array, { }; + $self->_read_hash( $array->[-1], [ @$indent, length("$1") ], $lines ); -=head1 SYNOPSIS + } else { + croak("Module::Build::YAML failed to classify line '$lines->[0]'"); + } - use Module::Build::YAML; + } elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) { + # This is probably a structure like the following... + # --- + # foo: + # - list + # bar: value + # + # ... so lets return and let the hash parser handle it + return 1; - ... + } else { + croak("Module::Build::YAML failed to classify line '$lines->[0]'"); + } + } -=head1 DESCRIPTION + return 1; +} + +# Parse an array +sub _read_hash { + my ($self, $hash, $indent, $lines) = @_; + + while ( @$lines ) { + # Check for a new document + if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) { + while ( @$lines and $lines->[0] !~ /^---/ ) { + shift @$lines; + } + return 1; + } -Provides just enough YAML support so that Module::Build works even if YAML.pm is not installed. + # Check the indent level + $lines->[0] =~ /^(\s*)/; + if ( length($1) < $indent->[-1] ) { + return 1; + } elsif ( length($1) > $indent->[-1] ) { + croak("Module::Build::YAML found bad indenting in line '$lines->[0]'"); + } -Currently, this amounts to the ability to write META.yml files when C<perl Build distmeta> -is executed via the Dump() and DumpFile() functions/methods. + # Get the key + unless ( $lines->[0] =~ s/^\s*([^\'\" ][^\n]*?)\s*:(\s+|$)// ) { + if ( $lines->[0] =~ /^\s*[?\'\"]/ ) { + croak("Module::Build::YAML does not support a feature in line '$lines->[0]'"); + } + croak("Module::Build::YAML failed to classify line '$lines->[0]'"); + } + my $key = $1; -=head1 AUTHOR + # Do we have a value? + if ( length $lines->[0] ) { + # Yes + $hash->{$key} = $self->_read_scalar( shift(@$lines), [ @$indent, undef ], $lines ); + } else { + # An indent + shift @$lines; + unless ( @$lines ) { + $hash->{$key} = undef; + return 1; + } + if ( $lines->[0] =~ /^(\s*)-/ ) { + $hash->{$key} = []; + $self->_read_array( $hash->{$key}, [ @$indent, length($1) ], $lines ); + } elsif ( $lines->[0] =~ /^(\s*)./ ) { + my $indent2 = length("$1"); + if ( $indent->[-1] >= $indent2 ) { + # Null hash entry + $hash->{$key} = undef; + } else { + $hash->{$key} = {}; + $self->_read_hash( $hash->{$key}, [ @$indent, length($1) ], $lines ); + } + } + } + } -Stephen Adkins <spadkins@gmail.com> + return 1; +} + +# Save an object to a file +sub write { + my $self = shift; + my $file = shift or return $self->_error('No file name provided'); -=head1 COPYRIGHT + # Write it to the file + open( CFG, '>' . $file ) or return $self->_error( + "Failed to open file '$file' for writing: $!" + ); + print CFG $self->write_string; + close CFG; -Copyright (c) 2006. Stephen Adkins. All rights reserved. + return 1; +} -This program is free software; you can redistribute it and/or modify it -under the same terms as Perl itself. +# Save an object to a string +sub write_string { + my $self = shift; + return '' unless @$self; -See L<http://www.perl.com/perl/misc/Artistic.html> + # Iterate over the documents + my $indent = 0; + my @lines = (); + foreach my $cursor ( @$self ) { + push @lines, '---'; -=cut + # An empty document + if ( ! defined $cursor ) { + # Do nothing + + # A scalar document + } elsif ( ! ref $cursor ) { + $lines[-1] .= ' ' . $self->_write_scalar( $cursor, $indent ); + + # A list at the root + } elsif ( ref $cursor eq 'ARRAY' ) { + unless ( @$cursor ) { + $lines[-1] .= ' []'; + next; + } + push @lines, $self->_write_array( $cursor, $indent, {} ); + + # A hash at the root + } elsif ( ref $cursor eq 'HASH' ) { + unless ( %$cursor ) { + $lines[-1] .= ' {}'; + next; + } + push @lines, $self->_write_hash( $cursor, $indent, {} ); + + } else { + croak("Cannot serialize " . ref($cursor)); + } + } + + join '', map { "$_\n" } @lines; +} + +sub _write_scalar { + my $string = $_[1]; + return '~' unless defined $string; + return "''" unless length $string; + if ( $string =~ /[\x00-\x08\x0b-\x0d\x0e-\x1f\"\'\n]/ ) { + $string =~ s/\\/\\\\/g; + $string =~ s/"/\\"/g; + $string =~ s/\n/\\n/g; + $string =~ s/([\x00-\x1f])/\\$UNPRINTABLE[ord($1)]/g; + return qq|"$string"|; + } + if ( $string =~ /(?:^\W|\s)/ or $QUOTE{$string} ) { + return "'$string'"; + } + return $string; +} + +sub _write_array { + my ($self, $array, $indent, $seen) = @_; + if ( $seen->{refaddr($array)}++ ) { + die "Module::Build::YAML does not support circular references"; + } + my @lines = (); + foreach my $el ( @$array ) { + my $line = (' ' x $indent) . '-'; + my $type = ref $el; + if ( ! $type ) { + $line .= ' ' . $self->_write_scalar( $el, $indent + 1 ); + push @lines, $line; + + } elsif ( $type eq 'ARRAY' ) { + if ( @$el ) { + push @lines, $line; + push @lines, $self->_write_array( $el, $indent + 1, $seen ); + } else { + $line .= ' []'; + push @lines, $line; + } + + } elsif ( $type eq 'HASH' ) { + if ( keys %$el ) { + push @lines, $line; + push @lines, $self->_write_hash( $el, $indent + 1, $seen ); + } else { + $line .= ' {}'; + push @lines, $line; + } + + } else { + die "Module::Build::YAML does not support $type references"; + } + } + + @lines; +} + +sub _write_hash { + my ($self, $hash, $indent, $seen) = @_; + if ( $seen->{refaddr($hash)}++ ) { + die "Module::Build::YAML does not support circular references"; + } + my @lines = (); + foreach my $name ( sort keys %$hash ) { + my $el = $hash->{$name}; + my $line = (' ' x $indent) . "$name:"; + my $type = ref $el; + if ( ! $type ) { + $line .= ' ' . $self->_write_scalar( $el, $indent + 1 ); + push @lines, $line; + + } elsif ( $type eq 'ARRAY' ) { + if ( @$el ) { + push @lines, $line; + push @lines, $self->_write_array( $el, $indent + 1, $seen ); + } else { + $line .= ' []'; + push @lines, $line; + } + + } elsif ( $type eq 'HASH' ) { + if ( keys %$el ) { + push @lines, $line; + push @lines, $self->_write_hash( $el, $indent + 1, $seen ); + } else { + $line .= ' {}'; + push @lines, $line; + } + + } else { + die "Module::Build::YAML does not support $type references"; + } + } + + @lines; +} + +# Set error +sub _error { + $Module::Build::YAML::errstr = $_[1]; + undef; +} + +# Retrieve error +sub errstr { + $Module::Build::YAML::errstr; +} + +##################################################################### +# YAML Compatibility + +sub Dump { + Module::Build::YAML->new(@_)->write_string; +} + +sub Load { + my $self = Module::Build::YAML->read_string(@_); + unless ( $self ) { + croak("Failed to load YAML document from string"); + } + if ( wantarray ) { + return @$self; + } else { + # To match YAML.pm, return the last document + return $self->[-1]; + } +} + +BEGIN { + *freeze = *Dump; + *thaw = *Load; +} + +sub DumpFile { + my $file = shift; + Module::Build::YAML->new(@_)->write($file); +} + +sub LoadFile { + my $self = Module::Build::YAML->read($_[0]); + unless ( $self ) { + croak("Failed to load YAML document from '" . ($_[0] || '') . "'"); + } + if ( wantarray ) { + return @$self; + } else { + # Return only the last document to match YAML.pm, + return $self->[-1]; + } +} + +##################################################################### +# Use Scalar::Util if possible, otherwise emulate it + +BEGIN { + eval { + require Scalar::Util; + }; + if ( $@ ) { + # Failed to load Scalar::Util + eval <<'END_PERL'; +sub refaddr { + my $pkg = ref($_[0]) or return undef; + if (!!UNIVERSAL::can($_[0], 'can')) { + bless $_[0], 'Scalar::Util::Fake'; + } else { + $pkg = undef; + } + "$_[0]" =~ /0x(\w+)/; + my $i = do { local $^W; hex $1 }; + bless $_[0], $pkg if defined $pkg; + $i; +} +END_PERL + } else { + Scalar::Util->import('refaddr'); + } +} + +1; + +__END__ diff --git a/cpan/Module-Build/lib/inc/latest.pm b/cpan/Module-Build/lib/inc/latest.pm new file mode 100644 index 0000000000..9d4a38006b --- /dev/null +++ b/cpan/Module-Build/lib/inc/latest.pm @@ -0,0 +1,250 @@ +package inc::latest; +use strict; +use vars qw($VERSION); +$VERSION = '0.35_08'; +$VERSION = eval $VERSION; + +use Carp; +use File::Basename (); +use File::Spec (); +use File::Path (); +use IO::File (); +use File::Copy (); + +# track and return modules loaded by inc::latest +my @loaded_modules; +sub loaded_modules {@loaded_modules} + +# must ultimately "goto" the import routine of the module to be loaded +# so that the calling package is correct when $mod->import() runs. +sub import { + my ($package, $mod, @args) = @_; + return unless(defined $mod); + + my $inc_path = './inc/latest.pm'; + my $private_path = './inc/latest/private.pm'; + if(-e $inc_path) { + # delete our methods + delete $inc::latest::{$_} for(keys %inc::latest::); + # load the bundled module + require $inc_path; + require $private_path; + my $import = inc::latest->can('import'); + goto $import; + } + + # author mode - just record and load the modules + push(@loaded_modules, $mod); + require inc::latest::private; + goto \&inc::latest::private::_load_module; +} + +sub write { + my $package = shift; + my ($where, @preload) = @_; + + warn "should really be writing in inc/" unless $where =~ /inc$/; + + # write inc/latest.pm + File::Path::mkpath( $where ); + my $fh = IO::File->new( File::Spec->catfile($where,'latest.pm'), "w" ); + print {$fh} "# This stub created by inc::latest $VERSION\n"; + print {$fh} <<'HERE'; +package inc::latest; +use strict; +use vars '@ISA'; +require inc::latest::private; +@ISA = qw/inc::latest::private/; +HERE + if (@preload) { + print {$fh} "\npackage inc::latest::preload;\n"; + for my $mod (@preload) { + print {$fh} "inc::latest->import('$mod');\n"; + } + } + print {$fh} "\n1;\n"; + close $fh; + + # write inc/latest/private; + require inc::latest::private; + File::Path::mkpath( File::Spec->catdir( $where, 'latest' ) ); + my $from = $INC{'inc/latest/private.pm'}; + my $to = File::Spec->catfile($where,'latest','private.pm'); + File::Copy::copy( $from, $to ) or die "Couldn't copy '$from' to '$to': $!"; + + return 1; +} + +sub bundle_module { + my ($package, $module, $where) = @_; + + # create inc/inc_$foo + (my $dist = $module) =~ s{::}{-}g; + my $inc_lib = File::Spec->catdir($where,"inc_$dist"); + File::Path::mkpath $inc_lib; + + # get list of files to copy + require ExtUtils::Installed; + # workaround buggy EU::Installed check of @INC + my $inst = ExtUtils::Installed->new(extra_libs => [@INC]); + my $packlist = $inst->packlist( $module ) or die "Couldn't find packlist"; + my @files = grep { /\.pm$/ } keys %$packlist; + + + # figure out prefix + my $mod_path = quotemeta $package->_mod2path( $module ); + my ($prefix) = grep { /$mod_path$/ } @files; + $prefix =~ s{$mod_path$}{}; + + # copy files + for my $from ( @files ) { + next unless $from =~ /\.pm$/; + (my $mod_path = $from) =~ s{^\Q$prefix\E}{}; + my $to = File::Spec->catfile( $inc_lib, $mod_path ); + File::Path::mkpath(File::Basename::dirname($to)); + File::Copy::copy( $from, $to ) or die "Couldn't copy '$from' to '$to': $!"; + } + return 1; +} + +# Translate a module name into a directory/file.pm to search for in @INC +sub _mod2path { + my ($self, $mod) = @_; + my @parts = split /::/, $mod; + $parts[-1] .= '.pm'; + return $parts[0] if @parts == 1; + return File::Spec->catfile(@parts); +} + +1; + + +=head1 NAME + +inc::latest - use modules bundled in inc/ if they are newer than installed ones + +=head1 SYNOPSIS + + # in Build.PL + use inc::latest 'Module::Build'; + +=head1 DESCRIPTION + +The C<inc::latest> module helps bootstrap configure-time dependencies for CPAN +distributions. These dependencies get bundled into the C<inc> directory within +a distribution and are used by Build.PL (or Makefile.PL). + +Arguments to C<inc::latest> are module names that are checked against both the +current C<@INC> array and against specially-named directories in C<inc>. If +the bundled verison is newer than the installed one (or the module isn't +installed, then, the bundled directory is added to the start of <@INC> and the +module is loaded from there. + +There are actually two variations of C<inc::latest> -- one for authors and one +for the C<inc> directory. For distribution authors, the C<inc::latest> +installed in the system will record modules loaded via C<inc::latest> and can +be used to create the bundled files in C<inc>, including writing the second +variation as C<inc/latest.pm>. + +This second C<inc::latest> is the one that is loaded in a distribution being +installed (e.g. from Build.PL). This bundled C<inc::latest> is the one +that determines which module to load. + +=head2 Special notes on bundling + +The C<inc::latest> module creates bundled directories based on the packlist +file of an installed distribution. Even though C<inc::latest> takes module +name arguments, it is better to think of it as bundling and making available +entire I<distributions>. When a module is loaded through C<inc::latest>, +it looks in all bundled distributions in C<inc/> for a newer module than +can be found in the existing C<@INC> array. + +Thus, the module-name provided should usually be the "top-level" module name of +a distribution, though this is not strictly required. For example, +L<Module::Build> has a number of heuristics to map module names to packlists, +allowing users to do things like this: + + use inc::latest 'Devel::AssertOS::Unix'; + +even though Devel::AssertOS::Unix is contained within the Devel-CheckOS +distribution. + +At the current time, packlists are required. Thus, bundling dual-core modules +may require a 'forced install' over versions in the latest version of perl +in order to create the necessary packlist for bundling. + +=head1 USAGE + +When calling C<use>, the bundled C<inc::latest> takes a single module name and +optional arguments to pass to that module's own import method. + + use 'inc::latest' 'Foo::Bar' qw/foo bar baz/; + +=head2 Author-mode + +You are in author-mode inc::latest if any of the Author-mode methods are +available. For example: + + if ( inc::latest->can('write') ) { + inc::latest->write('inc'); + } + +=over 4 + +=item loaded_modules() + + my @list = inc::latest->loaded_modules; + +This takes no arguments and always returns a list of module names requested for +loading via "use inc::latest 'MODULE'", regardless of wether the load was +successful or not. + +=item write() + + inc::latest->write( 'inc' ); + +This writes the bundled version of inc::latest to the directory name given as an +argument. It almost all cases, it should be 'C<inc>'. + +=item bundle_module() + + for my $mod ( inc::latest->loaded_modules ) { + inc::latest->bundle_module($mod, $dir); + } + +If $mod corresponds to a packlist, then this function creates a specially-named +directory in $dir and copies all .pm files from the modlist to the new +directory (which almost always should just be 'inc'). For example, if Foo::Bar +is the name of the module, and $dir is 'inc', then the directory would be +'inc/inc_Foo-Bar' and contain files like this: + + inc/inc_Foo-Bar/Foo/Bar.pm + +Currently, $mod B<must> have a packlist. If this is not the case (e.g. for a +dual-core module), then the bundling will fail. You may be able to create a +packlist by forced installing the module on top of the version that came with +core Perl. + +=back + +=head2 As bundled in inc/ + +All methods are private. Only the C<import> method is public. + +=head1 AUTHOR + +Eric Wilhelm <ewilhelm@cpan.org>, David Golden <dagolden@cpan.org> + +=head1 COPYRIGHT + +Copyright (c) 2009 by Eric Wilhelm and David Golden + +This library is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Module::Build> + +=cut + diff --git a/cpan/Module-Build/lib/inc/latest/private.pm b/cpan/Module-Build/lib/inc/latest/private.pm new file mode 100644 index 0000000000..285514bc38 --- /dev/null +++ b/cpan/Module-Build/lib/inc/latest/private.pm @@ -0,0 +1,101 @@ +package inc::latest::private; +use strict; +use vars qw($VERSION); +$VERSION = '0.35_08'; +$VERSION = eval $VERSION; + +use File::Spec; +use IO::File; + +# must ultimately "goto" the import routine of the module to be loaded +# so that the calling package is correct when $mod->import() runs. +sub import { + my ($package, $mod, @args) = @_; + my $file = $package->_mod2path($mod); + + if ($INC{$file}) { + # Already loaded, but let _load_module handle import args + goto \&_load_module; + } + + # A bundled copy must be present + my ($bundled, $bundled_dir) = $package->_search_bundled($file) + or die "No bundled copy of $mod found"; + + my $from_inc = $package->_search_INC($file); + unless ($from_inc) { + # Only bundled is available + unshift(@INC, $bundled_dir); + goto \&_load_module; + } + + if (_version($from_inc) >= _version($bundled)) { + # Ignore the bundled copy + goto \&_load_module; + } + + # Load the bundled copy + unshift(@INC, $bundled_dir); + goto \&_load_module; +} + +sub _version { + require ExtUtils::MakeMaker; + return ExtUtils::MM->parse_version(shift); +} + +# use "goto" for import to preserve caller +sub _load_module { + my $package = shift; # remaining @_ is ready for goto + my ($mod, @args) = @_; + eval "require $mod; 1" or die $@; + if ( my $import = $mod->can('import') ) { + goto $import; + } + return 1; +} + +sub _search_bundled { + my ($self, $file) = @_; + + my $mypath = 'inc'; + + local *DH; # Maintain 5.005 compatibility + opendir DH, $mypath or die "Can't open directory $mypath: $!"; + + while (defined(my $e = readdir DH)) { + next unless $e =~ /^inc_/; + my $try = File::Spec->catfile($mypath, $e, $file); + + return($try, File::Spec->catdir($mypath, $e)) if -e $try; + } + return; +} + +# Look for the given path in @INC. +sub _search_INC { + # TODO: doesn't handle coderefs or arrayrefs or objects in @INC, but + # it probably should + my ($self, $file) = @_; + + foreach my $dir (@INC) { + next if ref $dir; + my $try = File::Spec->catfile($dir, $file); + return $try if -e $try; + } + + return; +} + +# Translate a module name into a directory/file.pm to search for in @INC +sub _mod2path { + my ($self, $mod) = @_; + my @parts = split /::/, $mod; + $parts[-1] .= '.pm'; + return $parts[0] if @parts == 1; + return File::Spec->catfile(@parts); +} + +1; + + diff --git a/cpan/Module-Build/t/PL_files.t b/cpan/Module-Build/t/PL_files.t index a22171458c..68614c80e4 100644 --- a/cpan/Module-Build/t/PL_files.t +++ b/cpan/Module-Build/t/PL_files.t @@ -4,7 +4,7 @@ use strict; use lib 't/lib'; use MBTest tests => 8; use DistGen; -use Module::Build; +blib_load('Module::Build'); my $dist; diff --git a/cpan/Module-Build/t/README.pod b/cpan/Module-Build/t/README.pod new file mode 100644 index 0000000000..b2d0579d3e --- /dev/null +++ b/cpan/Module-Build/t/README.pod @@ -0,0 +1,94 @@ +=head1 A GUIDE TO WRITING TESTS FOR MODULE::BUILD + +This document provides tips on writing new tests for Module::Build. Please +note that many existing tests were written prior to these guidelines and +have many different styles. Please don't copy/paste old tests by rote without +considering better ways to test. See C<sample.t> for a starter test file. + +=head1 TEST FILE PREAMBLE + +Every Module::Build test should begin with the same preamble to ensure that the +test library is set properly and that the correct version of Module::Build is +being tested. + + use strict; + use lib 't/lib'; + use MBTest tests => 2; # or 'no_plan' + + blib_load('Module::Build'); + +The C<MBTest> module is in C<t/lib/> and subclasses Test::More. When loaded +it cleans up several environment variables that could cause problems, +tweaks C<@INC> and exports several helper functions. See that module for +details. + +=head1 CREATING A TEST DISTRIBUTION + +The C<DistGen> module in C<t/lib/> should be used to create sample +distributions for testing. It provides numerous helpful methods to +create a skeleton distribution, add files, change files, and so on. +Run C<perldoc> on C<t/lib/DistGen.pm> to see the documentation. + + # CREATE A TEST DISTRIBUTION + + use DistGen; + + # create dist object in a temp directory + my $dist = DistGen->new; + + # enter the test distribution directory before further testing + $dist->chdir_in; + + # generate the skeleton files + $dist->regen; + + +=head1 GETTING A MODULE::BUILD OBJECT + +From inside the test distribution, you can get the Module::Build object +configured in Build.PL using the C<new_from_context> method on the +dist object. This is just like Module::Build's C<new_from_context> except +it passes C<< quiet => 1 >> to avoid sending output to the terminal. +Use the Module::Build object to test the programmatic API. + + my $mb = $dist->new_from_context( quiet => 1 ); + isa_ok( $mb, "Module::Build" ); + is( $mb->dist_name, "Simple", "dist_name is 'Simple'" ); + +=head1 TESTING THE COMMAND LINE API + +The command line API is tested by running subprocesses, not via a Module::Build +object. The C<DistGen> object has helper methods for running C<Build.PL> and +C<Build> and passing arguments on the command line. + + $dist->run_build_pl( '--quiet' ); + $dist->run_build( 'test' ); + +=head1 TYPICAL TESTING CYCLE + +The typical testing cycle is to generate or modify a test distribution, either +through the C<DistGen> object or directly in the filesystem, then regenerate +the distribution and test it (or run command line tests and observe the +result.) + + # Modify the distribution + + $dist->change_build_pl( + { + module_name => $dist->name, + license => 'artistic', + } + ); + $dist->regen; + + # Get a new build object and test it + + $mb = $dist->new_from_context; + is( $mb->license, "artistic", "saw 'artistic' license" ); + + +=head1 COPYRIGHT + +This documentation is Copyright (C) 2009 by David Golden. You can redistribute +it and/or modify it under the same terms as Perl 5.10.0. + diff --git a/cpan/Module-Build/t/actions/installdeps.t b/cpan/Module-Build/t/actions/installdeps.t new file mode 100644 index 0000000000..95e221d0ad --- /dev/null +++ b/cpan/Module-Build/t/actions/installdeps.t @@ -0,0 +1,48 @@ +use strict; +use lib 't/lib'; +use MBTest; +use DistGen; + +plan tests => 7; + +# Ensure any Module::Build modules are loaded from correct directory +blib_load('Module::Build'); + +# create dist object in a temp directory +# enter the directory and generate the skeleton files +my $dist = DistGen->new->chdir_in; + +$dist->change_build_pl( + module_name => $dist->name, + requires => { + 'File::Spec' => 9999, + }, + build_requires => { + 'Getopt::Long' => 9998, + }, + cpan_client => $^X . ' -le print($_)for($^X,@ARGV)', +)->regen; + +# get a Module::Build object and test with it +my $mb; +stdout_stderr_of( sub { $mb = $dist->new_from_context('verbose' => 1) } ); +isa_ok( $mb, "Module::Build" ); +like( $mb->cpan_client, qr/^\Q$^X\E/, "cpan_client is mocked with perl" ); + +my $out = stdout_of( sub { + $dist->run_build('installdeps') +}); +ok( length($out), "ran mocked Build installdeps"); +my $expected = quotemeta(Module::Build->find_command($^X)); +like( $out, qr/$expected/i, "relative cpan_client resolved relative to \$^X" ); +like( $out, qr/File::Spec/, "saw File::Spec prereq" ); +like( $out, qr/Getopt::Long/, "saw Getopt::Long prereq" ); + +$out = stdout_stderr_of( sub { + $dist->run_build('installdeps', '--cpan_client', 'ADLKASJDFLASDJ') +}); +like( $out, qr/cpan_client .* is not executable/, + "Build installdeps with bad cpan_client dies" +); + +# vim:ts=2:sw=2:et:sta:sts=2 diff --git a/cpan/Module-Build/t/add_property.t b/cpan/Module-Build/t/add_property.t index 6032b0929d..e0b25ae00f 100644 --- a/cpan/Module-Build/t/add_property.t +++ b/cpan/Module-Build/t/add_property.t @@ -2,12 +2,11 @@ use strict; use lib 't/lib'; -use MBTest tests => 29; +use MBTest tests => 27; #use MBTest 'no_plan'; use DistGen; -BEGIN { use_ok 'Module::Build' or die; } -ensure_blib 'Module::Build'; +blib_load 'Module::Build'; my $tmp = MBTest->tmpdir; my $dist = DistGen->new( dir => $tmp ); diff --git a/cpan/Module-Build/t/basic.t b/cpan/Module-Build/t/basic.t index f46be0a4c9..74c50b6178 100644 --- a/cpan/Module-Build/t/basic.t +++ b/cpan/Module-Build/t/basic.t @@ -2,10 +2,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 60; +use MBTest tests => 58; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); my $tmp = MBTest->tmpdir; @@ -28,7 +27,7 @@ $dist->chdir_in; $mb = Module::Build->new( dist_name => $dist->name, dist_version => 7 ); ok $mb; - ok ! $mb->module_name; # Make sure it's defined + ok $mb->module_name; # Set via heuristics is $mb->dist_name, $dist->name; } @@ -163,10 +162,7 @@ $dist->chdir_in; is $args{foo}, 1; # revert test distribution to pristine state because we modified a file - $dist->remove; - $dist = DistGen->new( dir => $tmp ); - $dist->regen; - $dist->chdir_in; + $dist->regen( clean => 1 ); } # Test author stuff @@ -236,5 +232,3 @@ $dist->chdir_in; is_deeply $mb->include_dirs, ['/foo'], 'Should have single include dir'; } -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/bundle_inc.t b/cpan/Module-Build/t/bundle_inc.t new file mode 100644 index 0000000000..edb1aa94cd --- /dev/null +++ b/cpan/Module-Build/t/bundle_inc.t @@ -0,0 +1,194 @@ +# sample.t -- a sample test file for Module::Build + +use strict; +use lib 't/lib'; +use MBTest; # or 'no_plan' +use DistGen; +use Config; +use IO::File; +use File::Spec; +use ExtUtils::Packlist; +use File::Path; + +# Ensure any Module::Build modules are loaded from correct directory +blib_load('Module::Build'); +blib_load('Module::Build::ConfigData'); + +if ( Module::Build::ConfigData->feature('inc_bundling_support') ) { + plan tests => 18; +} else { + plan skip_all => 'inc_bundling_support feature is not enabled'; +} + +# need to do a temp install of M::B being tested to ensure a packlist +# is available for bundling + +my $current_mb = Module::Build->resume(); +my $temp_install = MBTest->tmpdir(); +my $arch = $Config{archname}; +my $lib_path = File::Spec->catdir($temp_install,qw/lib perl5/); +my $arch_path = File::Spec->catdir( $lib_path, $arch ); +mkpath ( $arch_path ); +ok( -d $arch_path, "created temporary M::B pseudo-install directory"); + +unshift @INC, $lib_path, $arch_path; +local $ENV{PERL5LIB} = join( $Config{path_sep}, + $lib_path, $arch_path, ($ENV{PERL5LIB} ? $ENV{PERL5LIB} : () ) +); + +stdout_of( sub { $current_mb->dispatch('install', install_base => $temp_install) } ); + +# create dist object in a temp directory +# enter the directory and generate the skeleton files +my $dist = DistGen->new( inc => 1 )->chdir_in->regen; + +# get a Module::Build object and test with it +my $mb = $dist->new_from_context(); # quiet by default +isa_ok( $mb, "Module::Build" ); +is( $mb->dist_name, "Simple", "dist_name is 'Simple'" ); +is_deeply( $mb->bundle_inc, [ 'Module::Build' ], + "Module::Build is flagged for bundling" +); + +# see what gets bundled +stdout_stderr_of( sub { $mb->dispatch('distdir') } ); + +my $dist_inc = File::Spec->catdir($mb->dist_dir, 'inc'); +ok( -e File::Spec->catfile( $dist_inc, 'latest.pm' ), + "./inc/latest.pm created" +); + +ok( -d File::Spec->catdir( $dist_inc, 'inc_Module-Build' ), + "dist_dir/inc/inc_Module_Build created" +); + +my $mb_file = + File::Spec->catfile( $dist_inc, qw/inc_Module-Build Module Build.pm/ ); + +ok( -e $mb_file, + "dist_dir/inc/inc_Module_Build/Module/Build.pm created" +); + +ok( -e File::Spec->catfile( $dist_inc, qw/inc_Module-Build Module Build Base.pm/ ), + "dist_dir/inc/inc_Module_Build/Module/Build/Base.pm created" +); + +# Force bundled M::B to a higher version so it gets loaded + +my $fh = IO::File->new($mb_file, "+<") or die "Could not open $mb_file: $!"; +my $mb_code = do { local $/; <$fh> }; +$mb_code =~ s{\$VERSION\s+=\s+\S+}{\$VERSION = 9999;}; +$fh->seek(0,0); +print {$fh} $mb_code; +$fh->close; + +# test the bundling in dist_dir +chdir $mb->dist_dir; + +stdout_of( sub { Module::Build->run_perl_script('Build.PL',[],[]) } ); + +my $meta = IO::File->new('MYMETA.yml'); +ok( $meta, "found MYMETA.yml" ); +ok( scalar( grep { /generated_by:.*9999/ } <$meta> ), + "dist_dir Build.PL loaded bundled Module::Build" +); + +#--------------------------------------------------------------------------# +# test identification of dependencies +#--------------------------------------------------------------------------# + +$dist->chdir_in; + +$dist->add_file( 'mylib/Foo.pm', << 'HERE' ); +package Foo; +our $VERSION = 1; +1; +HERE + +$dist->add_file( 'mylib/Bar.pm', << 'HERE' ); +package Bar; +use Foo; +our $VERSION = 42; +1; +HERE + +$dist->change_file( 'Build.PL', << "HERE" ); +use inc::latest 'Module::Build'; +use inc::latest 'Foo'; + +Module::Build->new( + module_name => '$dist->{name}', + license => 'perl', +)->create_build_script; +HERE + +$dist->regen( clean => 1 ); + +make_packlist($_,'mylib') for qw/Foo Bar/; + +# get a Module::Build object and test with it +my $abs_mylib = File::Spec->rel2abs('mylib'); + + +unshift @INC, $abs_mylib; +$mb = $dist->new_from_context(); # quiet by default +isa_ok( $mb, "Module::Build" ); +is_deeply( [sort @{$mb->bundle_inc}], [ 'Foo', 'Module::Build' ], + "Module::Build and Foo are flagged for bundling" +); + +my $output = stdout_stderr_of( sub { $mb->dispatch('distdir') } ); + +ok( -e File::Spec->catfile( $dist_inc, 'latest.pm' ), + "./inc/latest.pm created" +); + +ok( -d File::Spec->catdir( $dist_inc, 'inc_Foo' ), + "dist_dir/inc/inc_Foo created" +); + +$dist->change_file( 'Build.PL', << "HERE" ); +use inc::latest 'Module::Build'; +use inc::latest 'Bar'; + +Module::Build->new( + module_name => '$dist->{name}', + license => 'perl', +)->create_build_script; +HERE + +$dist->regen( clean => 1 ); +make_packlist($_,'mylib') for qw/Foo Bar/; + +$mb = $dist->new_from_context(); # quiet by default +isa_ok( $mb, "Module::Build" ); +is_deeply( [sort @{$mb->bundle_inc}], [ 'Bar', 'Module::Build' ], + "Module::Build and Bar are flagged for bundling" +); + +$output = stdout_stderr_of( sub { $mb->dispatch('distdir') } ); + +ok( -e File::Spec->catfile( $dist_inc, 'latest.pm' ), + "./inc/latest.pm created" +); + +ok( -d File::Spec->catdir( $dist_inc, 'inc_Bar' ), + "dist_dir/inc/inc_Bar created" +); + + + +sub make_packlist { + my ($mod, $lib) = @_; + my $arch = $Config{archname}; + (my $mod_path = $mod) =~ s{::}{/}g; + my $mod_file = File::Spec->catfile( $lib, "$mod_path\.pm" ); + my $abs = File::Spec->rel2abs($mod_file); + my $packlist_path = File::Spec->catdir($lib, $arch, 'auto', $mod_path); + mkpath $packlist_path; + my $packlist = ExtUtils::Packlist->new; + $packlist->{$abs}++; + $packlist->write( File::Spec->catfile( $packlist_path, '.packlist' )); +} + +# vim:ts=2:sw=2:et:sta:sts=2 diff --git a/cpan/Module-Build/t/compat.t b/cpan/Module-Build/t/compat.t index 88e5953408..f84b79b744 100644 --- a/cpan/Module-Build/t/compat.t +++ b/cpan/Module-Build/t/compat.t @@ -25,8 +25,8 @@ if ( $Config{make} && $^O ne 'VMS' ? find_in_path($Config{make}) : 1 ) { my $is_vms_mms = ($^O eq 'VMS') && ($Config{make} =~ /MM[SK]/i); -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); +blib_load('Module::Build::Version'); ######################### @@ -43,8 +43,8 @@ $dist->chdir_in; ######################### -use Module::Build; -use Module::Build::Compat; +blib_load('Module::Build'); +blib_load('Module::Build::Compat'); use Carp; $SIG{__WARN__} = \&Carp::cluck; @@ -72,10 +72,11 @@ $dist->change_build_pl({ license => 'perl', requires => { 'perl' => $], - 'File::Spec' => 0, + 'File::Spec' => 0.2, }, - build_requires => { - 'Test::More' => 0, + build_requires => { + 'Test::More' => 0, + 'File::Spec' => 0, }, PL_files => { 'foo.PL' => 'foo' }, }); @@ -90,8 +91,11 @@ $dist->regen; test_makefile_types( requires => { 'perl' => $], - 'File::Spec' => 0, + 'File::Spec' => 0.2, + }, + build_requires => { 'Test::More' => 0, + 'File::Spec' => 0, }, PL_files => { 'foo.PL' => 'foo', @@ -108,7 +112,7 @@ $dist->regen; # Create M::B instance but don't pollute STDOUT my $mb; -stdout_of( sub { +stdout_stderr_of( sub { $mb = Module::Build->new_from_context; }); ok $mb, "Module::Build->new_from_context"; @@ -131,7 +135,7 @@ ok $mb, "Module::Build->new_from_context"; # Makefile.PL - make sure it fails in the right way here. local @Foo::Builder::ISA = qw(Module::Build); my $foo_builder; - stdout_of( sub { + stdout_stderr_of( sub { $foo_builder = Foo::Builder->new_from_context; }); foreach my $style ('passthrough', 'small') { @@ -148,13 +152,13 @@ ok $mb, "Module::Build->new_from_context"; # Now make sure it can actually work. my $bar_builder; - stdout_of( sub { + stdout_stderr_of( sub { $bar_builder = Module::Build->subclass( class => 'Bar::Builder' )->new_from_context; }); foreach my $style ('passthrough', 'small') { create_makefile_pl($style, $bar_builder); my $result; - stdout_of( sub { + stdout_stderr_of( sub { $result = $mb->run_perl_script('Makefile.PL'); }); ok $result, "Makefile.PL ran without error"; @@ -167,7 +171,7 @@ ok $mb, "Module::Build->new_from_context"; my $libdir = File::Spec->catdir( $tmp, 'libdir' ); my $result; - stdout_of( sub { + stdout_stderr_of( sub { $result = $mb->run_perl_script('Makefile.PL', [], [ "LIB=$libdir", @@ -188,7 +192,7 @@ ok $mb, "Module::Build->new_from_context"; # Make sure those switches actually had an effect my ($ran_ok, $output); - $output = stdout_of( sub { $ran_ok = $new_build->do_system(@make, 'test') } ); + $output = stdout_stderr_of( sub { $ran_ok = $new_build->do_system(@make, 'test') } ); ok $ran_ok, "make test ran without error"; $output =~ s/^/# /gm; # Don't confuse our own test output like $output, qr/(?:# ok \d+\s+)+/, 'Should be verbose'; @@ -201,7 +205,7 @@ ok $mb, "Module::Build->new_from_context"; $make_macro = '/macro=("' . $make_macro . '")'; } - $output = stdout_of( sub { + $output = stdout_stderr_of( sub { local $ENV{HARNESS_TIMER}; # RT#39635 - timer messes with output $ran_ok = $mb->do_system(@make, 'test', $make_macro) } ); @@ -258,7 +262,7 @@ ok $mb, "Module::Build->new_from_context"; } } - stdout_of( sub { $mb->do_system(@make, 'realclean'); } ); + stdout_stderr_of( sub { $mb->do_system(@make, 'realclean'); } ); ok ! -e $makefile, "$makefile shouldn't exist"; 1 while unlink 'Makefile.PL'; @@ -274,14 +278,14 @@ ok $mb, "Module::Build->new_from_context"; create_makefile_pl('passthrough', $mb); - stdout_of( sub { + stdout_stderr_of( sub { $mb->run_perl_script('Makefile.PL', [], ['INSTALL_BASE=~/foo']); }); my $b2 = Module::Build->current; ok $b2->install_base, "install_base set"; unlike $b2->install_base, qr/^~/, "Tildes should be expanded"; - stdout_of( sub { $mb->do_system(@make, 'realclean'); } ); + stdout_stderr_of( sub { $mb->do_system(@make, 'realclean'); } ); ok ! -e $makefile, "$makefile shouldn't exist"; 1 while unlink 'Makefile.PL'; @@ -293,34 +297,53 @@ ok $mb, "Module::Build->new_from_context"; $dist->regen; my $mb; - stdout_of( sub { + stdout_stderr_of( sub { $mb = Module::Build->new_from_context( recursive_test_files => 1 ); }); create_makefile_pl('traditional', $mb); my $args = extract_writemakefile_args() || {}; - is $args->{TESTS}, - join( q{ }, - File::Spec->catfile(qw(t *.t)), - File::Spec->catfile(qw(t deep *.t)) - ), - 'Makefile.PL has correct TESTS line for recursive test files'; -} -# cleanup -$dist->remove; + if ( exists $args->{test}->{TESTS} ) { + is $args->{test}->{TESTS}, + join( q{ }, + File::Spec->catfile(qw(t *.t)), + File::Spec->catfile(qw(t deep *.t)) + ), + 'Makefile.PL has correct TESTS line for recursive test files'; + } else { + ok( ! exists $args->{TESTS}, 'Not using incorrect recursive tests key' ); + } + +} ######################################################### +sub _merge_prereqs { + my ($first, $second) = @_; + my $new = { %$first }; + for my $k (keys %$second) { + if ( exists $new->{$k} ) { + my ($v1,$v2) = ($new->{$k},$second->{$k}); + $new->{$k} = ($v1 > $v2 ? $v1 : $v2); + } + else { + $new->{$k} = $second->{$k}; + } + } + return $new; +} + sub test_makefile_types { my %opts = @_; $opts{requires} ||= {}; + $opts{build_requires} ||= {}; $opts{PL_files} ||= {}; foreach my $type (@makefile_types) { # Create M::B instance my $mb; - stdout_of( sub { + stdout_stderr_of( sub { $mb = Module::Build->new_from_context; }); ok $mb, "Module::Build->new_from_context"; @@ -330,12 +353,12 @@ sub test_makefile_types { test_makefile_pl_requires_perl( $opts{requires}{perl} ); test_makefile_creation($mb); - test_makefile_prereq_pm( $opts{requires} ); + test_makefile_prereq_pm( _merge_prereqs($opts{requires}, $opts{build_requires}) ); test_makefile_pl_files( $opts{PL_files} ) if $type eq 'traditional'; my ($output,$success); # Capture output to keep our STDOUT clean - $output = stdout_of( sub { + $output = stdout_stderr_of( sub { $success = $mb->do_system(@make); }); ok $success, "make ran without error"; @@ -345,13 +368,13 @@ sub test_makefile_types { } # Can't let 'test' STDOUT go to our STDOUT, or it'll confuse Test::Harness. - $output = stdout_of( sub { + $output = stdout_stderr_of( sub { $success = $mb->do_system(@make, 'test'); }); ok $success, "make test ran without error"; like uc $output, qr{DONE\.|SUCCESS}, "make test output indicated success"; - $output = stdout_of( sub { + $output = stdout_stderr_of( sub { $success = $mb->do_system(@make, 'realclean'); }); ok $success, "make realclean ran without error"; @@ -372,7 +395,7 @@ sub test_makefile_creation { my ($output, $result); # capture output to avoid polluting our test output - $output = stdout_of( sub { + $output = stdout_stderr_of( sub { $result = $build->run_perl_script('Makefile.PL', $preargs, $postargs); }); my $label = "Makefile.PL ran without error"; @@ -472,7 +495,8 @@ sub extract_writemakefile_args { } sub create_makefile_pl { - Module::Build::Compat->create_makefile_pl(@_); + my @args = @_; + stdout_stderr_of( sub { Module::Build::Compat->create_makefile_pl(@args) } ); my $ok = ok -e 'Makefile.PL', "$_[0] Makefile.PL created"; # Some really conservative make's, like HP/UX, assume files with the same diff --git a/cpan/Module-Build/t/compat/exit.t b/cpan/Module-Build/t/compat/exit.t index 78269a97a3..3672c938c3 100644..100755 --- a/cpan/Module-Build/t/compat/exit.t +++ b/cpan/Module-Build/t/compat/exit.t @@ -3,10 +3,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 5; +use MBTest tests => 3; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); ######################### @@ -24,11 +23,13 @@ $dist->chdir_in; my $mb; stdout_of(sub{ $mb = Module::Build->new_from_context}); -use Module::Build::Compat; +blib_load('Module::Build::Compat'); $dist->regen; -Module::Build::Compat->create_makefile_pl('passthrough', $mb); +stdout_stderr_of( + sub{ Module::Build::Compat->create_makefile_pl('passthrough', $mb); } +); # as silly as all of this exit(0) business is, that is what the cpan # testers have instructed everybody to do so... diff --git a/cpan/Module-Build/t/debug.t b/cpan/Module-Build/t/debug.t index c9b4fa581c..e0b8f60817 100644 --- a/cpan/Module-Build/t/debug.t +++ b/cpan/Module-Build/t/debug.t @@ -2,18 +2,15 @@ use strict; use lib 't/lib'; -use MBTest tests => 3; +use MBTest tests => 1; -require_ok('Module::Build'); -ensure_blib('Module::Build'); +blib_load('Module::Build'); my $tmp = MBTest->tmpdir; use DistGen; my $dist = DistGen->new( dir => $tmp ); $dist->regen; -END{ $dist->remove } - $dist->chdir_in; ######################### @@ -28,6 +25,3 @@ $dist->chdir_in; ); } -######################### - -# cleanup diff --git a/cpan/Module-Build/t/destinations.t b/cpan/Module-Build/t/destinations.t index 4af99d0031..07247a32ba 100644 --- a/cpan/Module-Build/t/destinations.t +++ b/cpan/Module-Build/t/destinations.t @@ -2,10 +2,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 115; +use MBTest tests => 113; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); my $tmp = MBTest->tmpdir; @@ -248,7 +247,8 @@ $mb->prefix(undef); } # Poke at the innards of MB to change the default install locations. - my $old = $mb->install_sets->{site} = \%test_config; + my $old = $mb->install_sets->{site}; + $mb->install_sets->{site} = \%test_config; $mb->config(siteprefixexp => catdir(File::Spec->rootdir, 'wierd', 'prefix')); @@ -321,5 +321,3 @@ sub test_install_destinations { } } - -$dist->remove; diff --git a/cpan/Module-Build/t/ext.t b/cpan/Module-Build/t/ext.t index 8045761c2a..6101bccd16 100644 --- a/cpan/Module-Build/t/ext.t +++ b/cpan/Module-Build/t/ext.t @@ -4,8 +4,6 @@ use strict; use lib 't/lib'; use MBTest; -use Module::Build; - my @unix_splits = ( { q{one t'wo th'ree f"o\"ur " "five" } => [ 'one', 'two three', 'fo"ur ', 'five' ] }, @@ -58,9 +56,11 @@ my @win_splits = { 'a " b " c' => [ 'a', ' b ', 'c' ] }, ); -plan tests => 10 + 4*@unix_splits + 4*@win_splits; +plan tests => 9 + 4*@unix_splits + 4*@win_splits; -ensure_blib('Module::Build'); +blib_load('Module::Build'); +blib_load('Module::Build::Platform::Unix'); +blib_load('Module::Build::Platform::Windows'); ######################### @@ -74,7 +74,6 @@ foreach my $platform ('', '::Platform::Unix', '::Platform::Windows') { # I think 3.24 isn't actually the majik version, my 3.23 seems to pass... my $low_TPW_version = Text::ParseWords->VERSION < 3.24; -use Module::Build::Platform::Unix; foreach my $test (@unix_splits) { # Text::ParseWords bug: local $TODO = $low_TPW_version && ((keys %$test)[0] =~ m{\\\n}); @@ -82,7 +81,6 @@ foreach my $test (@unix_splits) { do_split_tests('Module::Build::Platform::Unix', $test); } -use Module::Build::Platform::Windows; foreach my $test (@win_splits) { do_split_tests('Module::Build::Platform::Windows', $test); } diff --git a/cpan/Module-Build/t/extend.t b/cpan/Module-Build/t/extend.t index db99eec70b..36ff4b6946 100644 --- a/cpan/Module-Build/t/extend.t +++ b/cpan/Module-Build/t/extend.t @@ -2,10 +2,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 66; +use MBTest tests => 64; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); my $tmp = MBTest->tmpdir; @@ -79,7 +78,7 @@ print "Hello, World!\n"; $mb->add_build_element('foo'); $mb->add_build_element('foo'); - is_deeply $mb->build_elements, [qw(PL support pm xs pod script foo)], + is_deeply $mb->build_elements, [qw(PL support pm xs share_dir pod script foo)], 'The foo element should be in build_elements only once'; $mb->dispatch('build'); @@ -187,21 +186,20 @@ print "Hello, World!\n"; meta_add => {foo => 'bar'}, conflicts => {'Foo::Barxx' => 0}, ); - my %data; - $mb->prepare_metadata( \%data ); - is $data{foo}, 'bar'; + my $data = $mb->prepare_metadata; + is $data->{foo}, 'bar'; $mb->meta_merge(foo => 'baz'); - $mb->prepare_metadata( \%data ); - is $data{foo}, 'baz'; + $data = $mb->prepare_metadata; + is $data->{foo}, 'baz'; $mb->meta_merge(conflicts => {'Foo::Fooxx' => 0}); - $mb->prepare_metadata( \%data ); - is_deeply $data{conflicts}, {'Foo::Barxx' => 0, 'Foo::Fooxx' => 0}; + $data = $mb->prepare_metadata; + is_deeply $data->{conflicts}, {'Foo::Barxx' => 0, 'Foo::Fooxx' => 0}; $mb->meta_add(conflicts => {'Foo::Bazxx' => 0}); - $mb->prepare_metadata( \%data ); - is_deeply $data{conflicts}, {'Foo::Bazxx' => 0, 'Foo::Fooxx' => 0}; + $data = $mb->prepare_metadata; + is_deeply $data->{conflicts}, {'Foo::Bazxx' => 0, 'Foo::Fooxx' => 0}; } { @@ -275,5 +273,3 @@ print "Hello, World!\n"; } -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/files.t b/cpan/Module-Build/t/files.t index 87b192eaba..cf822fb091 100644 --- a/cpan/Module-Build/t/files.t +++ b/cpan/Module-Build/t/files.t @@ -2,10 +2,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 6; +use MBTest tests => 4; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); use IO::File; my $tmp = MBTest->tmpdir; @@ -46,5 +45,3 @@ my $mb = Module::Build->new_from_context; ok( Module::Build->dir_contains($first, $second) ); } -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/help.t b/cpan/Module-Build/t/help.t index 8408315f07..2bf34c8d50 100644 --- a/cpan/Module-Build/t/help.t +++ b/cpan/Module-Build/t/help.t @@ -2,38 +2,23 @@ use strict; use lib 't/lib'; -use MBTest tests => 25; +use MBTest tests => 23; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); - -use Cwd (); -use File::Path (); - -my $cwd = Cwd::cwd(); -my $tmp = MBTest->tmpdir; +blib_load('Module::Build'); use DistGen; -my $dist = DistGen->new(dir => $tmp); - - +my $dist = DistGen->new; $dist->regen; +$dist->chdir_in; my $restart = sub { - $dist->clean(); - DistGen::chdir_all( $cwd ); - File::Path::rmtree( $tmp ); # we're redefining the same package as we go, so... delete($::{'MyModuleBuilder::'}); delete($INC{'MyModuleBuilder.pm'}); - $dist->regen; - chdir($dist->dirname) or - die "Can't chdir to '@{[$dist->dirname]}': $!"; + $dist->regen( clean => 1 ); }; -chdir($dist->dirname) or die "Can't chdir to '@{[$dist->dirname]}': $!"; - ######################################################################## { # check the =item style my $mb = Module::Build->subclass( @@ -274,7 +259,5 @@ is($mb->get_action_docs('batz'), undef, 'nothing after uplevel'); # cleanup $dist->clean(); -DistGen::chdir_all($cwd); -File::Path::rmtree( $tmp ); # vim:ts=2:sw=2:et:sta diff --git a/cpan/Module-Build/t/install.t b/cpan/Module-Build/t/install.t index 2cadaa39da..66cdd5c94a 100644 --- a/cpan/Module-Build/t/install.t +++ b/cpan/Module-Build/t/install.t @@ -2,10 +2,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 36; +use MBTest tests => 34; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); use Config; use Cwd (); @@ -225,10 +224,7 @@ Simple Man <simple@example.com> is keys %$pms, 0; # revert to pristine state - $dist->remove; - $dist = DistGen->new( dir => $tmp ); - $dist->regen; - $dist->chdir_in; + $dist->regen( clean => 1 ); } sub strip_volume { @@ -243,6 +239,3 @@ sub file_exists { ok -e $file or diag("Expected $file to exist, but it doesn't"); } - -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/install_extra_target.t b/cpan/Module-Build/t/install_extra_target.t index c717ce5eee..21d0c272ae 100644 --- a/cpan/Module-Build/t/install_extra_target.t +++ b/cpan/Module-Build/t/install_extra_target.t @@ -3,10 +3,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 8; +use MBTest tests => 6; -require_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); use File::Spec::Functions qw( catdir ); @@ -46,11 +45,11 @@ sub process_etc_files } #Copy share files to blib -sub process_share_files +sub process_shared_files { my $self = shift; - $self->copy_files("share"); + $self->copy_files("shared"); } 1; @@ -62,23 +61,23 @@ my $build = $subclass->new( ); $build->add_build_element('etc'); -$build->add_build_element('share'); +$build->add_build_element('shared'); my $distdir = lc $build->dist_name(); foreach my $id ('core', 'site', 'vendor') { #Where to install these build types when using prefix symantics - $build->prefix_relpaths($id, 'share' => "share/$distdir"); + $build->prefix_relpaths($id, 'shared' => "shared/$distdir"); $build->prefix_relpaths($id, 'etc' => "etc/$distdir"); #Where to install these build types when using default symantics my $set = $build->install_sets($id); - $set->{'share'} = '/usr/'.($id eq 'site' ? 'local/':'')."share/$distdir"; + $set->{'shared'} = '/usr/'.($id eq 'site' ? 'local/':'')."shared/$distdir"; $set->{'etc'} = ($id eq 'site' ? '/usr/local/etc/':'/etc/').$distdir; } #Where to install these types when using install_base symantics -$build->install_base_relpaths('share' => "share/$distdir"); +$build->install_base_relpaths('shared' => "shared/$distdir"); $build->install_base_relpaths('etc' => "etc/$distdir"); $build->create_build_script(); @@ -97,12 +96,12 @@ stardate = 1234344 ===EOF=== -$dist->add_file("share/data", <<'===EOF==='); +$dist->add_file("shared/data", <<'===EOF==='); 7 * 9 = 42? ===EOF=== -$dist->add_file("share/html/index.html", <<'===EOF==='); +$dist->add_file("shared/html/index.html", <<'===EOF==='); <HTML> <BODY> <H1>Hello World!</H1> @@ -122,16 +121,15 @@ $output .= stdout_of sub { $dist->run_build }; my $error; $error++ unless ok(-e "blib/etc/config", "Built etc/config"); -$error++ unless ok(-e "blib/share/data", "Built share/data"); -$error++ unless ok(-e "blib/share/html/index.html", "Built share/html"); +$error++ unless ok(-e "blib/shared/data", "Built shared/data"); +$error++ unless ok(-e "blib/shared/html/index.html", "Built shared/html"); diag "OUTPUT:\n$output" if $error; $output = stdout_of sub { $dist->run_build('install') }; $error = 0; $error++ unless ok(-e "$installdest/etc/simple/config", "installed etc/config"); -$error++ unless ok(-e "$installdest/share/simple/data", "installed share/data"); -$error++ unless ok(-e "$installdest/share/simple/html/index.html", "installed share/html"); +$error++ unless ok(-e "$installdest/shared/simple/data", "installed shared/data"); +$error++ unless ok(-e "$installdest/shared/simple/html/index.html", "installed shared/html"); diag "OUTPUT:\n$output" if $error; -$dist->remove(); diff --git a/cpan/Module-Build/t/lib/DistGen.pm b/cpan/Module-Build/t/lib/DistGen.pm index 86ee794f3b..d1fb260d60 100644 --- a/cpan/Module-Build/t/lib/DistGen.pm +++ b/cpan/Module-Build/t/lib/DistGen.pm @@ -7,9 +7,9 @@ use vars qw( $VERSION $VERBOSE @EXPORT_OK); $VERSION = '0.01'; $VERBOSE = 0; - use Carp; +use MBTest (); use Cwd (); use File::Basename (); use File::Find (); @@ -38,7 +38,7 @@ BEGIN { $vms_efs_case = VMS::Feature::current("efs_case_preserve"); } else { my $env_unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || ''; - $unix_rpt = $env_unix_rpt =~ /^[ET1]/i; + $unix_rpt = $env_unix_rpt =~ /^[ET1]/i; my $efs_case = $ENV{'DECC$EFS_CASE_PRESERVE'} || ''; $vms_efs_case = $efs_case =~ /^[ET1]/i; } @@ -64,44 +64,76 @@ sub undent { } sub chdir_all ($) { - # OS/2 has "current directory per disk", undeletable; + # OS/2 has "current directory per disk", undeletable; # doing chdir() to another disk won't change cur-dir of initial disk... chdir('/') if $^O eq 'os2'; chdir shift; } + ######################################################################## +END { chdir_all(MBTest->original_cwd); } + sub new { - my $package = shift; + my $self = bless {}, shift; + $self->reset(@_); +} + +sub reset { + my $self = shift; my %options = @_; $options{name} ||= 'Simple'; - $options{dir} ||= Cwd::cwd(); + $options{dir} = File::Spec->rel2abs( + defined $options{dir} ? $options{dir} : MBTest->tmpdir + ); my %data = ( no_manifest => 0, xs => 0, + inc => 0, %options, ); - my $self = bless( \%data, $package ); - - # So we can clean up later even if the caller chdir()s - $self->{dir} = File::Spec->rel2abs($self->{dir}); + %$self = %data; tie %{$self->{filedata}}, 'Tie::CPHash'; tie %{$self->{pending}{change}}, 'Tie::CPHash'; + # start with a fresh, empty directory if ( -d $self->dirname ) { warn "Warning: Removing existing directory '@{[$self->dirname]}'\n"; - $self->remove; + File::Path::rmtree( $self->dirname ); } + File::Path::mkpath( $self->dirname ); $self->_gen_default_filedata(); return $self; } +sub remove { + my $self = shift; + $self->chdir_original if($self->did_chdir); + File::Path::rmtree( $self->dirname ); + return $self; +} + +sub revert { + my ($self, $file) = @_; + if ( defined $file ) { + delete $self->{filedata}{$file}; + delete $self->{pending}{$_}{$file} for qw/change remove/; + } + else { + delete $self->{filedata}{$_} for keys %{ $self->{filedata} }; + for my $pend ( qw/change remove/ ) { + delete $self->{pending}{$pend}{$_} for keys %{ $self->{pending}{$pend} }; + } + } + $self->_gen_default_filedata; +} + sub _gen_default_filedata { my $self = shift; @@ -112,17 +144,32 @@ sub _gen_default_filedata { $self->add_file($member, $data) unless($self->{filedata}{$member}); }; - $self->$add_unless('Build.PL', undent(<<" ---")); - use strict; - use Module::Build; + if ( ! $self->{inc} ) { + $self->$add_unless('Build.PL', undent(<<" ---")); + use strict; + use Module::Build; - my \$builder = Module::Build->new( - module_name => '$self->{name}', - license => 'perl', - ); + my \$builder = Module::Build->new( + module_name => '$self->{name}', + license => 'perl', + ); - \$builder->create_build_script(); - --- + \$builder->create_build_script(); + --- + } + else { + $self->$add_unless('Build.PL', undent(<<" ---")); + use strict; + use inc::latest 'Module::Build'; + + my \$builder = Module::Build->new( + module_name => '$self->{name}', + license => 'perl', + ); + + \$builder->create_build_script(); + --- + } my $module_filename = join( '/', ('lib', split(/::/, $self->{name})) ) . '.pm'; @@ -229,7 +276,7 @@ sub _gen_default_filedata { # 5.6 is missing const char * in its typemap $self->$add_unless('typemap', undent(<<" ---")); - const char * T_PV + const char *\tT_PV --- $self->$add_unless('t/basic.t', undent(<<" ---")); @@ -249,7 +296,6 @@ sub _gen_manifest { my $manifest = shift; my $fh = IO::File->new( ">$manifest" ) or do { - $self->remove(); die "Can't write '$manifest'\n"; }; @@ -312,7 +358,6 @@ sub regen { my $dirname = File::Basename::dirname( $fullname ); unless ( -d $dirname ) { File::Path::mkpath( $dirname ) or do { - $self->remove(); die "Can't create '$dirname'\n"; }; } @@ -322,7 +367,6 @@ sub regen { } my $fh = IO::File->new(">$fullname") or do { - $self->remove(); die "Can't write '$fullname'\n"; }; print $fh $self->{filedata}{$file}; @@ -339,6 +383,7 @@ sub regen { } $self->_gen_manifest( $manifest ); } + return $self; } sub clean { @@ -396,20 +441,7 @@ sub clean { }, ($^O eq 'VMS' ? './' : File::Spec->curdir) ); chdir_all( $here ); -} - -sub remove { - my $self = shift; - croak("invalid usage -- remove()") if(@_); - $self->chdir_original if($self->did_chdir); - File::Path::rmtree( $self->dirname ); - # might as well check - croak("\nthis test should have used chdir_in()") unless(Cwd::getcwd); -} - -sub revert { - my $self = shift; - die "Unimplemented.\n"; + return $self; } sub add_file { @@ -425,10 +457,13 @@ sub remove_file { } delete( $self->{filedata}{$file} ); $self->{pending}{remove}{$file} = 1; + return $self; } sub change_build_pl { - my ($self, $opts) = @_; + my ($self, @opts) = @_; + + my $opts = ref $opts[0] eq 'HASH' ? $opts[0] : { @opts }; local $Data::Dumper::Terse = 1; (my $args = Dumper($opts)) =~ s/^\s*\{|\}\s*$//g; @@ -437,16 +472,17 @@ sub change_build_pl { use strict; use Module::Build; my \$b = Module::Build->new( - # Some CPANPLUS::Dist::Build versions need to allow mismatches + # Some CPANPLUS::Dist::Build versions need to allow mismatches # On logic: thanks to Module::Install, CPAN.pm must set both keys, but # CPANPLUS sets only the one - allow_mb_mismatch => ( + allow_mb_mismatch => ( \$ENV{PERL5_CPANPLUS_IS_RUNNING} && ! \$ENV{PERL5_CPAN_IS_RUNNING} ? 1 : 0 ), $args ); \$b->create_build_script(); --- + return $self; } sub change_file { @@ -455,6 +491,7 @@ sub change_file { my $data = shift; $self->{filedata}{$file} = $data; $self->{pending}{change}{$file} = 1; + return $self; } sub get_file { @@ -466,40 +503,43 @@ sub get_file { sub chdir_in { my $self = shift; - - $self->{original_dir} ||= Cwd::cwd; # only once + $self->{original_dir} ||= Cwd::cwd; # only once! my $dir = $self->dirname; chdir($dir) or die "Can't chdir to '$dir': $!"; + return $self; } ######################################################################## -sub did_chdir { - my $self = shift; +sub did_chdir { exists shift()->{original_dir} } - return exists($self->{original_dir}); -} ######################################################################## sub chdir_original { my $self = shift; - croak("never called chdir_in()") unless($self->{original_dir}); - my $dir = $self->{original_dir}; + my $dir = delete $self->{original_dir}; chdir_all($dir) or die "Can't chdir to '$dir': $!"; + return $self; } ######################################################################## +sub new_from_context { + my ($self, @args) = @_; + require Module::Build; + return Module::Build->new_from_context( quiet => 1, @args ); +} + sub run_build_pl { my ($self, @args) = @_; require Module::Build; - Module::Build->run_perl_script('Build.PL', [], [@args]) + return Module::Build->run_perl_script('Build.PL', [], [@args]) } sub run_build { my ($self, @args) = @_; require Module::Build; my $build_script = $^O eq 'VMS' ? 'Build.com' : 'Build'; - Module::Build->run_perl_script($build_script, [], [@args]) + return Module::Build->run_perl_script($build_script, [], [@args]) } 1; @@ -516,8 +556,7 @@ DistGen - Creates simple distributions for testing. use DistGen; # create distribution and prepare to test - my $dist = DistGen->new(name => 'Foo::Bar', dir => $tmp); - $dist->regen; + my $dist = DistGen->new(name => 'Foo::Bar'); $dist->chdir_in; # change distribution files @@ -526,42 +565,48 @@ DistGen - Creates simple distributions for testing. $dist->remove_file('t/some_test.t'); $dist->regen; - # clean up extraneous files + # undo changes and clean up extraneous files + $dist->revert; $dist->clean; # exercise the command-line interface $dist->run_build_pl(); $dist->run_build('test'); - # finish testing and clean up - $dist->chdir_original; - $dist->remove; + # start over as a new distribution + $dist->reset( name => 'Foo::Bar', xs => 1 ); + $dist->chdir_in; =head1 USAGE A DistGen object manages a set of files in a distribution directory. -The constructor and some methods only define the target state of the -distribution. They do B<not> make any changes to the filesystem: +The C<new()> constructor initializes the object and creates an empty +directory for the distribution. It does not create files or chdir into +the directory. The C<reset()> method re-initializes the object in a +new directory with new parameters. It also does not create files or change +the current directory. + +Some methods only define the target state of the distribution. They do B<not> +make any changes to the filesystem: - new add_file change_file change_build_pl remove_file + revert Other methods then change the filesystem to match the target state of -the distribution (or to remove it entirely): +the distribution: - regen clean + regen remove Other methods are provided for a convenience during testing. The -most important are ones that manage the current directory: +most important is the one to enter the distribution directory: chdir_in - chdir_original Additional methods portably encapsulate running Build.PL and Build: @@ -570,16 +615,19 @@ Additional methods portably encapsulate running Build.PL and Build: =head1 API -=head2 Constructor +=head2 Constructors =head3 new() -Create a new object. Does not write its contents (see L</regen()>.) +Create a new object and an empty directory to hold the distribution's files. +If no C<dir> option is provided, it defaults to MBTest->tmpdir, which sets +a different temp directory for Perl core testing and CPAN testing. + +The C<new> method does not write any files -- see L</regen()> below. - my $tmp = MBTest->tmpdir; my $dist = DistGen->new( name => 'Foo::Bar', - dir => $tmp, + dir => MBTest->tmpdir, xs => 1, no_manifest => 0, ); @@ -596,9 +644,14 @@ dist name. =item dir -The (parent) directory in which to create the distribution directory. -The default is File::Spec->curdir. The distribution will be created -under this according to the "dist" form of C<name> (e.g. "Foo-Bar".) +The (parent) directory in which to create the distribution directory. The +distribution will be created under this according to the "dist" form of C<name> +(e.g. "Foo-Bar".) Defaults to a temporary directory. + + $dist = DistGen->new( dir => '/tmp/MB-test' ); + $dist->regen; + + # distribution files have been created in /tmp/MB-test/Simple =item xs @@ -622,6 +675,13 @@ the following files are also added: typemap lib/Simple.xs # based on name parameter +=head3 reset() + +The C<reset> method re-initializes the object as if it were generated +from a fresh call to C<new>. It takes the same optional parameters as C<new>. + + $dist->reset( name => 'Foo::Bar', xs => 0 ); + =head2 Adding and editing files Note that C<$filename> should always be specified with unix-style paths, @@ -669,6 +729,14 @@ Removes C<$filename> from the distribution. $dist->remove_file( $filename ); +=head3 revert() + +Returns the object to its initial state, or given a $filename it returns that +file to its initial state if it is one of the built-in files. + + $dist->revert; + $dist->revert($filename); + =head2 Changing the distribution directory These methods immediately affect the filesystem. @@ -680,8 +748,10 @@ flagged for removal with remove_file(). $dist->regen(clean => 1); -If the optional C<clean> argument is given, it also removes any -extraneous files that do not belong to the distribution. +If the optional C<clean> argument is given, it also calls C<clean>. These +can also be chained like this, instead: + + $dist->clean->regen; =head3 clean() @@ -689,22 +759,19 @@ Removes any files that are not part of the distribution. $dist->clean; -=begin TODO - -=head3 revert() - -[Unimplemented] Returns the object to its initial state, or given a -$filename it returns that file to it's initial state if it is one of -the built-in files. +=head3 remove() - $dist->revert; - $dist->revert($filename); +Changes back to the original directory and removes the distribution +directory (but not the temporary directory set during C<new()>). -=end TODO + $dist = DistGen->new->chdir->regen; + # ... do some testing ... -=head3 remove() + $dist->remove->chdir_in->regen; + # ... do more testing ... -Removes the entire distribution directory. +This is like a more aggressive form of C<clean>. Generally, calling C<clean> +and C<regen> should be sufficient. =head2 Changing directories diff --git a/cpan/Module-Build/t/lib/MBTest.pm b/cpan/Module-Build/t/lib/MBTest.pm index dc2410b399..8a5acd257a 100644 --- a/cpan/Module-Build/t/lib/MBTest.pm +++ b/cpan/Module-Build/t/lib/MBTest.pm @@ -13,6 +13,7 @@ BEGIN { my @delete_env_keys = qw( DEVEL_COVER_OPTIONS MODULEBUILDRC + PERL_MB_OPT HARNESS_TIMER HARNESS_OPTIONS HARNESS_VERBOSE @@ -49,7 +50,15 @@ BEGIN { # In case the test wants to use our other bundled # modules, make sure they can be loaded. - push @INC, File::Spec->catdir('t', 'bundled'); + my $t_lib = File::Spec->catdir('t', 'bundled'); + push @INC, $t_lib; # Let user's installed version override + + if ($ENV{PERL_CORE}) { + # We change directories, so expand @INC and $^X to absolute paths + # Also add . + @INC = (map(File::Spec->rel2abs($_), @INC), "."); + $^X = File::Spec->rel2abs($^X); + } } use Exporter; @@ -74,7 +83,7 @@ my @extra_exports = qw( find_in_path check_compiler have_module - ensure_blib + blib_load ); push @EXPORT, @extra_exports; __PACKAGE__->export(scalar caller, @extra_exports); @@ -85,7 +94,9 @@ __PACKAGE__->export(scalar caller, @extra_exports); # always return to the current directory { - my $cwd = Cwd::cwd; + my $cwd = File::Spec->rel2abs(Cwd::cwd); + + sub original_cwd { return $cwd } END { # Go back to where you came from! @@ -103,13 +114,11 @@ __PACKAGE__->export(scalar caller, @extra_exports); } ######################################################################## -# Setup a temp directory -sub tmpdir { - my ($self, $usr_tmp) = @_; - return File::Temp::tempdir( 'MB-XXXXXXXX', - CLEANUP => 1, DIR => $ENV{PERL_CORE} ? Cwd::cwd : - $usr_tmp ? $usr_tmp : File::Spec->tmpdir - ); +# Setup a temp directory +sub tmpdir { + my ($self, @args) = @_; + my $dir = $ENV{PERL_CORE} ? MBTest->original_cwd : File::Spec->tmpdir; + return File::Temp::tempdir('MB-XXXXXXXX', CLEANUP => 1, DIR => $dir, @args); } sub save_handle { @@ -137,7 +146,7 @@ sub stdout_stderr_of { $stdout = stdout_of ( sub { $stderr = stderr_of( $subr ) }); - return ($stdout, $stderr); + return wantarray ? ($stdout, $stderr) : $stdout . $stderr; } sub slurp { @@ -160,13 +169,20 @@ sub exe_exts { sub find_in_path { my $thing = shift; - - my @path = split $Config{path_sep}, $ENV{PATH}; + my @exe_ext = exe_exts(); - foreach (@path) { - my $fullpath = File::Spec->catfile($_, $thing); + if ( File::Spec->file_name_is_absolute( $thing ) ) { foreach my $ext ( '', @exe_ext ) { - return "$fullpath$ext" if -e "$fullpath$ext"; + return "$thing$ext" if -e "$thing$ext"; + } + } + else { + my @path = split $Config{path_sep}, $ENV{PATH}; + foreach (@path) { + my $fullpath = File::Spec->catfile($_, $thing); + foreach my $ext ( '', @exe_ext ) { + return "$fullpath$ext" if -e "$fullpath$ext"; + } } } return; @@ -178,6 +194,7 @@ sub check_compiler { local $SIG{__WARN__} = sub {}; + blib_load('Module::Build'); my $mb = Module::Build->current; $mb->verbose( 0 ); @@ -202,21 +219,23 @@ sub check_compiler { sub have_module { my $module = shift; - return eval "use $module; 1"; + return eval "require $module; 1"; } -sub ensure_blib { - # Make sure the given module was loaded from blib/, not the larger system +sub blib_load { + # Load the given module and ensure it came from blib/, not the larger system my $mod = shift; + have_module($mod) or die "Error loading $mod\: $@\n"; + (my $path = $mod) =~ s{::}{/}g; - - local $Test::Builder::Level = $Test::Builder::Level + 1; - SKIP: { - skip "no blib in core", 1 if $ENV{PERL_CORE}; - like $INC{"$path.pm"}, qr/\bblib\b/, "Make sure $mod was loaded from blib/" - or diag "PERL5LIB: " . ($ENV{PERL5LIB} || '') . "\n" . - "PERL5OPT: " . ($ENV{PERL5OPT} || '') . "\n" . - "\@INC contains:\n " . join("\n ", @INC) . "\n"; + $path .= ".pm"; + my ($pkg, $file, $line) = caller; + unless($ENV{PERL_CORE}) { + unless($INC{$path} =~ m/\bblib\b/) { + (my $load_from = $INC{$path}) =~ s{$path$}{}; + die "$mod loaded from '$load_from'\nIt should have been loaded from blib. \@INC contains:\n ", + join("\n ", @INC) . "\nFatal error occured in blib_load() at $file, line $line.\n"; + } } } diff --git a/cpan/Module-Build/t/manifypods.t b/cpan/Module-Build/t/manifypods.t index 31c9e8ea83..5947646d13 100644 --- a/cpan/Module-Build/t/manifypods.t +++ b/cpan/Module-Build/t/manifypods.t @@ -3,15 +3,14 @@ use strict; use lib 't/lib'; use MBTest; -use Module::Build; -use Module::Build::ConfigData; +blib_load('Module::Build'); +blib_load('Module::Build::ConfigData'); if ( Module::Build::ConfigData->feature('manpage_support') ) { - plan tests => 22; + plan tests => 21; } else { plan skip_all => 'manpage_support feature is not enabled'; } -ensure_blib('Module::Build'); ######################### @@ -139,11 +138,7 @@ $mb->dispatch('realclean'); # revert to a pristine state -$dist->remove; -$dist = DistGen->new( dir => $tmp ); -$dist->regen; -$dist->chdir_in; - +$dist->regen( clean => 1 ); my $mb2 = Module::Build->new( module_name => $dist->name, @@ -163,6 +158,3 @@ foreach ('testcover', 'disttest') { unlike $docs, qr/\n=/, $docs; } - -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/mbyaml.t b/cpan/Module-Build/t/mbyaml.t deleted file mode 100644 index d2cb0d547f..0000000000 --- a/cpan/Module-Build/t/mbyaml.t +++ /dev/null @@ -1,262 +0,0 @@ -#!/usr/local/bin/perl -w - -use strict; -use lib 't/lib'; -use MBTest 'no_plan'; - -use_ok 'Module::Build::YAML'; -ensure_blib('Module::Build::YAML'); - -my ($dir); -$dir = "."; -$dir = "t" if (-d "t"); - -{ - my ($expected, $got, $var); - ########################################################## - # Test a typical-looking Module::Build structure (alphabetized) - ########################################################## - $var = { - 'resources' => { - 'license' => 'http://opensource.org/licenses/artistic-license.php' - }, - 'meta-spec' => { - 'version' => '1.2', - 'url' => 'http://module-build.sourceforge.net/META-spec-v1.2.html' - }, - 'generated_by' => 'Module::Build version 0.2709', - 'version' => '0.13', - 'name' => 'js-app', - 'dynamic_config' => '1', - 'author' => [ - '"Stephen Adkins" <spadkins@gmail.com>' - ], - 'license' => 'lgpl', - 'build_requires' => { - 'App::Build' => '0', - 'File::Spec' => '0', - 'Module::Build' => '0' - }, - 'provides' => { - 'JavaScript::App' => { - 'version' => '0', - 'file' => 'lib/JavaScript/App.pm' - } - }, - 'requires' => { - 'App::Options' => '0' - }, - 'abstract' => 'A framework for building dynamic widgets or full applications in Javascript' - }; - $expected = <<'EOF'; ---- -abstract: A framework for building dynamic widgets or full applications in Javascript -author: - - '"Stephen Adkins" <spadkins@gmail.com>' -build_requires: - App::Build: 0 - File::Spec: 0 - Module::Build: 0 -dynamic_config: 1 -generated_by: Module::Build version 0.2709 -license: lgpl -meta-spec: - url: http://module-build.sourceforge.net/META-spec-v1.2.html - version: 1.2 -name: js-app -provides: - JavaScript::App: - file: lib/JavaScript/App.pm - version: 0 -requires: - App::Options: 0 -resources: - license: http://opensource.org/licenses/artistic-license.php -version: 0.13 -EOF - $got = &Module::Build::YAML::Dump($var); - is($got, $expected, "Dump(): single deep hash"); - - ########################################################## - # Test a typical-looking Module::Build structure (ordered) - ########################################################## - $expected = <<'EOF'; ---- -name: js-app -version: 0.13 -author: - - '"Stephen Adkins" <spadkins@gmail.com>' -abstract: A framework for building dynamic widgets or full applications in Javascript -license: lgpl -resources: - license: http://opensource.org/licenses/artistic-license.php -requires: - App::Options: 0 -build_requires: - App::Build: 0 - File::Spec: 0 - Module::Build: 0 -dynamic_config: 1 -provides: - JavaScript::App: - file: lib/JavaScript/App.pm - version: 0 -generated_by: Module::Build version 0.2709 -meta-spec: - url: http://module-build.sourceforge.net/META-spec-v1.2.html - version: 1.2 -EOF - $var->{_order} = [qw(name version author abstract license resources requires build_requires dynamic_config provides)]; - $got = &Module::Build::YAML::Dump($var); - is($got, $expected, "Dump(): single deep hash, ordered"); - - ########################################################## - # Test that an array turns into multiple documents - ########################################################## - $var = [ - "e", - 2.71828, - [ "pi", "is", 3.1416 ], - { fun => "under_sun", 6 => undef, "more", undef }, - ]; - $expected = <<'EOF'; ---- -e ---- -2.71828 ---- -- pi -- is -- 3.1416 ---- -6: ~ -fun: under_sun -more: ~ -EOF - $got = &Module::Build::YAML::Dump(@$var); - is($got, $expected, "Dump(): multiple, various"); - - ########################################################## - # Test that a single array ref turns into one document - ########################################################## - $expected = <<'EOF'; ---- -- e -- 2.71828 -- - - pi - - is - - 3.1416 -- - 6: ~ - fun: under_sun - more: ~ -EOF - $got = &Module::Build::YAML::Dump($var); - is($got, $expected, "Dump(): single array of various"); - - ########################################################## - # Test Object-Oriented Flavor of the API - ########################################################## - my $y = Module::Build::YAML->new(); - $got = $y->Dump($var); - is($got, $expected, "Dump(): single array of various (OO)"); - - ########################################################## - # Test Quoting Conditions (newlines, quotes, tildas, undefs) - ########################################################## - $var = { - 'foo01' => '`~!@#$%^&*()_+-={}|[]\\;\':",./?<> -<nl>', - 'foo02' => '~!@#$%^&*()_+-={}|[]\\;:,./<>?', - 'foo03' => undef, - 'foo04' => '~', - }; - $expected = <<'EOF'; ---- -foo01: "`~!@#$%^&*()_+-={}|[]\;':\",./?<>\n<nl>" -foo02: "~!@#$%^&*()_+-={}|[]\;:,./<>?" -foo03: ~ -foo04: "~" -EOF - $got = &Module::Build::YAML::Dump($var); - is($got, $expected, "Dump(): tricky embedded characters"); - - $var = { - 'foo10' => undef, - 'foo40' => '!', - 'foo41' => '@', - 'foo42' => '#', - 'foo43' => '$', - 'foo44' => '%', - 'foo45' => '^', - 'foo47' => '&', - 'foo48' => '*', - 'foo49' => '(', - 'foo50' => ')', - 'foo51' => '_', - 'foo52' => '+', - 'foo53' => '-', - 'foo54' => '=', - 'foo55' => '{', - 'foo56' => '}', - 'foo57' => '|', - 'foo58' => '[', - 'foo59' => ']', - 'foo60' => '\\', - 'foo61' => ';', - 'foo62' => ':', - 'foo63' => ',', - 'foo64' => '.', - 'foo65' => '/', - 'foo66' => '<', - 'foo67' => '>', - 'foo68' => '?', - 'foo69' => '\'', - 'foo70' => '"', - 'foo71' => '`', - 'foo72' => ' -', - }; - $expected = <<'EOF'; ---- -foo10: ~ -foo40: "!" -foo41: '@' -foo42: "#" -foo43: $ -foo44: % -foo45: "^" -foo47: "&" -foo48: "*" -foo49: "(" -foo50: ")" -foo51: _ -foo52: + -foo53: - -foo54: = -foo55: "{" -foo56: "}" -foo57: "|" -foo58: "[" -foo59: "]" -foo60: \ -foo61: ; -foo62: : -foo63: , -foo64: . -foo65: / -foo66: '<' -foo67: '>' -foo68: "?" -foo69: "'" -foo70: '"' -foo71: "`" -foo72: "\n" -EOF - $got = &Module::Build::YAML::Dump($var); - is($got, $expected, "Dump(): tricky embedded characters (singles)"); - -} - - diff --git a/cpan/Module-Build/t/metadata.t b/cpan/Module-Build/t/metadata.t index 6f53c1d225..2850bea24c 100644 --- a/cpan/Module-Build/t/metadata.t +++ b/cpan/Module-Build/t/metadata.t @@ -2,15 +2,13 @@ use strict; use lib 't/lib'; -use MBTest tests => 53; +use MBTest tests => 51; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); +blib_load('Module::Build::ConfigData'); my $tmp = MBTest->tmpdir; -use Module::Build::ConfigData; - my %metadata = ( module_name => 'Simple', @@ -56,7 +54,6 @@ my $simple2_file = 'lib/Simple2.pm'; $dist->chdir_in; -use Module::Build; my $mb = Module::Build->new_from_context; ################################################## @@ -68,7 +65,7 @@ my $mb = Module::Build->new_from_context; my $mb_config_req = { 'Module::Build' => int($Module::Build::VERSION * 100)/100 }; - my $node = $mb->prepare_metadata( {} ); + my $node = $mb->prepare_metadata( ); # exists() doesn't seem to work here is $node->{name}, $metadata{module_name}; @@ -89,7 +86,7 @@ my $mb = Module::Build->new_from_context; { my $mb_prereq = { 'Module::Build' => 0 }; $mb->configure_requires( $mb_prereq ); - my $node = $mb->prepare_metadata( {} ); + my $node = $mb->prepare_metadata( ); # exists() doesn't seem to work here @@ -366,7 +363,7 @@ package Simple; $VERSION = '2.34'; --- $dist->regen( clean => 1 ); -$mb = new_build(); +stderr_of( sub { $mb = new_build(); } ); $err = stderr_of( sub { $provides = $mb->find_dist_packages } ); is_deeply($provides, {'Simple' => { file => $simple_file, @@ -470,7 +467,7 @@ package Foo; $VERSION = '2.34'; --- $dist->regen( clean => 1 ); -$mb = new_build(); +stderr_of( sub { $mb = new_build(); } ); $err = stderr_of( sub { $provides = $mb->find_dist_packages } ); # XXX Should 'Foo' exist ??? Can't predict values for file & version ok( exists( $provides->{Foo} ) ); @@ -604,6 +601,3 @@ $dist->regen( clean => 1 ); $mb = new_build(); is_deeply($mb->find_dist_packages, {}); -############################################################ -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/metadata2.t b/cpan/Module-Build/t/metadata2.t index a5af034dc0..954b6589a0 100644 --- a/cpan/Module-Build/t/metadata2.t +++ b/cpan/Module-Build/t/metadata2.t @@ -2,14 +2,11 @@ use strict; use lib 't/lib'; -use MBTest tests => 20; +use MBTest tests => 18; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); +blib_load('Module::Build::ConfigData'); -my $tmp = MBTest->tmpdir; - -use Module::Build::ConfigData; use DistGen; @@ -19,14 +16,12 @@ SKIP: { skip( 'YAML_support feature is not enabled', 4 ) unless Module::Build::ConfigData->feature('YAML_support'); - my $dist = DistGen->new( dir => $tmp, no_manifest => 1 ); - $dist->regen; - - $dist->chdir_in; + my $dist = DistGen->new( no_manifest => 1 )->chdir_in->regen; ok ! -e 'MANIFEST'; - my $mb = Module::Build->new_from_context; + my $mb; + stderr_of( sub { $mb = Module::Build->new_from_context } ); my $out; $out = eval { stderr_of(sub{$mb->dispatch('distmeta')}) }; @@ -36,7 +31,6 @@ SKIP: { ok -e 'META.yml'; - $dist->remove; } @@ -62,7 +56,7 @@ Simple Simon <simon@simple.sim> =cut --- -my $dist = DistGen->new( dir => $tmp ); +my $dist = DistGen->new->chdir_in; $dist->change_build_pl ({ @@ -71,10 +65,6 @@ $dist->change_build_pl license => 'perl', create_readme => 1, }); -$dist->regen; - -$dist->chdir_in; - # .pm File with pod # @@ -139,7 +129,3 @@ is( $mb->dist_author->[0], 'Simple Simon <simon@simple.sim>', is( $mb->dist_abstract, "A simple module", "Extracting abstract from .pod over .pm"); - -############################################################ -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/moduleinfo.t b/cpan/Module-Build/t/moduleinfo.t index ca7eb048e5..e28726d493 100644 --- a/cpan/Module-Build/t/moduleinfo.t +++ b/cpan/Module-Build/t/moduleinfo.t @@ -4,99 +4,58 @@ use strict; use lib 't/lib'; -use MBTest tests => 82; - -use_ok 'Module::Build::ModuleInfo'; -ensure_blib('Module::Build::ModuleInfo'); - -my $tmp = MBTest->tmpdir; - -use DistGen; -my $dist = DistGen->new( dir => $tmp ); -$dist->regen; - -$dist->chdir_in; - -######################### - -# class method C<find_module_by_name> -my $module = Module::Build::ModuleInfo->find_module_by_name( - 'Module::Build::ModuleInfo' ); -ok( -e $module, 'find_module_by_name() succeeds' ); - - -# fail on invalid module name -my $pm_info = Module::Build::ModuleInfo->new_from_module( - 'Foo::Bar', inc => [] ); -ok( !defined( $pm_info ), 'fail if can\'t find module by module name' ); - - -# fail on invalid filename -my $file = File::Spec->catfile( 'Foo', 'Bar.pm' ); -$pm_info = Module::Build::ModuleInfo->new_from_file( $file, inc => [] ); -ok( !defined( $pm_info ), 'fail if can\'t find module by file name' ); - - -# construct from module filename -$file = File::Spec->catfile( 'lib', split( /::/, $dist->name ) ) . '.pm'; -$pm_info = Module::Build::ModuleInfo->new_from_file( $file ); -ok( defined( $pm_info ), 'new_from_file() succeeds' ); - -# construct from module name, using custom include path -$pm_info = Module::Build::ModuleInfo->new_from_module( - $dist->name, inc => [ 'lib', @INC ] ); -ok( defined( $pm_info ), 'new_from_module() succeeds' ); - +use MBTest; # parse various module $VERSION lines +# these will be reversed later to create %modules my @modules = ( - <<'---', # declared & defined on same line with 'our' + '1.23' => <<'---', # declared & defined on same line with 'our' package Simple; our $VERSION = '1.23'; --- - <<'---', # declared & defined on separate lines with 'our' + '1.23' => <<'---', # declared & defined on separate lines with 'our' package Simple; our $VERSION; $VERSION = '1.23'; --- - <<'---', # use vars + '1.23' => <<'---', # use vars package Simple; use vars qw( $VERSION ); $VERSION = '1.23'; --- - <<'---', # choose the right default package based on package/file name + '1.23' => <<'---', # choose the right default package based on package/file name package Simple::_private; $VERSION = '0'; package Simple; $VERSION = '1.23'; # this should be chosen for version --- - <<'---', # just read the first $VERSION line + '1.23' => <<'---', # just read the first $VERSION line package Simple; $VERSION = '1.23'; # we should see this line $VERSION = eval $VERSION; # and ignore this one --- - <<'---', # just read the first $VERSION line in reopened package (1) + '1.23' => <<'---', # just read the first $VERSION line in reopened package (1) package Simple; $VERSION = '1.23'; package Error::Simple; $VERSION = '2.34'; package Simple; --- - <<'---', # just read the first $VERSION line in reopened package (2) + '1.23' => <<'---', # just read the first $VERSION line in reopened package (2) package Simple; package Error::Simple; $VERSION = '2.34'; package Simple; $VERSION = '1.23'; --- - <<'---', # mentions another module's $VERSION + '1.23' => <<'---', # mentions another module's $VERSION package Simple; $VERSION = '1.23'; if ( $Other::VERSION ) { # whatever } --- - <<'---', # mentions another module's $VERSION in a different package + '1.23' => <<'---', # mentions another module's $VERSION in a different package package Simple; $VERSION = '1.23'; package Simple2; @@ -104,21 +63,21 @@ if ( $Simple::VERSION ) { # whatever } --- - <<'---', # $VERSION checked only in assignments, not regexp ops + '1.23' => <<'---', # $VERSION checked only in assignments, not regexp ops package Simple; $VERSION = '1.23'; if ( $VERSION =~ /1\.23/ ) { # whatever } --- - <<'---', # $VERSION checked only in assignments, not relational ops + '1.23' => <<'---', # $VERSION checked only in assignments, not relational ops package Simple; $VERSION = '1.23'; if ( $VERSION == 3.45 ) { # whatever } --- - <<'---', # $VERSION checked only in assignments, not relational ops + '1.23' => <<'---', # $VERSION checked only in assignments, not relational ops package Simple; $VERSION = '1.23'; package Simple2; @@ -126,36 +85,36 @@ if ( $Simple::VERSION == 3.45 ) { # whatever } --- - <<'---', # Fully qualified $VERSION declared in package + '1.23' => <<'---', # Fully qualified $VERSION declared in package package Simple; $Simple::VERSION = 1.23; --- - <<'---', # Differentiate fully qualified $VERSION in a package + '1.23' => <<'---', # Differentiate fully qualified $VERSION in a package package Simple; $Simple2::VERSION = '999'; $Simple::VERSION = 1.23; --- - <<'---', # Differentiate fully qualified $VERSION and unqualified + '1.23' => <<'---', # Differentiate fully qualified $VERSION and unqualified package Simple; $Simple2::VERSION = '999'; $VERSION = 1.23; --- - <<'---', # $VERSION declared as package variable from within 'main' package + '1.23' => <<'---', # $VERSION declared as package variable from within 'main' package $Simple::VERSION = '1.23'; { package Simple; $x = $y, $cats = $dogs; } --- - <<'---', # $VERSION wrapped in parens - space inside + '1.23' => <<'---', # $VERSION wrapped in parens - space inside package Simple; ( $VERSION ) = '1.23'; --- - <<'---', # $VERSION wrapped in parens - no space inside + '1.23' => <<'---', # $VERSION wrapped in parens - no space inside package Simple; ($VERSION) = '1.23'; --- - <<'---', # $VERSION follows a spurious 'package' in a quoted construct + '1.23' => <<'---', # $VERSION follows a spurious 'package' in a quoted construct package Simple; __PACKAGE__->mk_accessors(qw( program socket proc @@ -163,25 +122,87 @@ __PACKAGE__->mk_accessors(qw( our $VERSION = "1.23"; --- - <<'---', # $VERSION using version.pm + '1.23' => <<'---', # $VERSION using version.pm package Simple; use version; our $VERSION = version->new('1.23'); --- - <<'---', # $VERSION using version.pm and qv() + '1.23' => <<'---', # $VERSION using version.pm and qv() package Simple; use version; our $VERSION = qv('1.230'); --- - <<'---', # Two version assignments, should ignore second one + '1.23' => <<'---', # Two version assignments, should ignore second one $Simple::VERSION = '1.230'; $Simple::VERSION = eval $Simple::VERSION; --- + '1.23' => <<'---', # declared & defined on same line with 'our' +package Simple; +our $VERSION = '1.23_00_00'; +--- + '1.23' => <<'---', # package NAME VERSION + package Simple 1.23; +--- + '1.23_01' => <<'---', # package NAME VERSION + package Simple 1.23_01; +--- + 'v1.2.3' => <<'---', # package NAME VERSION + package Simple v1.2.3; +--- + 'v1.2_3' => <<'---', # package NAME VERSION + package Simple v1.2_3; +--- ); +my %modules = reverse @modules; + +plan tests => 36 + 2 * keys( %modules ); -my( $i, $n ) = ( 1, scalar( @modules ) ); -foreach my $module ( @modules ) { +blib_load('Module::Build::ModuleInfo'); + +my $tmp = MBTest->tmpdir; + +use DistGen; +my $dist = DistGen->new( dir => $tmp ); +$dist->regen; + +$dist->chdir_in; + +######################### + +# class method C<find_module_by_name> +my $module = Module::Build::ModuleInfo->find_module_by_name( + 'Module::Build::ModuleInfo' ); +ok( -e $module, 'find_module_by_name() succeeds' ); + + +# fail on invalid module name +my $pm_info = Module::Build::ModuleInfo->new_from_module( + 'Foo::Bar', inc => [] ); +ok( !defined( $pm_info ), 'fail if can\'t find module by module name' ); + + +# fail on invalid filename +my $file = File::Spec->catfile( 'Foo', 'Bar.pm' ); +$pm_info = Module::Build::ModuleInfo->new_from_file( $file, inc => [] ); +ok( !defined( $pm_info ), 'fail if can\'t find module by file name' ); + + +# construct from module filename +$file = File::Spec->catfile( 'lib', split( /::/, $dist->name ) ) . '.pm'; +$pm_info = Module::Build::ModuleInfo->new_from_file( $file ); +ok( defined( $pm_info ), 'new_from_file() succeeds' ); + +# construct from module name, using custom include path +$pm_info = Module::Build::ModuleInfo->new_from_module( + $dist->name, inc => [ 'lib', @INC ] ); +ok( defined( $pm_info ), 'new_from_module() succeeds' ); + + +foreach my $module ( sort keys %modules ) { + my $expected = $modules{$module}; SKIP: { skip( "No our() support until perl 5.6", 2 ) - if $] < 5.006 && $module =~ /\bour\b/; + if $] < 5.006 && $module =~ /\bour\b/; + skip( "No package NAME VERSION support until perl 5.11.1", 2 ) + if $] < 5.011001 && $module =~ /package\s+[\w\:\']+\s+v?[0-9._]+/; $dist->change_file( 'lib/Simple.pm', $module ); $dist->regen; @@ -191,19 +212,17 @@ foreach my $module ( @modules ) { my $pm_info = Module::Build::ModuleInfo->new_from_file( $file ); # Test::Builder will prematurely numify objects, so use this form - ok( $pm_info->version eq '1.23', - "correct module version ($i of $n)" ); - is( $warnings, '', 'no warnings from parsing' ); - $i++; + my $errs; + ok( $pm_info->version eq $expected, + "correct module version (expected '$expected')" ) + or $errs++; + is( $warnings, '', 'no warnings from parsing' ) or $errs++; + diag "Got: '@{[$pm_info->version]}'\nModule contents:\n$module" if $errs; } } # revert to pristine state -$dist->remove; -$dist = DistGen->new( dir => $tmp ); -$dist->regen; -$dist->chdir_in; - +$dist->regen( clean => 1 ); # Find each package only once $dist->change_file( 'lib/Simple.pm', <<'---' ); @@ -249,19 +268,15 @@ $pm_info = Module::Build::ModuleInfo->new_from_file( $file ); is( $pm_info->version, '1.23_01', 'alpha version reported'); # NOTE the following test has be done this way because Test::Builder is -# too smart for our own good and tries to see if the version object is a +# too smart for our own good and tries to see if the version object is a # dual-var, which breaks with alpha versions: # Argument "1.23_0100" isn't numeric in addition (+) at -# /usr/lib/perl5/5.8.7/Test/Builder.pm line 505. +# /usr/lib/perl5/5.8.7/Test/Builder.pm line 505. ok( $pm_info->version > 1.23, 'alpha version greater than non'); # revert to pristine state -$dist->remove; -$dist = DistGen->new( dir => $tmp ); -$dist->regen; -$dist->chdir_in; - +$dist->regen( clean => 1 ); # parse $VERSION lines scripts for package main my @scripts = ( @@ -313,7 +328,7 @@ $::VERSION = 0.01; --- ); -( $i, $n ) = ( 1, scalar( @scripts ) ); +my ( $i, $n ) = ( 1, scalar( @scripts ) ); foreach my $script ( @scripts ) { $dist->change_file( 'bin/simple.plx', $script ); $dist->regen; @@ -402,7 +417,7 @@ __DATA__ is( $pm_info->name, 'Simple', 'found default package' ); is( $pm_info->version, '0.01', 'version for default package' ); my @packages = $pm_info->packages_inside; - is_deeply(\@packages, ['Simple']); + is_deeply(\@packages, ['Simple'], 'packages inside'); } { @@ -419,10 +434,7 @@ $VERSION = version->new('0.61.' . (qw$Revision: 129 $)[1]); is( $pm_info->name, 'Simple', 'found default package' ); is( $pm_info->version, '0.60.128', 'version for default package' ); my @packages = $pm_info->packages_inside; - is_deeply([sort @packages], ['Simple', 'Simple::Simon']); + is_deeply([sort @packages], ['Simple', 'Simple::Simon'], 'packages inside'); is( $pm_info->version('Simple::Simon'), '0.61.129', 'version for embedded package' ); } - -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/mymeta.t b/cpan/Module-Build/t/mymeta.t new file mode 100644 index 0000000000..c60a5b2420 --- /dev/null +++ b/cpan/Module-Build/t/mymeta.t @@ -0,0 +1,30 @@ +#!/usr/bin/perl -w + +use strict; +use lib 't/lib'; +use MBTest tests => 3; + +blib_load('Module::Build'); + +my $tmp = MBTest->tmpdir; + +use DistGen; +my $dist = DistGen->new( dir => $tmp ); +$dist->regen; +$dist->chdir_in; + +######################### + +# Test MYMETA generation +{ + ok( ! -e "MYMETA.yml", "MYMETA.yml doesn't exist before Build.PL runs" ); + my $output; + $output = stdout_of sub { $dist->run_build_pl }; + like($output, qr/Creating new 'MYMETA.yml' with configuration results/, + "Saw MYMETA.yml creation message" + ); + ok( -e "MYMETA.yml", "MYMETA.yml exists" ); +} + +######################### + diff --git a/cpan/Module-Build/t/new_from_context.t b/cpan/Module-Build/t/new_from_context.t index ee34f07367..f45a1760eb 100644 --- a/cpan/Module-Build/t/new_from_context.t +++ b/cpan/Module-Build/t/new_from_context.t @@ -2,10 +2,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 4; +use MBTest tests => 2; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); use IO::File; my $tmp = MBTest->tmpdir; @@ -25,7 +24,4 @@ my $mb = eval { Module::Build->new_from_context}; ok(! $@, 'dodged the bullet') or die; ok($mb); -# cleanup -$dist->remove; - # vim:ts=2:sw=2:et:sta diff --git a/cpan/Module-Build/t/notes.t b/cpan/Module-Build/t/notes.t index 29f1fc38b1..4568e7c36a 100644 --- a/cpan/Module-Build/t/notes.t +++ b/cpan/Module-Build/t/notes.t @@ -2,10 +2,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 13; +use MBTest tests => 11; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); my $tmp = MBTest->tmpdir; @@ -65,6 +64,3 @@ $mb = Module::Build->resume; ok $mb; is $mb->notes('foo'), 'bar'; - -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/parents.t b/cpan/Module-Build/t/parents.t index 666fb05601..825f79a787 100644 --- a/cpan/Module-Build/t/parents.t +++ b/cpan/Module-Build/t/parents.t @@ -2,10 +2,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 28; +use MBTest tests => 26; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); ######################### diff --git a/cpan/Module-Build/t/perl_mb_opt.t b/cpan/Module-Build/t/perl_mb_opt.t new file mode 100644 index 0000000000..70089ee6be --- /dev/null +++ b/cpan/Module-Build/t/perl_mb_opt.t @@ -0,0 +1,62 @@ +# sample.t -- a sample test file for Module::Build + +use strict; +use lib 't/lib'; +use MBTest; +use DistGen; + +plan tests => 8; # or 'no_plan' + +# Ensure any Module::Build modules are loaded from correct directory +blib_load('Module::Build'); + +# create dist object in a temp directory +# enter the directory and generate the skeleton files +my $dist = DistGen->new->chdir_in->regen; + +$dist->add_file('t/subtest/foo.t', <<'END_T'); +use strict; +use Test::More tests => 1; +ok(1, "this is a recursive test"); +END_T + +$dist->regen; + +# get a Module::Build object and test with it +my $mb = $dist->new_from_context(); # quiet by default +isa_ok( $mb, "Module::Build" ); +is( $mb->dist_name, "Simple", "dist_name is 'Simple'" ); +ok( ! $mb->recursive_test_files, "set for no recursive testing" ); + +# set for recursive testing using PERL_MB_OPT +{ + local $ENV{PERL_MB_OPT} = "--verbose --recursive_test_files 1"; + + my $out = stdout_stderr_of( sub { + $dist->run_build('test'); + }); + like( $out, qr/this is a recursive test/, + "recursive tests run via PERL_MB_OPT" + ); +} + +# set Build.PL opts using PERL_MB_OPT +{ + local $ENV{PERL_MB_OPT} = "--verbose --recursive_test_files 1"; + my $mb = $dist->new_from_context(); # quiet by default + ok( $mb->recursive_test_files, "PERL_MB_OPT set recusive tests in Build.PL" ); + ok( $mb->verbose, "PERL_MB_OPT set verbose in Build.PL" ); +} + +# verify settings preserved during 'Build test' +{ + ok( !$ENV{PERL_MB_OPT}, "PERL_MB_OPT cleared" ); + my $out = stdout_stderr_of( sub { + $dist->run_build('test'); + }); + like( $out, qr/this is a recursive test/, + "recursive tests run via Build object" + ); +} + +# vim:ts=2:sw=2:et:sta:sts=2 diff --git a/cpan/Module-Build/t/pod_parser.t b/cpan/Module-Build/t/pod_parser.t index 42a78209e2..64d4c75348 100644 --- a/cpan/Module-Build/t/pod_parser.t +++ b/cpan/Module-Build/t/pod_parser.t @@ -2,10 +2,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 8; +use MBTest tests => 9; -use_ok 'Module::Build::PodParser'; -ensure_blib('Module::Build::PodParser'); +blib_load('Module::Build::PodParser'); ######################### @@ -66,3 +65,26 @@ EOF } +{ + # Try again with mixed-case =head1s. + untie *FH; + tie *FH, 'IO::StringBased', <<'EOF'; +=head1 Name + +Foo::Bar - Perl extension for blah blah blah + +=head1 Author + +C<Foo::Bar> was written by Engelbert Humperdinck I<E<lt>eh@example.comE<gt>> in 2004. + +Home page: http://example.com/~eh/ + +=cut +EOF + + my $pp = Module::Build::PodParser->new(fh => \*FH); + ok $pp, 'object created'; + + is $pp->get_author->[0], 'C<Foo::Bar> was written by Engelbert Humperdinck I<E<lt>eh@example.comE<gt>> in 2004.', 'author'; + is $pp->get_abstract, 'Perl extension for blah blah blah', 'abstract'; +} diff --git a/cpan/Module-Build/t/ppm.t b/cpan/Module-Build/t/ppm.t index 7fb6450648..4d69c9767a 100644 --- a/cpan/Module-Build/t/ppm.t +++ b/cpan/Module-Build/t/ppm.t @@ -3,11 +3,10 @@ use strict; use lib 't/lib'; use MBTest; - -use Module::Build; -use Module::Build::ConfigData; use Config; +blib_load('Module::Build'); +blib_load('Module::Build::ConfigData'); my $manpage_support = Module::Build::ConfigData->feature('manpage_support'); my $HTML_support = Module::Build::ConfigData->feature('HTML_support'); @@ -26,15 +25,13 @@ my $HTML_support = Module::Build::ConfigData->feature('HTML_support'); } elsif ( $^O eq 'VMS' ) { plan skip_all => "Needs porting work on VMS"; } else { - plan tests => 13; + plan tests => 12; } } -ensure_blib('Module::Build'); my $tmp = MBTest->tmpdir; - use DistGen; my $dist = DistGen->new( dir => $tmp, xs => 1 ); $dist->add_file( 'hello', <<'---' ); @@ -66,7 +63,6 @@ $dist->chdir_in; use File::Spec::Functions qw(catdir); -use Module::Build; my @installstyle = qw(lib perl5); my $mb = Module::Build->new_from_context( verbose => 0, @@ -98,13 +94,10 @@ my $varchname = Module::Build::PPMMaker->_varchname($mb->config); # do a strict string comparison, but absent an XML parser it's the # best we can do. is $ppd, <<"---"; -<SOFTPKG NAME="$dist_filename" VERSION="0,01,0,0"> - <TITLE>@{[$dist->name]}</TITLE> +<SOFTPKG NAME="$dist_filename" VERSION="0.01"> <ABSTRACT>Perl extension for blah blah blah</ABSTRACT> <AUTHOR>A. U. Thor, a.u.thor\@a.galaxy.far.far.away</AUTHOR> <IMPLEMENTATION> - <PERLCORE VERSION="$perl_version" /> - <OS NAME="$^O" /> <ARCHITECTURE NAME="$varchname" /> <CODEBASE HREF="/path/to/codebase-xs" /> </IMPLEMENTATION> @@ -185,9 +178,6 @@ SKIP: { } -$dist->remove; - - ######################################## sub exists_ok { diff --git a/cpan/Module-Build/t/properties/module_name.t b/cpan/Module-Build/t/properties/module_name.t new file mode 100644 index 0000000000..c266b41ba2 --- /dev/null +++ b/cpan/Module-Build/t/properties/module_name.t @@ -0,0 +1,53 @@ +# sample.t -- a sample test file for Module::Build + +use strict; +use lib 't/lib'; +use MBTest; +use DistGen; + +plan tests => 4; + +# Ensure any Module::Build modules are loaded from correct directory +blib_load('Module::Build'); + +# enter the directory and generate the skeleton files +my $dist = DistGen->new( name => "Not::So::Simple" )->chdir_in; + +#--------------------------------------------------------------------------# +# try getting module_name from dist directory name +#--------------------------------------------------------------------------# + +$dist->change_build_pl( + dist_name => 'Random-Name', + dist_version => 1, +)->regen; + +my $mb = $dist->new_from_context(); +isa_ok( $mb, "Module::Build" ); +is( $mb->module_name, "Not::So::Simple", + "module_name guessed from directory name" +); + +#--------------------------------------------------------------------------# +# Try getting module_name from dist_version_from +#--------------------------------------------------------------------------# + +$dist->add_file( 'lib/Simple/Name.pm', << 'END_PACKAGE' ); +package Simple::Name; +our $VERSION = 1.23; +1; +END_PACKAGE + +$dist->change_build_pl( + dist_name => 'Random-Name', + dist_version_from => 'lib/Simple/Name.pm', + dist_abstract => "Don't complain about missing abstract", +)->regen( clean => 1 ); + +$mb = $dist->new_from_context(); +isa_ok( $mb, "Module::Build" ); +is( $mb->module_name, "Simple::Name", + "module_name guessed from dist_version_from" +); + +# vim:ts=2:sw=2:et:sta:sts=2 diff --git a/cpan/Module-Build/t/properties/needs_compiler.t b/cpan/Module-Build/t/properties/needs_compiler.t new file mode 100644 index 0000000000..f298e82739 --- /dev/null +++ b/cpan/Module-Build/t/properties/needs_compiler.t @@ -0,0 +1,122 @@ +# sample.t -- a sample test file for Module::Build + +use strict; +use lib 't/lib'; +use MBTest; +use DistGen; + +plan tests => 19; + +# Ensure any Module::Build modules are loaded from correct directory +blib_load('Module::Build'); + +my $dist = DistGen->new->regen->chdir_in; + +# get a Module::Build object and test with it +my $mb; +stderr_of(sub { + ok( $mb = $dist->new_from_context, "Default Build.PL" ); +}); + +ok( ! $mb->needs_compiler, "needs_compiler is false" ); +ok( ! exists $mb->{properties}{build_requires}{'ExtUtils::CBuilder'}, + "ExtUtils::CBuilder is not in build_requires" +); + +#--------------------------------------------------------------------------# +# try with c_source +#--------------------------------------------------------------------------# +$dist->change_build_pl({ + module_name => $dist->name, + license => 'perl', + c_source => 'src', +}); +$dist->regen; +stderr_of(sub { + ok( $mb = $dist->new_from_context, + "Build.PL with c_source" + ); +}); +is( $mb->c_source, 'src', "c_source is set" ); +ok( $mb->needs_compiler, "needs_compiler is true" ); +ok( exists $mb->{properties}{build_requires}{'ExtUtils::CBuilder'}, + "ExtUtils::CBuilder was added to build_requires" +); + +#--------------------------------------------------------------------------# +# try with xs files +#--------------------------------------------------------------------------# +$dist = DistGen->new(dir => 'MBTest', xs => 1); +$dist->regen; +$dist->chdir_in; + +stderr_of(sub { + ok( $mb = $dist->new_from_context, + "Build.PL with xs files" + ); +}); +ok( $mb->needs_compiler, "needs_compiler is true" ); +ok( exists $mb->{properties}{build_requires}{'ExtUtils::CBuilder'}, + "ExtUtils::CBuilder was added to build_requires" +); + +#--------------------------------------------------------------------------# +# force needs_compiler off, despite xs modules +#--------------------------------------------------------------------------# + +$dist->change_build_pl({ + module_name => $dist->name, + license => 'perl', + needs_compiler => 0, +}); +$dist->regen; + +stderr_of(sub { + ok( $mb = $dist->new_from_context , + "Build.PL with xs files, but needs_compiler => 0" + ); +}); +is( $mb->needs_compiler, 0, "needs_compiler is false" ); +ok( ! exists $mb->{properties}{build_requires}{'ExtUtils::CBuilder'}, + "ExtUtils::CBuilder is not in build_requires" +); + +#--------------------------------------------------------------------------# +# don't override specific EU::CBuilder build_requires +#--------------------------------------------------------------------------# + +$dist->change_build_pl({ + module_name => $dist->name, + license => 'perl', + build_requires => { 'ExtUtils::CBuilder' => 0.2 }, +}); +$dist->regen; + +stderr_of(sub { + ok( $mb = $dist->new_from_context , + "Build.PL with xs files, build_requires EU::CB 0.2" + ); +}); +ok( $mb->needs_compiler, "needs_compiler is true" ); +is( $mb->build_requires->{'ExtUtils::CBuilder'}, 0.2, + "build_requires for ExtUtils::CBuilder is correct version" +); + +#--------------------------------------------------------------------------# +# falsify compiler and test error handling +#--------------------------------------------------------------------------# + +my $err = stderr_of( sub { + $mb = $dist->new_from_context( config => { cc => "adfasdfadjdjk" } ) +}); +ok( $mb, "Build.PL while hiding compiler" ); +like( $err, qr/no compiler detected/, + "hidden compiler resulted in warning message during Build.PL" +); +eval { $mb->dispatch('build') }; +like( $@, qr/no compiler detected/, + "hidden compiler resulted in fatal message during Build" +); + + +# vim:ts=2:sw=2:et:sta:sts=2 diff --git a/cpan/Module-Build/t/properties/share_dir.t b/cpan/Module-Build/t/properties/share_dir.t new file mode 100644 index 0000000000..f781a8a7ce --- /dev/null +++ b/cpan/Module-Build/t/properties/share_dir.t @@ -0,0 +1,228 @@ +#!/usr/bin/perl -w + +use strict; +use lib 't/lib'; +use MBTest; +use File::Spec::Functions qw/catdir catfile/; + +#--------------------------------------------------------------------------# +# Begin testing +#--------------------------------------------------------------------------# + +plan tests => 21; + +blib_load('Module::Build'); + +#--------------------------------------------------------------------------# +# Create test distribution +#--------------------------------------------------------------------------# + +my $tmp = MBTest->tmpdir; + +use DistGen; +my $dist = DistGen->new( dir => $tmp, name => 'Simple::Share' ); +$dist->regen; +$dist->chdir_in; + +#--------------------------------------------------------------------------# +# Test setting 'share_dir' +#--------------------------------------------------------------------------# + +my $mb = $dist->new_from_context; + +# Test without a 'share' dir +ok( $mb, "Created Module::Build object" ); +is( $mb->share_dir, undef, + "default share undef if no 'share' dir exists" +); +ok( ! exists $mb->{properties}{requires}{'File::ShareDir'}, + "File::ShareDir not added to 'requires'" +); + +# Add 'share' dir and an 'other' dir and content +$dist->add_file('share/foo.txt',<< '---'); +This is foo.txt +--- +$dist->add_file('other/share/bar.txt',<< '---'); +This is bar.txt +--- +$dist->regen; +ok( -e catfile(qw/share foo.txt/), "Created 'share' directory" ); +ok( -e catfile(qw/other share bar.txt/), "Created 'other/share' directory" ); + +# Check default when share_dir is not given +stdout_stderr_of( sub { $mb = $dist->new_from_context }); +is_deeply( $mb->share_dir, { dist => [ 'share' ] }, + "Default share_dir set as dist-type share" +); +is( $mb->{properties}{requires}{'File::ShareDir'}, '1.00', + "File::ShareDir 1.00 added to 'requires'" +); + +# share_dir set to scalar +$dist->change_build_pl( + { + module_name => $dist->name, + license => 'perl', + share_dir => 'share', + } +); +$dist->regen; +stdout_stderr_of( sub { $mb = $dist->new_from_context }); +is_deeply( $mb->share_dir, { dist => [ 'share' ] }, + "Scalar share_dir set as dist-type share" +); + +# share_dir set to arrayref +$dist->change_build_pl( + { + module_name => $dist->name, + license => 'perl', + share_dir => [ 'share' ], + } +); +$dist->regen; +stdout_stderr_of( sub { $mb = $dist->new_from_context }); +is_deeply( $mb->share_dir, { dist => [ 'share' ] }, + "Arrayref share_dir set as dist-type share" +); + +# share_dir set to hashref w scalar +$dist->change_build_pl( + { + module_name => $dist->name, + license => 'perl', + share_dir => { dist => 'share' }, + } +); +$dist->regen; +stdout_stderr_of( sub { $mb = $dist->new_from_context }); +is_deeply( $mb->share_dir, { dist => [ 'share' ] }, + "Hashref share_dir w/ scalar dist set as dist-type share" +); + +# share_dir set to hashref w array +$dist->change_build_pl( + { + module_name => $dist->name, + license => 'perl', + share_dir => { dist => [ 'share' ] }, + } +); +$dist->regen; +stdout_stderr_of( sub { $mb = $dist->new_from_context }); +is_deeply( $mb->share_dir, { dist => [ 'share' ] }, + "Hashref share_dir w/ arrayref dist set as dist-type share" +); + +# Generate a module sharedir (scalar) +$dist->change_build_pl( + { + module_name => $dist->name, + license => 'perl', + share_dir => { + dist => 'share', + module => { $dist->name => 'other/share' }, + }, + } +); +$dist->regen; +stdout_stderr_of( sub { $mb = $dist->new_from_context }); +is_deeply( $mb->share_dir, + { dist => [ 'share' ], + module => { $dist->name => ['other/share'] }, + }, + "Hashref share_dir w/ both dist and module shares (scalar-form)" +); + +# Generate a module sharedir (array) +$dist->change_build_pl( + { + module_name => $dist->name, + license => 'perl', + share_dir => { + dist => [ 'share' ], + module => { $dist->name => ['other/share'] }, + }, + } +); +$dist->regen; +stdout_stderr_of( sub { $mb = $dist->new_from_context }); +is_deeply( $mb->share_dir, + { dist => [ 'share' ], + module => { $dist->name => ['other/share'] }, + }, + "Hashref share_dir w/ both dist and module shares (array-form)" +); + +#--------------------------------------------------------------------------# +# test constructing to/from mapping +#--------------------------------------------------------------------------# + +is_deeply( $mb->_find_share_dir_files, + { + catfile(qw/share foo.txt/) => catfile(qw/dist Simple-Share foo.txt/), + catfile(qw/other share bar.txt/) => catfile(qw/module Simple-Share bar.txt/), + }, + "share_dir filemap for copying to lib complete" +); + +#--------------------------------------------------------------------------# +# test moving files to blib +#--------------------------------------------------------------------------# + +$mb->dispatch('build'); + +ok( -d 'blib', "Build ran and blib exists" ); +ok( -d 'blib/lib/auto/share', "blib/lib/auto/share exists" ); + +my $share_list = Module::Build->rscan_dir('blib/lib/auto/share', sub {-f}); + +is_deeply( + [ sort @$share_list ], [ + 'blib/lib/auto/share/dist/Simple-Share/foo.txt', + 'blib/lib/auto/share/module/Simple-Share/bar.txt', + ], + "share_dir files copied to blib" +); + +#--------------------------------------------------------------------------# +# test installing +#--------------------------------------------------------------------------# + +my $temp_install = 'temp_install'; +mkdir $temp_install; +ok( -d $temp_install, "temp install dir created" ); + +$mb->install_base($temp_install); +stdout_of( sub { $mb->dispatch('install') } ); + +$share_list = Module::Build->rscan_dir( + "$temp_install/lib/perl5/auto/share", sub {-f} +); + +is_deeply( + [ sort @$share_list ], [ + "$temp_install/lib/perl5/auto/share/dist/Simple-Share/foo.txt", + "$temp_install/lib/perl5/auto/share/module/Simple-Share/bar.txt", + ], + "share_dir files correctly installed" +); + +#--------------------------------------------------------------------------# +# test with File::ShareDir +#--------------------------------------------------------------------------# + +SKIP: { + eval { require File::ShareDir; File::ShareDir->VERSION(1.00) }; + skip "needs File::ShareDir 1.00", 2 if $@; + + unshift @INC, File::Spec->catdir($temp_install, qw/lib perl5/); + require Simple::Share; + + eval {File::ShareDir::dist_file('Simple-Share','foo.txt') }; + is( $@, q{}, "Found shared dist file" ); + + eval {File::ShareDir::module_file('Simple::Share','bar.txt') }; + is( $@, q{}, "Found shared module file" ); +} diff --git a/cpan/Module-Build/t/resume.t b/cpan/Module-Build/t/resume.t new file mode 100644 index 0000000000..add123d3d4 --- /dev/null +++ b/cpan/Module-Build/t/resume.t @@ -0,0 +1,43 @@ +use strict; +use lib 't/lib'; +use MBTest; +plan tests => 3; # or 'no_plan' +use DistGen; + +# Ensure any Module::Build modules are loaded from correct directory +blib_load('Module::Build'); + +# create dist object in a temp directory +# enter the directory and generate the skeleton files +my $dist = DistGen->new->chdir_in; +$dist->add_file('mylib/MBUtil.pm', << "---"); +package MBUtil; +sub foo { 42 } +1; +--- + +$dist->add_file('Build.PL', << "---"); +use strict; +use lib 'mylib'; +use MBUtil; +use Module::Build; + +die unless MBUtil::foo() == 42; + +my \$builder = Module::Build->new( +module_name => '$dist->{name}', +license => 'perl', +); + +\$builder->create_build_script(); +--- + +$dist->regen; + +# get a Module::Build object and test with it +my $mb = $dist->new_from_context(); # quiet by default +isa_ok( $mb, "Module::Build" ); +is( $mb->dist_name, "Simple", "dist_name is 'Simple'" ); +ok( ( grep { /mylib/ } @INC ), "resume added \@INC addition to \@INC"); + +# vim:ts=2:sw=2:et:sta:sts=2 diff --git a/cpan/Module-Build/t/runthrough.t b/cpan/Module-Build/t/runthrough.t index 21d3d1c113..741755c12c 100644 --- a/cpan/Module-Build/t/runthrough.t +++ b/cpan/Module-Build/t/runthrough.t @@ -2,12 +2,10 @@ use strict; use lib 't/lib'; -use MBTest tests => 32; +use MBTest tests => 30; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); - -use Module::Build::ConfigData; +blib_load('Module::Build'); +blib_load('Module::Build::ConfigData'); my $have_yaml = Module::Build::ConfigData->feature('YAML_support'); ######################### @@ -24,6 +22,9 @@ $dist->change_build_pl requires => { 'File::Spec' => 0 }, }); +$dist->add_file( 'MANIFEST.SKIP', <<'---' ); +^MYMETA.yml$ +--- $dist->add_file( 'script', <<'---' ); #!perl -w print "Hello, World!\n"; @@ -169,12 +170,11 @@ SKIP: { # do a strict string comparison, but absent an XML parser it's the # best we can do. is $ppd, <<'EOF'; -<SOFTPKG NAME="Simple" VERSION="0,01,0,0"> - <TITLE>Simple</TITLE> +<SOFTPKG NAME="Simple" VERSION="0.01"> <ABSTRACT>Perl extension for blah blah blah</ABSTRACT> <AUTHOR>A. U. Thor, a.u.thor@a.galaxy.far.far.away</AUTHOR> <IMPLEMENTATION> - <DEPENDENCY NAME="File-Spec" VERSION="0,0,0,0" /> + <REQUIRE NAME="File::Spec" VERSION="0" /> <CODEBASE HREF="/path/to/codebase" /> </IMPLEMENTATION> </SOFTPKG> @@ -189,8 +189,6 @@ ok ! -e $mb->build_script; ok ! -e $mb->config_dir; ok ! -e $mb->dist_dir; -$dist->remove; - SKIP: { skip( 'Windows-only test', 4 ) unless $^O =~ /^MSWin/; @@ -223,8 +221,5 @@ echo Hello, World! my $out = slurp( $script_file ); is $out, $script_data, ' unmodified by pl2bat'; - $dist->remove; } -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/sample.t b/cpan/Module-Build/t/sample.t new file mode 100644 index 0000000000..d83bc56ecc --- /dev/null +++ b/cpan/Module-Build/t/sample.t @@ -0,0 +1,20 @@ +# sample.t -- a sample test file for Module::Build + +use strict; +use lib 't/lib'; +use MBTest tests => 2; # or 'no_plan' +use DistGen; + +# Ensure any Module::Build modules are loaded from correct directory +blib_load('Module::Build'); + +# create dist object in a temp directory +# enter the directory and generate the skeleton files +my $dist = DistGen->new->chdir_in->regen; + +# get a Module::Build object and test with it +my $mb = $dist->new_from_context(); # quiet by default +isa_ok( $mb, "Module::Build" ); +is( $mb->dist_name, "Simple", "dist_name is 'Simple'" ); + +# vim:ts=2:sw=2:et:sta:sts=2 diff --git a/cpan/Module-Build/t/script_dist.t b/cpan/Module-Build/t/script_dist.t index e6b7fd8832..02faca0132 100644 --- a/cpan/Module-Build/t/script_dist.t +++ b/cpan/Module-Build/t/script_dist.t @@ -8,7 +8,8 @@ use MBTest 'no_plan'; use DistGen qw(undent); -use Module::Build; +blib_load('Module::Build'); +blib_load('Module::Build::ConfigData'); # XXX DistGen shouldn't be assuming module-ness? my $dist = DistGen->new(dir => MBTest->tmpdir); @@ -69,12 +70,11 @@ is_deeply($mb->dist_author, ['A. U. Thor, a.u.thor@a.galaxy.far.far.away']); ok $mb->dispatch('distmeta'); -use Module::Build::ConfigData; SKIP: { skip( 'YAML_support feature is not enabled', 1 ) unless Module::Build::ConfigData->feature('YAML_support'); - require YAML; - my $yml = YAML::LoadFile('META.yml'); + require YAML::Tiny; + my $yml = YAML::Tiny::LoadFile('META.yml'); is_deeply($yml->{provides}, \%meta_provides); } $dist->chdir_original if $dist->did_chdir; diff --git a/cpan/Module-Build/t/test_file_exts.t b/cpan/Module-Build/t/test_file_exts.t index 9dbf73e290..5bb803c7aa 100644 --- a/cpan/Module-Build/t/test_file_exts.t +++ b/cpan/Module-Build/t/test_file_exts.t @@ -2,11 +2,10 @@ use strict; use lib 't/lib'; -use MBTest tests => 5; +use MBTest tests => 3; use DistGen; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); my $tmp = MBTest->tmpdir; my $dist = DistGen->new( dir => $tmp ); @@ -39,7 +38,4 @@ my $out = uc(stdout_of( like $out, qr/^OK 1 - FIRST MYTEST[.]S/m, 'Should see first test output'; like $out, qr/^OK 2 - SECOND MYTEST[.]S/m, 'Should see second test output'; -# Cleanup. -$dist->remove; - # vim:ts=4:sw=4:et:sta diff --git a/cpan/Module-Build/t/test_type.t b/cpan/Module-Build/t/test_type.t index 3c6cfb61e4..fe4d599d72 100644 --- a/cpan/Module-Build/t/test_type.t +++ b/cpan/Module-Build/t/test_type.t @@ -9,10 +9,9 @@ BEGIN { use strict; use lib 't/lib'; -use MBTest tests => 9; +use MBTest tests => 7; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); my $tmp = MBTest->tmpdir; @@ -72,6 +71,4 @@ like($output, qr/\.\. ?OK/); is($::x, 3, "called a third time"); -$dist->remove; - # vim:ts=4:sw=4:et:sta diff --git a/cpan/Module-Build/t/test_types.t b/cpan/Module-Build/t/test_types.t index 5f3f5cff8d..d88e215aa3 100644 --- a/cpan/Module-Build/t/test_types.t +++ b/cpan/Module-Build/t/test_types.t @@ -2,16 +2,13 @@ use strict; use lib 't/lib'; -use MBTest tests => 15 + 12; +use MBTest tests => 25; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); - -my $tmp = MBTest->tmpdir; +blib_load('Module::Build'); use DistGen; -my $dist = DistGen->new(dir => $tmp); +my $dist = DistGen->new()->chdir_in; $dist->add_file('t/special_ext.st', <<'---'); #!perl @@ -34,7 +31,6 @@ die "don't run this non-test file"; --- $dist->regen; -$dist->chdir_in; ######################### my $mb = Module::Build->subclass( @@ -98,10 +94,10 @@ is(scalar(@{[$all_output =~ m/OK 1/mg]}), 3 ); is(scalar(@{[$all_output =~ m/OK/mg]}), 8 ); is(scalar(@{[$all_output =~ m/ALL TESTS SUCCESSFUL\./mg]}), 1); -$dist->remove; - { # once-again +$dist->revert; + $dist->add_file('t/foo/special.st', <<'---'); #!perl use Test::More tests => 2; @@ -114,7 +110,6 @@ use strict; use Simple; ok 1; --- $dist->regen; -$dist->chdir_in; my $mb = Module::Build->subclass( code => q# @@ -174,7 +169,6 @@ like($all_output, qr/^OK 2 - SECOND TEST IN ANOTHER_EXT/m); is(scalar(@{[$all_output =~ m/(OK 1)/mg]}), 5 ); is(scalar(@{[$all_output =~ m/(OK)/mg]}), 13 ); -$dist->remove; } # end once-again # vim:ts=4:sw=4:et:sta diff --git a/cpan/Module-Build/t/tilde.t b/cpan/Module-Build/t/tilde.t index 5b39204171..692ade0c8a 100644 --- a/cpan/Module-Build/t/tilde.t +++ b/cpan/Module-Build/t/tilde.t @@ -4,10 +4,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 18; +use MBTest tests => 16; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); my $tmp = MBTest->tmpdir; @@ -111,6 +110,3 @@ SKIP: { like( run_sample( $p => "~$me/foo")->$p(), qr($expected)i ); } - -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/use_tap_harness.t b/cpan/Module-Build/t/use_tap_harness.t index d14cb052ba..f6e7e5073a 100644 --- a/cpan/Module-Build/t/use_tap_harness.t +++ b/cpan/Module-Build/t/use_tap_harness.t @@ -4,7 +4,7 @@ use strict; use Test::More; use lib 't/lib'; if (eval { require TAP::Harness } && TAP::Harness->VERSION >= 3) { - plan tests => 8; + plan tests => 9; } else { plan skip_all => 'TAP::Harness 3+ not installed' } @@ -12,21 +12,24 @@ if (eval { require TAP::Harness } && TAP::Harness->VERSION >= 3) { use MBTest; use DistGen; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); my $tmp = MBTest->tmpdir; my $dist = DistGen->new( dir => $tmp ); $dist->regen; - $dist->chdir_in; + ######################### # Make sure that TAP::Harness properly does its thing. -ok my $mb = Module::Build->new( +$dist->change_build_pl( module_name => $dist->name, use_tap_harness => 1, quiet => 1, -), 'Construct build object with test_file_exts parameter'; +); +$dist->regen; + +ok my $mb = $dist->new_from_context, + 'Construct build object with test_file_exts parameter'; $mb->add_to_cleanup('save_out'); # Use uc() so we don't confuse the current test output @@ -40,12 +43,16 @@ like $out, qr/^ALL TESTS SUCCESSFUL/m, 'Should see test success message'; ######################### # Make sure that arguments are passed through to TAP::Harness. -ok $mb = Module::Build->new( +$dist->change_build_pl( module_name => $dist->name, use_tap_harness => 1, tap_harness_args => { verbosity => 0 }, quiet => 1, -), 'Construct build object with test_file_exts parameter'; +); +$dist->regen; + +ok $mb = $dist->new_from_context, + 'Construct build object with test_file_exts parameter'; $mb->add_to_cleanup('save_out'); # Use uc() so we don't confuse the current test output @@ -56,6 +63,32 @@ $out = uc(stdout_of( unlike $out, qr/^OK 1/m, 'Should not see first test output'; like $out, qr/^ALL TESTS SUCCESSFUL/m, 'Should see test success message'; -$dist->remove; +#--------------------------------------------------------------------------# +# test that a failing test dies +#--------------------------------------------------------------------------# + +$dist->change_build_pl( + module_name => $dist->name, + use_tap_harness => 1, + tap_harness_args => { verbosity => 1 }, + quiet => 1, +); +$dist->change_file('t/basic.t',<<"---"); +use Test::More tests => 1; +use strict; + +use $dist->{name}; +ok 0; +--- +$dist->regen; + +ok $mb = $dist->new_from_context, + 'Construct build object after setting tests to fail'; +# Use uc() so we don't confuse the current test output +$out = stdout_stderr_of( sub { $dist->run_build('test')} ); +ok( $?, "'Build test' had non-zero exit code" ); +like( $out, qr{Errors in testing\. Cannot continue\.}, + "Saw emulated Test::Harness die() message" +); # vim:ts=4:sw=4:et:sta diff --git a/cpan/Module-Build/t/versions.t b/cpan/Module-Build/t/versions.t index 7f511e58f6..5eafbac297 100644 --- a/cpan/Module-Build/t/versions.t +++ b/cpan/Module-Build/t/versions.t @@ -2,10 +2,9 @@ use strict; use lib 't/lib'; -use MBTest tests => 4; +use MBTest tests => 2; -use_ok 'Module::Build'; -ensure_blib('Module::Build'); +blib_load('Module::Build'); my $tmp = MBTest->tmpdir; @@ -20,7 +19,3 @@ my $file = File::Spec->catfile( $dist->dirname, 'lib', @mod ) . '.pm'; is( Module::Build->version_from_file( $file ), '0.01', 'version_from_file' ); ok( Module::Build->compare_versions( '1.01_01', '>', '1.01' ), 'compare: 1.0_01 > 1.0' ); - - -# cleanup -$dist->remove; diff --git a/cpan/Module-Build/t/write_default_maniskip.t b/cpan/Module-Build/t/write_default_maniskip.t index 084d81ed3e..40389f20dc 100644 --- a/cpan/Module-Build/t/write_default_maniskip.t +++ b/cpan/Module-Build/t/write_default_maniskip.t @@ -8,14 +8,14 @@ use MBTest 'no_plan'; use DistGen; use Cwd; -use_ok 'Module::Build'; -ensure_blib 'Module::Build'; +blib_load('Module::Build'); { my $cwd = Cwd::cwd; chdir MBTest->tmpdir(); my $build = Module::Build->new( + module_name => "Foo::Bar", dist_name => "Foo-Bar", dist_version => '1.23', ); diff --git a/cpan/Module-Build/t/xs.t b/cpan/Module-Build/t/xs.t index e3f1ed7dd1..6d167c8539 100644 --- a/cpan/Module-Build/t/xs.t +++ b/cpan/Module-Build/t/xs.t @@ -3,11 +3,12 @@ use strict; use lib 't/lib'; use MBTest; -use Module::Build; use Config; my $tmp; +blib_load('Module::Build'); + { my ($have_c_compiler, $C_support_feature, $tmp_exec) = check_compiler(); @@ -20,24 +21,20 @@ my $tmp; } elsif ( !$Config{usedl} ) { plan skip_all => 'Perl not compiled for dynamic loading' } else { - plan tests => 23; + plan tests => 20; } require Cwd; $tmp = MBTest->tmpdir( $tmp_exec ? undef : Cwd::cwd ); } -ensure_blib('Module::Build'); ######################### use DistGen; -my $dist = DistGen->new( dir => $tmp, xs => 1 ); -$dist->regen; - -$dist->chdir_in; -my $mb = Module::Build->new_from_context; +my $dist = DistGen->new( dir => $tmp, xs => 1 )->chdir_in->regen; +my $mb = $dist->new_from_context; eval {$mb->dispatch('clean')}; is $@, ''; @@ -83,7 +80,7 @@ is $@, ''; # We can't be verbose in the sub-test, because Test::Harness will # think that the output is for the top-level test. -eval {$mb->dispatch('test')}; +stdout_stderr_of( sub { eval {$mb->dispatch('test')} }); is $@, ''; eval {$mb->dispatch('clean')}; @@ -106,42 +103,31 @@ is $@, ''; # Make sure blib/ is gone after 'realclean' ok ! -e 'blib'; - -# cleanup -$dist->remove; - - ######################################## # Try a XS distro with a deep namespace -$dist = DistGen->new( name => 'Simple::With::Deep::Name', - dir => $tmp, xs => 1 ); -$dist->regen; -$dist->chdir_in; -$mb = Module::Build->new_from_context; -is $@, ''; +$dist->reset( name => 'Simple::With::Deep::Name', dir => $tmp, xs => 1 ); +$dist->chdir_in->regen; -$mb->dispatch('build'); -is $@, ''; +$mb = $dist->new_from_context; -$mb->dispatch('test'); +eval { $mb->dispatch('build') }; is $@, ''; -$mb->dispatch('realclean'); +stdout_stderr_of( sub { eval { $mb->dispatch('test') } } ); is $@, ''; -# cleanup -$dist->remove; - +eval { $mb->dispatch('realclean') }; +is $@, ''; ######################################## # Try a XS distro using a flat directory structure # and a 'dist_name' instead of a 'module_name' -$dist = DistGen->new( name => 'Dist-Name', dir => $tmp, xs => 1 ); +$dist->reset( name => 'Dist-Name', dir => $tmp, xs => 1 )->chdir_in; $dist->remove_file('lib/Dist-Name.pm'); $dist->remove_file('lib/Dist-Name.xs'); @@ -211,20 +197,15 @@ ok( Simple::okay() eq 'ok' ); --- $dist->regen; -$dist->chdir_in; - -$mb = Module::Build->new_from_context; -is $@, ''; +$mb = $dist->new_from_context; -$mb->dispatch('build'); +eval { $mb->dispatch('build') }; is $@, ''; -$mb->dispatch('test'); +stdout_of( sub { eval { $mb->dispatch('test') } } ); is $@, ''; -$mb->dispatch('realclean'); +eval { $mb->dispatch('realclean') }; is $@, ''; -# cleanup -$dist->remove; |