From a314697d77d1e36849713cf4fbc8ebb62fedbf78 Mon Sep 17 00:00:00 2001 From: "Randy W. Sims" Date: Wed, 29 Mar 2006 09:10:32 -0500 Subject: [PATCH] Re: New Module::Build released From: "Randy W. Sims" Message-ID: <442ADBA8.4000203@thepierianspring.org> p4raw-id: //depot/perl@27631 --- MANIFEST | 2 + lib/ExtUtils/CBuilder.pm | 2 +- lib/ExtUtils/CBuilder/Changes | 5 + lib/ExtUtils/CBuilder/Platform/VMS.pm | 10 +- lib/Module/Build.pm | 90 +++++++++- lib/Module/Build/Authoring.pod | 292 ++++++++++++++++++++++++++----- lib/Module/Build/Base.pm | 271 ++++++++++++++++++---------- lib/Module/Build/Changes | 24 +++ lib/Module/Build/Platform/MacOS.pm | 2 + lib/Module/Build/Platform/VMS.pm | 14 ++ lib/Module/Build/Platform/Windows.pm | 2 + lib/Module/Build/Platform/os2.pm | 2 + lib/Module/Build/YAML.pm | 162 +++++++++++++++++ lib/Module/Build/t/bundled/Tie/CPHash.pm | 25 +-- lib/Module/Build/t/lib/DistGen.pm | 16 +- lib/Module/Build/t/mbyaml.t | 149 ++++++++++++++++ lib/Module/Build/t/metadata.t | 11 +- 17 files changed, 908 insertions(+), 171 deletions(-) create mode 100644 lib/Module/Build/YAML.pm create mode 100644 lib/Module/Build/t/mbyaml.t diff --git a/MANIFEST b/MANIFEST index 26d0054..944449f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1953,6 +1953,7 @@ lib/Module/Build/ConfigData.pm Module::Build lib/Module/Build/Cookbook.pm Module::Build lib/Module/Build/ModuleInfo.pm Module::Build lib/Module/Build/Notes.pm Module::Build +lib/Module/Build/YAML.pm Module::Build lib/Module/Build/Platform/aix.pm Module::Build lib/Module/Build/Platform/Amiga.pm Module::Build lib/Module/Build/Platform/cygwin.pm Module::Build @@ -1980,6 +1981,7 @@ lib/Module/Build/t/install.t Module::Build lib/Module/Build/t/lib/DistGen.pm Module::Build lib/Module/Build/t/lib/MBTest.pm Module::Build lib/Module/Build/t/manifypods.t Module::Build +lib/Module/Build/t/mbyaml.t Module::Build lib/Module/Build/t/metadata.t Module::Build lib/Module/Build/t/metadata2.t Module::Build lib/Module/Build/t/moduleinfo.t Module::Build diff --git a/lib/ExtUtils/CBuilder.pm b/lib/ExtUtils/CBuilder.pm index e2c6cf3..730721f 100644 --- a/lib/ExtUtils/CBuilder.pm +++ b/lib/ExtUtils/CBuilder.pm @@ -5,7 +5,7 @@ use File::Path (); use File::Basename (); use vars qw($VERSION @ISA); -$VERSION = '0.17'; +$VERSION = '0.18'; $VERSION = eval $VERSION; # Okay, this is the brute-force method of finding out what kind of diff --git a/lib/ExtUtils/CBuilder/Changes b/lib/ExtUtils/CBuilder/Changes index 460f628..32b57ca 100644 --- a/lib/ExtUtils/CBuilder/Changes +++ b/lib/ExtUtils/CBuilder/Changes @@ -1,5 +1,10 @@ Revision history for Perl extension ExtUtils::CBuilder. +0.18 Sat Mar 25 13:35:47 CST 2006 + + - Yet more fixes for arg_defines() on VMS. [Craig A. Berry and John + E. Malmberg] + 0.17 Wed Mar 15 22:46:15 CST 2006 - When we're being run from an uninstalled perl distribution diff --git a/lib/ExtUtils/CBuilder/Platform/VMS.pm b/lib/ExtUtils/CBuilder/Platform/VMS.pm index 56285a5..9921f61 100644 --- a/lib/ExtUtils/CBuilder/Platform/VMS.pm +++ b/lib/ExtUtils/CBuilder/Platform/VMS.pm @@ -14,18 +14,18 @@ sub arg_defines { s/"/""/g foreach values %args; - my $config_defines; + my @config_defines; # VMS can only have one define qualifier; add the one from config, if any. - if ($self->{config}{ccflags} =~ s{/def[^=]+(?:=)+(?:\()?([^\/\)]*)} {}i) { - $config_defines = $1; + if ($self->{config}{ccflags} =~ s{/ def[^=]+ =+ \(? ([^\/\)]*) } {}ix) { + push @config_defines, $1; } - return unless (scalar keys %args) || $config_defines; + return '' unless keys(%args) || @config_defines; return ('/define=(' - . (defined $config_defines ? "$config_defines," : '') . join(',', + @config_defines, map "\"$_" . ( length($args{$_}) ? "=$args{$_}" : '') . "\"", keys %args) . ')'); diff --git a/lib/Module/Build.pm b/lib/Module/Build.pm index cd0b8b5..6d2623f 100644 --- a/lib/Module/Build.pm +++ b/lib/Module/Build.pm @@ -15,7 +15,7 @@ use Module::Build::Base; use vars qw($VERSION @ISA); @ISA = qw(Module::Build::Base); -$VERSION = '0.27_09'; +$VERSION = '0.27_10'; $VERSION = eval $VERSION; # Okay, this is the brute-force method of finding out what kind of @@ -233,25 +233,25 @@ The following build actions are provided by default. =item build +[version 0.01] + If you run the C script without any arguments, it runs the C action, which in turn runs the C and C actions. This is analogous to the MakeMaker 'make all' target. -=item testpodcoverage - -This checks the pod coverage of the distribution and -produces C-style output. If you are a module author, -this is useful to run before creating a new release. - =item clean +[version 0.01] + This action will clean up any files that the build process may have created, including the C directory (but not including the C<_build/> directory and the C script itself). =item code +[version 0.20] + This action builds your codebase. By default it just creates a C directory and copies any C<.pm> @@ -270,10 +270,14 @@ with) will get copied correctly. =item config_data +[version 0.26] + ... =item diff +[version 0.14] + This action will compare the files about to be installed with their installed counterparts. For .pm and .pod files, a diff will be shown (this currently requires a 'diff' program to be in your PATH). For @@ -288,6 +292,8 @@ parameters it will accept - a good one is C<-u>: =item dist +[version 0.02] + This action is helpful for module authors who want to package up their module for source distribution through a medium like CPAN. It will create a tarball of the files listed in F and compress the tarball using @@ -302,15 +308,21 @@ want by supplying an explicit C (and optional C) parameter: =item distcheck +[version 0.05] + Reports which files are in the build directory but not in the F file, and vice versa. (See L for details.) =item distclean +[version 0.05] + Performs the 'realclean' action and then the 'distcheck' action. =item distdir +[version 0.05] + Creates a "distribution directory" named C<$dist_name-$dist_version> (if that directory already exists, it will be removed first), then copies all the files listed in the F file to that directory. @@ -318,13 +330,19 @@ This directory is what the distribution tarball is created from. =item distmeta +[version 0.21] + Creates the F file that describes the distribution. F is a file containing various bits of "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 in YAML format, so -the C module must be installed in order to create it. The +distribution. This file is created as F in YAML format. +It is recommended that the C module be installed to create it. +If the C 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. + F file must also be listed in F - if it's not, a warning will be issued. @@ -333,18 +351,24 @@ L =item distsign +[version 0.16] + Uses C to create a SIGNATURE file for your distribution, and adds the SIGNATURE file to the distribution's MANIFEST. =item disttest +[version 0.05] + Performs the 'distdir' action, then switches into that directory and runs a C, followed by the 'build' and 'test' actions in that directory. =item docs +[version 0.20] + This will generate documentation (e.g. Unix man pages and html documents) for any installable items under B that contain POD. If there are no C or C installation @@ -355,12 +379,16 @@ taken for html documents. =item fakeinstall +[version 0.02] + This is just like the C action, but it won't actually do anything, it will just report what it I have done if you had actually run the C action. =item help +[version 0.03] + This action will simply print out a message that is meant to help you use the build process. It will show you a list of available build actions too. @@ -371,6 +399,8 @@ find for that action. =item html +[version 0.26] + This will generate HTML documentation for any binary or library files under B that contain POD. The HTML documentation will only be installed if the install paths can be determined from values in @@ -380,6 +410,8 @@ and/or C installation targets. =item install +[version 0.01] + This action will use C to install the files from C into the system. See L for details about how Module::Build determines where to install @@ -398,6 +430,8 @@ situation indeed. =item manifest +[version 0.05] + This is an action intended for use by module authors, not people installing modules. It will bring the F up to date with the files currently present in the distribution. You may use a @@ -423,6 +457,8 @@ what the C action would do, without actually doing anything. =item manpages +[version 0.28] + This will generate man pages for any binary or library files under B that contain POD. The man pages will only be installed if the install paths can be determined from values in C. You can @@ -432,6 +468,8 @@ targets. =item ppd +[version 0.20] + Build a PPD file for your distribution. This action takes an optional argument C which is used in @@ -445,6 +483,8 @@ Example: =item ppmdist +[version 0.23] + Generates a PPM binary distribution and a PPD description file. This action also invokes the 'ppd' action, so it can accept the same C argument described under that action. @@ -455,6 +495,8 @@ the result. =item prereq_report +[version 0.28] + This action prints out a list of all prerequisites, the versions required, and the versions actually installed. This can be useful for reviewing the configuration of your system prior to a build, or when compiling data to send @@ -462,6 +504,8 @@ for a bug report. =item pure_install +[version 0.28] + This action is identical to the C action. In the future, though, if C starts writing to the file file F<$(INSTALLARCHLIB)/perllocal.pod>, C won't, and that @@ -469,6 +513,8 @@ will be the only difference between them. =item realclean +[version 0.01] + This action is just like the C action, but also removes the C<_build> directory and the C script. If you run the C action, you are essentially starting over, so you will @@ -476,11 +522,15 @@ have to re-create the C script again. =item skipcheck +[version 0.05] + Reports which files are skipped due to the entries in the F file (See L for details) =item test +[version 0.01] + This will use C to run any regression tests and report their results. Tests can be defined in the standard places: a file called C in the top-level directory, or several files ending @@ -514,6 +564,8 @@ or use a C-style pattern: =item testcover +[version 0.26] + Runs the C action using C, generating a code-coverage report showing which parts of the code were actually exercised during the tests. @@ -525,17 +577,31 @@ environment variable: =item testdb +[version 0.05] + This is a synonym for the 'test' action with the C argument. =item testpod +[version 0.25] + This checks all the files described in the C action and produces C-style output. If you are a module author, this is useful to run before creating a new release. +=item testpodcoverage + +[version 0.28] + +This checks the pod coverage of the distribution and +produces C-style output. If you are a module author, +this is useful to run before creating a new release. + =item versioninstall +[version 0.16] + ** Note: since C is so new, and since we just recently added support for it here too, this feature is to be considered experimental. ** @@ -599,6 +665,8 @@ Display extra information about the Build on output. =head2 Default Options File (F<.modulebuildrc>) +[version 0.28] + When Module::Build starts up, it will look for a file, F<$ENV{HOME}/.modulebuildrc>. If the file exists, the options specified there will be used as defaults, as if they were typed on the @@ -631,6 +699,8 @@ absolute path of the file containing your options. =head1 INSTALL PATHS +[version 0.19] + When you invoke Module::Build's C action, it needs to figure out where to install things. The nutshell version of how this works is that default installation locations are determined from @@ -798,6 +868,8 @@ platform you're installing on. =head2 About PREFIX Support +[version 0.28] + First, it is necessary to understand the original idea behind C. If, for example, the default installation locations for your machine are F for modules, diff --git a/lib/Module/Build/Authoring.pod b/lib/Module/Build/Authoring.pod index a92a81b..0bf2562 100644 --- a/lib/Module/Build/Authoring.pod +++ b/lib/Module/Build/Authoring.pod @@ -67,6 +67,8 @@ stabilizes. =item current() +[version 0.20] + This method returns a reasonable facsimile of the currently-executing C object representing the current build. You can use this object to query its C method, inquire about installed @@ -97,6 +99,8 @@ C was invoked from. =item new() +[version 0.03] + Creates a new Module::Build object. Arguments to the new() method are listed below. Most arguments are optional, but you must provide either the C argument, or C and one of @@ -109,11 +113,15 @@ version. =item add_to_cleanup +[version 0.19] + An array reference of files to be cleaned up when the C action is performed. See also the add_to_cleanup() method. =item auto_features +[version 0.26] + This parameter supports the setting of features (see L) automatically based on a set of prerequisites. For instance, for a module that could optionally use either MySQL or @@ -146,6 +154,8 @@ requirements can be specified. =item autosplit +[version 0.04] + An optional C argument specifies a file which should be run through the C function. If multiple files should be split, the argument may be given as an array of the files to @@ -159,6 +169,8 @@ startup. =item build_class +[version 0.28] + The Module::Build class or subclass to use in the build script. Defaults to "Module::Build" or the class name passed to or created by a call to C. This property is useful if you're @@ -170,6 +182,8 @@ executed. =item build_requires +[version 0.07] + Modules listed in this section are necessary to build and install the given module, but are not necessary for regular usage of it. This is actually an important distinction - it allows for tighter control over @@ -179,8 +193,22 @@ checking on binary/packaged distributions of the module. See the documentation for L<"PREREQUISITES"> for the details of how requirements can be specified. +=item create_packlist + +If true, this parameter tells Module::Build to create a F<.packlist> +file during the C action, just like ExtUtils::MakeMaker does. +The file is created in a subdirectory of the C installation +location. It is used by some other tools (CPAN, CPANPLUS, etc.) for +determining what files are part of an install. + +The default value is true. This parameter was introduced in +Module::Build version 0.2609; previously no packlists were ever +created by Module::Build. + =item c_source +[version 0.04] + An optional C argument specifies a directory which contains C source files that the rest of the build may depend on. Any C<.c> files in the directory will be compiled to object files. The @@ -189,6 +217,8 @@ linking phases of any C or XS files. =item conflicts +[version 0.07] + Modules listed in this section conflict in some serious way with the given module. C (or some higher-level tool) will refuse to install the given module if the given module/version is also @@ -199,6 +229,8 @@ requirements can be specified. =item create_makefile_pl +[version 0.19] + This parameter lets you use Module::Build::Compat during the C (or C) action to automatically create a Makefile.PL for compatibility with ExtUtils::MakeMaker. The parameter's value @@ -207,6 +239,8 @@ documentation. =item create_readme +[version 0.22] + This parameter tells Module::Build to automatically create a F file at the top level of your distribution. Currently it will simply use C (or C if it's installed) on the file @@ -220,6 +254,8 @@ generated F. =item dist_abstract +[version 0.20] + This should be a short description of the distribution. This is used when generating metadata for F and PPD files. If it is not given then C looks in the POD of the module from which @@ -229,6 +265,8 @@ abstract. =item dist_author +[version 0.20] + This should be something like "John Doe ", or if there are multiple authors, an anonymous array of strings may be specified. This is used when generating metadata for F and @@ -239,6 +277,8 @@ this section. =item dist_name +[version 0.11] + Specifies the name for this distribution. Most authors won't need to set this directly, they can use C to set C to a reasonable default. However, some agglomerative distributions like @@ -247,6 +287,8 @@ to a module name, so C can be set independently. =item dist_version +[version 0.11] + Specifies a version number for the distribution. See C or C for ways to have this set automatically from a C<$VERSION> variable in a module. One way or another, a version @@ -254,6 +296,8 @@ number needs to be set. =item dist_version_from +[version 0.11] + Specifies a file to look for the distribution version in. Most authors won't need to set this directly, they can use C to set it to a reasonable default. @@ -271,6 +315,8 @@ better. =item dynamic_config +[version 0.07] + A boolean flag indicating whether the F file must be executed, or whether this module can be built, tested and installed solely from consulting its metadata file. The main reason to set this @@ -288,6 +334,8 @@ packaging, and convenience improvements. =item extra_linker_flags +[version 0.19] + These parameters can contain array references (or strings, in which case they will be split into arrays) to pass through to the compiler and linker phases when compiling/linking C code. For example, to tell @@ -311,6 +359,8 @@ To link your XS code against glib you might write something like: =item get_options +[version 0.26] + You can pass arbitrary command line options to F or F, and they will be stored in the Module::Build object and can be accessed via the C method. However, sometimes you want @@ -381,12 +431,16 @@ Consult the Getopt::Long documentation for details on its usage. =item include_dirs +[version 0.24] + Specifies any additional directories in which to search for C header files. May be given as a string indicating a single directory, or as a list reference indicating multiple directories. =item install_path +[version 0.19] + You can set paths for individual installable elements by using the C parameter: @@ -401,6 +455,8 @@ C parameter: =item installdirs +[version 0.19] + Determines where files are installed within the normal perl hierarchy as determined by F. Valid values are: C, C, C. The default is C. See @@ -408,6 +464,8 @@ L =item license +[version 0.07] + Specifies the licensing terms of your distribution. Valid options include: @@ -497,12 +555,16 @@ tell me what to do. So if that's you, drop me a line. =item meta_add +[version 0.28] + A hash of key/value pairs that should be added to the F file during the C action. Any existing entries with the same names will be overridden. =item meta_merge +[version 0.28] + A hash of key/value pairs that should be merged into the F file during the C action. Any existing entries with the same names will be overridden. @@ -515,6 +577,8 @@ array value. =item module_name +[version 0.03] + The C is a shortcut for setting default values of C and C, reflecting the fact that the majority of CPAN distributions are centered around one "main" module. @@ -528,6 +592,8 @@ specify explicitly. =item PL_files +[version 0.06] + An optional parameter specifying a set of C<.PL> files in your distribution. These will be run as Perl scripts prior to processing the rest of the files in your distribution. They are usually used as @@ -560,6 +626,8 @@ files: =item pm_files +[version 0.19] + An optional parameter specifying the set of C<.pm> files in this distribution, specified as a hash reference whose keys are the files' locations in the distributions, and whose values are their logical @@ -587,11 +655,15 @@ Unix-like format, not in the style of the local system. =item pod_files +[version 0.19] + Just like C, but used for specifying the set of C<.pod> files in your distribution. =item recommends +[version 0.08] + This is just like the C argument, except that modules listed in this section aren't essential, just a good idea. We'll just print a friendly warning if one of these modules aren't found, but we'll @@ -608,8 +680,18 @@ wants to be helpful. See the documentation for L<"PREREQUISITES"> for the details of how requirements can be specified. +=item recursive_test_files + +[version 0.28] + +Normally, C does not search subdirectories when looking +for tests to run. When this options is set it will search recursively +in all subdirectories of the standard 't' test directory. + =item requires +[version 0.07] + An optional C argument specifies any module prerequisites that the current module depends on. @@ -633,6 +715,8 @@ requirements can be specified. =item script_files +[version 0.18] + An optional parameter specifying a set of files that should be installed as executable perl scripts when the module is installed. May be given as an array reference of the files, or as a hash @@ -649,6 +733,8 @@ though it will continue to exist for several version releases. =item sign +[version 0.16] + If a true value is specified for this parameter, C will be used (via the 'distsign' action) to create a SIGNATURE file for your distribution during the 'distdir' action, and to add the @@ -659,6 +745,8 @@ true if you have C installed on your system. =item test_files +[version 0.23] + An optional parameter specifying a set of files that should be used as C-style regression tests to be run during the C action. May be given as an array reference of the files, or as a hash @@ -675,6 +763,8 @@ for C<*.t> files. =item xs_files +[version 0.19] + Just like C, but used for specifying the set of C<.xs> files in your distribution. @@ -683,6 +773,8 @@ files in your distribution. =item new_from_context(%args) +[version 0.28] + When called from a directory containing a F script and a F file (in other words, the base directory of a distribution), this method will run the F and return the @@ -694,6 +786,8 @@ verbosity. =item resume() +[version 0.03] + You'll probably never call this method directly, it's only called from the auto-generated C script. The C method is only called once, when the user runs C. Thereafter, when @@ -703,6 +797,8 @@ the settings given earlier to C. =item subclass() +[version 0.06] + This creates a new C subclass on the fly, as described in the L<"SUBCLASSING"> section. The caller must provide either a C or C parameter, or both. The C parameter @@ -720,6 +816,8 @@ as the body of the subclass. =item add_build_element($type) +[version 0.26] + Adds a new type of entry to the build process. Accepts a single string specifying its type-name. There must also be a method defined to process things of that type, e.g. if you add a build element called @@ -730,6 +828,8 @@ See also L =item add_to_cleanup(@files) +[version 0.03] + You may call C<< $self->add_to_cleanup(@patterns) >> to tell C that certain files should be removed when the user performs the C action. The arguments to the method are @@ -747,6 +847,8 @@ code that creates them. =item args() +[version 0.26] + my $args_href = $build->args; my %args = $build->args; my $arg_value = $build->args($key); @@ -765,12 +867,16 @@ first argument. =item autosplit_file($from, $to) +[version 0.28] + Invokes the C module on the C<$from> file, sending the output to the C directory inside C<$to>. C<$to> is typically the C directory. =item base_dir() +[version 0.14] + Returns a string containing the root-level directory of this build, i.e. where the C script and the C directory can be found. This is usually the same as the current working directory, @@ -779,11 +885,15 @@ soon as it begins execution. =item build_requires() +[version 0.21] + Returns a hash reference indicating the C prerequisites that were passed to the C method. =item check_installed_status($module, $version) +[version 0.11] + This method returns a hash reference indicating whether a version dependency on a certain module is satisfied. The C<$module> argument is given as a string like C<"Data::Dumper"> or C<"perl">, and the @@ -813,6 +923,8 @@ or as a class method =item check_installed_version($module, $version) +[version 0.05] + Like C, but simply returns true or false depending on whether module C<$module> satisfies the dependency C<$version>. @@ -843,6 +955,8 @@ answer. =item compare_versions($v1, $op, $v2) +[version 0.28] + Compares two module versions C<$v1> and C<$v2> using the operator C<$op>, which should be one of Perl's numeric operators like C or C<< >= >> or the like. We do at least a halfway-decent job of @@ -854,6 +968,8 @@ out to C. =item config() +[version 0.22] + Returns a hash reference containing the C hash, including any changes the author or user has specified. This is a reference to the actual internal hash we use, so you probably shouldn't modify @@ -863,6 +979,8 @@ stuff there. =item config_data($name => $value) +[version 0.26] + With a single argument, returns the value of the configuration variable C<$name>. With two arguments, sets the given configuration variable to the given value. The value may be any perl scalar that's @@ -883,11 +1001,15 @@ See also L. =item conflicts() +[version 0.21] + Returns a hash reference indicating the C prerequisites that were passed to the C method. =item contains_pod($file) +[version 0.20] + [Deprecated] Please see L instead. Returns true if the given file appears to contain POD documentation. @@ -897,6 +1019,8 @@ future. =item copy_if_modified(%parameters) +[version 0.19] + Takes the file in the C parameter and copies it to the file in the C parameter, or the directory in the C parameter, if the file has changed since it was last copied (or if it doesn't exist @@ -912,6 +1036,8 @@ copying will be automatically created. =item create_build_script() +[version 0.05] + Creates an executable script called C in the current directory that will be used to execute further user actions. This script is roughly analogous (in function, not in form) to the Makefile created @@ -921,6 +1047,8 @@ when the C action is performed. =item current_action() +[version 0.28] + Returns the name of the currently-running action, such as "build" or "test". This action is not necessarily the action that was originally invoked by the user. For example, if the user invoked the "test" @@ -934,6 +1062,8 @@ user, see L below. =item depends_on(@actions) +[version 0.28] + Invokes the named action or list of actions in sequence. Using this method is preferred to calling the action explicitly because it performs some internal record-keeping, and it ensures that the same @@ -953,6 +1083,8 @@ whereas C is meant to set the very top action in motion. =item dir_contains($first_dir, $second_dir) +[version 0.28] + Returns true if the first directory logically contains the second directory. This is just a convenience function because C doesn't really provide an easy way to figure this out (but @@ -960,6 +1092,8 @@ C does...). =item dispatch($action, %args) +[version 0.03] + Invokes the build action C<$action>. Optionally, a list of options and their values can be passed in. This is equivalent to invoking an action at the command line, passing in a list of options. @@ -979,24 +1113,32 @@ whereas C is meant to set the very top action in motion. =item dist_dir() +[version 0.28] + Returns the name of the directory that will be created during the C action. The name is derived from the C and C properties. =item dist_name() +[version 0.21] + Returns the name of the current distribution, as passed to the C method in a C or modified C parameter. =item dist_version() +[version 0.21] + Returns the version of the current distribution, as determined by the C method from a C, C, or C parameter. =item do_system($cmd, @args) +[version 0.21] + This is a fairly simple wrapper around Perl's C built-in command. Given a command and an array of optional arguments, this method will print the command to C, and then execute it using @@ -1013,6 +1155,8 @@ directly. =item feature($name => $value) +[version 0.26] + With a single argument, returns true if the given feature is set. With two arguments, sets the given feature to the given boolean value. In this context, a "feature" is any optional functionality of an @@ -1033,20 +1177,50 @@ See also L. =item have_c_compiler() +[version 0.21] + Returns true if the current system seems to have a working C compiler. We currently determine this by attempting to compile a simple C source file and reporting whether the attempt was successful. =item install_destination($type) +[version 0.28] + Returns the directory in which items of type C<$type> (e.g. C, C, C, or anything else returned by the C method) will be installed during the C action. Any settings for C, C, and C are taken into account when determining the return value. +=item install_path() + +=item install_path($type) + +=item install_path($type => $path) + +[version 0.28] + +Set or retrieve paths for specific installable elements. This is +useful when you want to examine any explicit install paths specified +by the user on the command line, or if you want to set the install +path for a specific installable element based on another attribute +like C. + +With no argument, it returns a reference to a hash containing all +elements and their respective values. This hash should not be modified +directly; use the multi-argument below form to change values. + +The single argument form returns the value associated with the +element C<$type>. + +The multi-argument form allows you to set the paths for one or more +element types. The return value is undefined. + =item install_types() +[version 0.28] + Returns a list of installable types that this build knows about. These types each correspond to the name of a directory in F, and the list usually includes items such as C, C, C, @@ -1056,6 +1230,8 @@ exist. =item invoked_action() +[version 0.28] + This is the name of the original action invoked by the user. This value is set when the user invokes F, the F script, or programatically through the L method. It does not @@ -1070,6 +1246,8 @@ L above. =item notes($key => $value) +[version 0.20] + The C value allows you to store your own persistent information about the build, and to share that information among different entities involved in the build. See the example in the @@ -1089,56 +1267,17 @@ run again or the C action is run. =item orig_dir() +[version 0.28] + Returns a string containing the working directory that was in effect before the F script chdir()-ed into the C. This might be useful for writing wrapper tools that might need to chdir() back out. -=item rscan_dir($dir, $pattern) - -Uses C to traverse the directory C<$dir>, returning a -reference to an array of entries matching C<$pattern>. C<$pattern> -may either be a regular expression (using C or just a plain -string), or a reference to a subroutine that will return true for -wanted entries. If C<$pattern> is not given, all entries will be -returned. - -Examples: - - # All the *.pm files in lib/ - $m->rscan_dir('lib', qr/\.pm$/) - - # All the files in blib/ that aren't *.html files - $m->rscan_dir('blib', sub {-f $_ and not /\.html$/}); - - # All the files in t/ - $m->rscan_dir('t'); - -=item runtime_params() - -=item runtime_params($key) - -The C method stores the values passed on the command line -for valid properties (that is, any command line options for which -C returns a true value). The value on the command line may -override the default value for a property, as well as any value specified in a -call to C. This allows you to programmatically tell if C -or any execution of C<./Build> had command line options specified that -override valid properties. - -The C method is essentally a glorified read-only hash. With -no arguments, C returns the entire hash of properties -specified on the command line. With one argument, C -returns the value associated with the given key. - -The lifetime of the C data is for "a build" - that is, the -C hash is created when C is run (or when the -C method is called, if the Module::Build Perl API is being used instead -of called from a shell), and lasts until C is run again or the -C action is run. - =item os_type() +[version 0.04] + If you're subclassing Module::Build and some code needs to alter its behavior based on the current platform, you may only need to know whether you're running on Windows, Unix, MacOS, VMS, etc., and not the @@ -1150,6 +1289,8 @@ though. =item prepare_metadata() +[version 0.28] + This method is provided for authors to override to customize the fields of F. It is passed a YAML::Node node object which can be modified as desired and then returned. E.g. @@ -1166,6 +1307,8 @@ be modified as desired and then returned. E.g. =item prereq_failures() +[version 0.11] + Returns a data structure containing information about any failed prerequisites (of any of the types described above), or C if all prerequisites are met. @@ -1214,6 +1357,8 @@ Examples: =item prereq_report() +[version 0.28] + Returns a human-readable (table-form) string showing all prerequisites, the versions required, and the versions actually installed. This can be useful for reviewing the configuration of your @@ -1223,6 +1368,8 @@ C method. =item prompt($message, $default) +[version 0.12] + Asks the user a question and returns their response as a string. The first argument specifies the message to display to the user (for example, C<"Where do you keep your money?">). The second argument, @@ -1240,16 +1387,69 @@ This method may be called as a class or object method. =item recommends() +[version 0.21] + Returns a hash reference indicating the C prerequisites that were passed to the C method. =item requires() +[version 0.21] + Returns a hash reference indicating the C prerequisites that were passed to the C method. +=item rscan_dir($dir, $pattern) + +[version 0.28] + +Uses C to traverse the directory C<$dir>, returning a +reference to an array of entries matching C<$pattern>. C<$pattern> +may either be a regular expression (using C or just a plain +string), or a reference to a subroutine that will return true for +wanted entries. If C<$pattern> is not given, all entries will be +returned. + +Examples: + + # All the *.pm files in lib/ + $m->rscan_dir('lib', qr/\.pm$/) + + # All the files in blib/ that aren't *.html files + $m->rscan_dir('blib', sub {-f $_ and not /\.html$/}); + + # All the files in t/ + $m->rscan_dir('t'); + +=item runtime_params() + +=item runtime_params($key) + +[version 0.28] + +The C method stores the values passed on the command line +for valid properties (that is, any command line options for which +C returns a true value). The value on the command line may +override the default value for a property, as well as any value specified in a +call to C. This allows you to programmatically tell if C +or any execution of C<./Build> had command line options specified that +override valid properties. + +The C method is essentally a glorified read-only hash. With +no arguments, C returns the entire hash of properties +specified on the command line. With one argument, C +returns the value associated with the given key. + +The lifetime of the C data is for "a build" - that is, the +C hash is created when C is run (or when the +C method is called, if the Module::Build Perl API is being used instead +of called from a shell), and lasts until C is run again or the +C action is run. + =item script_files() +[version 0.18] + Returns a hash reference whose keys are the perl script files to be installed, if any. This corresponds to the C parameter to the C method. With an optional argument, this parameter may be set @@ -1264,6 +1464,8 @@ transition. =item up_to_date(\@source_files, \@derived_files) +[version 0.20] + This method can be used to compare a set of source files to a set of derived files. If any of the source files are newer than any of the derived files, it returns false. Additionally, if any of the derived @@ -1274,6 +1476,8 @@ names. =item y_n($message, $default) +[version 0.12] + Asks the user a yes/no question using C and returns true or false accordingly. The user will be asked the question repeatedly until they give an answer that looks like "yes" or "no". @@ -1329,6 +1533,8 @@ accessor methods for the following properties: =item create_makefile_pl() +=item create_packlist() + =item create_readme() =item debugger() diff --git a/lib/Module/Build/Base.pm b/lib/Module/Build/Base.pm index d8ec8ee..5cbddce 100644 --- a/lib/Module/Build/Base.pm +++ b/lib/Module/Build/Base.pm @@ -12,7 +12,6 @@ use File::Compare (); use Data::Dumper (); use IO::File (); use Text::ParseWords (); -use Carp (); use Module::Build::ModuleInfo; use Module::Build::Notes; @@ -315,39 +314,147 @@ sub cwd { return Cwd::cwd(); } +sub _quote_args { + # Returns a string that can become [part of] a command line with + # proper quoting so that the subprocess sees this same list of args. + my ($self, @args) = @_; + + my $return_args = ''; + my @quoted; + + for (@args) { + if ( /^[^\s*?!$<>;\\|'"\[\]\{\}]+$/ ) { + # Looks pretty safe + push @quoted, $_; + } else { + # XXX this will obviously have to improve - is there already a + # core module lying around that does proper quoting? + s/"/"'"'"/g; + push @quoted, qq("$_"); + } + } + + return join " ", @quoted; +} + +sub _backticks { + # Tries to avoid using true backticks, when possible, so that we + # don't have to worry about shell args. + + my ($self, @cmd) = @_; + if ($self->have_multiarg_pipeopen) { + local *FH; + open FH, "-|", @cmd or die "Can't run @cmd: $!"; + return wantarray ? : join '', ; + } else { + my $cmd = $self->_quote_args(@cmd); + return `$cmd`; + } +} + +sub have_multiarg_pipeopen { $] >= 5.008 } + +# Determine whether a given binary is the same as the perl +# (configuration) that started this process. sub _perl_is_same { my ($self, $perl) = @_; - return `$perl -MConfig=myconfig -e print -e myconfig` eq Config->myconfig; + + my @cmd = ($perl); + + # When run from the perl core, @INC will include the directories + # where perl is yet to be installed. We need to reference the + # absolute path within the source distribution where it can find + # it's Config.pm This also prevents us from picking up a Config.pm + # from a different configuration that happens to be already + # installed in @INC. + if ($ENV{PERL_CORE}) { + push @cmd, '-I' . File::Spec->catdir(File::Basename::dirname($perl), 'lib'); + } + + push @cmd, qw(-MConfig=myconfig -e print -e myconfig); + return $self->_backticks(@cmd) eq Config->myconfig; } +# Returns the absolute path of the perl interperter used to invoke +# this process. The path is derived from $^X or $Config{perlpath}. On +# some platforms $^X contains the complete absolute path of the +# interpreter, on other it may contain a relative path, or simply +# 'perl'. This can also vary depending on whether a path was supplied +# when perl was invoked. Additionally, the value in $^X may omit the +# executable extension on platforms that use one. It's a fatal error +# if the interpreter can't be found because it can result in undefined +# behavior by routines that depend on it (generating errors or +# invoking the wrong perl. sub find_perl_interpreter { - return $^X if File::Spec->file_name_is_absolute($^X); my $proto = shift; - my $c = ref($proto) ? $proto->config : \%Config::Config; - my $exe = $c->{exe_ext}; + my $c = ref($proto) ? $proto->config : \%Config::Config; - my $thisperl = $^X; - if ($proto->os_type eq 'VMS') { - # VMS might have a file version at the end - $thisperl .= $exe unless $thisperl =~ m/$exe(;\d+)?$/i; - } elsif (defined $exe) { - $thisperl .= $exe unless $thisperl =~ m/$exe$/i; - } + my $perl = $^X; + my $perl_basename = File::Basename::basename($perl); + + my @potential_perls; + + # Try 1, Check $^X for absolute path + push( @potential_perls, $perl ) + if File::Spec->file_name_is_absolute($perl); - my $uninstperl; + # Try 2, Check $^X for a valid relative path + my $abs_perl = File::Spec->rel2abs($perl); + push( @potential_perls, $abs_perl ); + + # Try 3, Last ditch effort: These two option use hackery to try to locate + # a suitable perl. The hack varies depending on whether we are running + # from an installed perl or an uninstalled perl in the perl source dist. if ($ENV{PERL_CORE}) { + + # Try 3.A, If we are in a perl source tree, running an uninstalled + # perl, we can keep moving up the directory tree until we find our + # binary. We wouldn't do this under any other circumstances. + # CBuilder is also in the core, so it should be available here require ExtUtils::CBuilder; - $uninstperl = File::Spec->catfile(ExtUtils::CBuilder::->perl_src, $thisperl); + my $perl_src = ExtUtils::CBuilder->perl_src; + if ( defined($perl_src) && length($perl_src) ) { + my $uninstperl = + File::Spec->rel2abs(File::Spec->catfile( $perl_src, $perl_basename )); + push( @potential_perls, $uninstperl ); + } + + } else { + + # Try 3.B, First look in $Config{perlpath}, then search the users + # PATH. We do not want to do either if we are running from an + # uninstalled perl in a perl source tree. + + push( @potential_perls, $c->{perlpath} ); + + push( @potential_perls, + map File::Spec->catfile($_, $perl_basename), File::Spec->path() ); } - foreach my $perl ( $uninstperl || (), - $c->{perlpath}, - map File::Spec->catfile($_, $thisperl), File::Spec->path() - ) { - return $perl if -f $perl and $proto->_perl_is_same($perl); + # Now that we've enumerated the potential perls, it's time to test + # them to see if any of them match our configuration, returning the + # absolute path of the first successful match. + my $exe = $c->{exe_ext}; + foreach my $thisperl ( @potential_perls ) { + + if ($proto->os_type eq 'VMS') { + # VMS might have a file version at the end + $thisperl .= $exe unless $thisperl =~ m/$exe(;\d+)?$/i; + } elsif (defined $exe) { + $thisperl .= $exe unless $thisperl =~ m/$exe$/i; + } + + if ( -f $thisperl && $proto->_perl_is_same($thisperl) ) { + return $thisperl; + } } - return; + + # We've tried all alternatives, and didn't find a perl that matches + # our configuration. Throw an exception, and list alternatives we tried. + my @paths = map File::Basename::dirname($_), @potential_perls; + die "Can't locate the perl binary used to run this script " . + "in (@paths)\n"; } sub _is_interactive { @@ -620,6 +727,7 @@ __PACKAGE__->add_property(installdirs => 'site'); __PACKAGE__->add_property(metafile => 'META.yml'); __PACKAGE__->add_property(recurse_into => []); __PACKAGE__->add_property(use_rcfile => 1); +__PACKAGE__->add_property(create_packlist => 1); { my $Is_ActivePerl = eval {require ActivePerl::DocTools}; @@ -1159,7 +1267,7 @@ sub _added_to_INC { my $perl = ref($self) ? $self->perl : $self->find_perl_interpreter; - my @inc = `$perl -le "print for \@INC"`; + my @inc = $self->_backticks($perl, '-le', 'print for @INC'); chomp @inc; return @default_inc = @inc; @@ -1235,8 +1343,7 @@ close(*DATA) unless eof(*DATA); # ensure no open handles to this script use $build_package; # Some platforms have problems setting \$^X in shebang contexts, fix it up here -\$^X = Module::Build->find_perl_interpreter - unless File::Spec->file_name_is_absolute(\$^X); +\$^X = Module::Build->find_perl_interpreter; if (-e 'Build.PL' and not $build_package->up_to_date('Build.PL', \$progname)) { warn "Warning: Build.PL has been altered. You may need to run 'perl Build.PL' again.\\n"; @@ -2015,7 +2122,7 @@ sub process_script_files { foreach my $file (keys %$files) { my $result = $self->copy_if_modified($file, $script_dir, 'flatten') or next; - $self->fix_shebang_line($result); + $self->fix_shebang_line($result) unless $self->os_type eq 'VMS'; $self->make_executable($result); } } @@ -2102,6 +2209,7 @@ sub _find_file_by_type { sub localize_file_path { my ($self, $path) = @_; + $path =~ s/\.\z// if $self->os_type eq 'VMS'; return File::Spec->catfile( split m{/}, $path ); } @@ -2609,12 +2717,19 @@ sub ACTION_dist { sub ACTION_distcheck { my ($self) = @_; - + require ExtUtils::Manifest; local $^W; # ExtUtils::Manifest is not warnings clean. my ($missing, $extra) = ExtUtils::Manifest::fullcheck(); - die "MANIFEST appears to be out of sync with the distribution\n" - if @$missing || @$extra; + + return unless @$missing || @$extra; + + my $msg = "MANIFEST appears to be out of sync with the distribution\n"; + if ( $self->invoked_action eq 'distcheck' ) { + die $msg; + } else { + warn $msg; + } } sub _add_to_manifest { @@ -2847,6 +2962,7 @@ sub _write_default_maniskip { # Avoid Module::Build generated and utility files. \bBuild$ +\bBuild.bat$ \b_build # Avoid Devel::Cover generated files @@ -2969,44 +3085,6 @@ sub _hash_merge { } } -sub _yaml_quote_string { - # XXX doesn't handle embedded newlines - - my ($self, $string) = @_; - if ($string !~ /\"/) { - $string =~ s{\\}{\\\\}g; - return qq{"$string"}; - } else { - $string =~ s{([\\'])}{\\$1}g; - return qq{'$string'}; - } -} - -sub _write_minimal_metadata { - my $self = shift; - my $p = $self->{properties}; - - my $file = $self->metafile; - my $fh = IO::File->new("> $file") - or die "Can't open $file: $!"; - - my @author = map $self->_yaml_quote_string($_), @{$self->dist_author}; - my $abstract = $self->_yaml_quote_string($self->dist_abstract); - - # XXX Add the meta_add & meta_merge stuff - - print $fh <<"EOF"; ---- #YAML:1.0 -name: $p->{dist_name} -version: $p->{dist_version} -author: -@{[ join "\n", map " - $_", @author ]} -abstract: $abstract -license: $p->{license} -generated_by: Module::Build version $Module::Build::VERSION, without YAML.pm -EOF -} - sub ACTION_distmeta { my ($self) = @_; @@ -3061,26 +3139,31 @@ sub write_metafile { $self->{wrote_metadata} = $yaml_sub->($metafile, $node ); } else { - $self->log_warn(<_write_minimal_metadata; + require Module::Build::YAML; + my (%node, @order_keys); + $self->prepare_metadata(\%node, \@order_keys); + $node{_order} = \@order_keys; + &Module::Build::YAML::DumpFile($metafile, \%node); + $self->{wrote_metadata} = 1; } $self->_add_to_manifest('MANIFEST', $metafile); } sub prepare_metadata { - my ($self, $node) = @_; + my ($self, $node, $keys) = @_; my $p = $self->{properties}; + # 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_//; - $node->{$name} = $self->$_(); + $add_node->($name, $self->$_()); die "ERROR: Missing required field '$_' for META.yml\n" unless defined($node->{$name}) && length($node->{$name}); } @@ -3091,10 +3174,14 @@ sub prepare_metadata { } foreach ( @{$self->prereq_action_types} ) { - $node->{$_} = $p->{$_} if exists $p->{$_} and keys %{ $p->{$_} }; + if (exists $p->{$_} and keys %{ $p->{$_} }) { + $add_node->($_, $p->{$_}); + } } - $node->{dynamic_config} = $p->{dynamic_config} if exists $p->{dynamic_config}; + if (exists $p->{dynamic_config}) { + $add_node->('dynamic_config', $p->{dynamic_config}); + } my $pkgs = eval { $self->find_dist_packages }; if ($@) { $self->log_warn("WARNING: Possible missing or corrupt 'MANIFEST' file.\n" . @@ -3103,18 +3190,19 @@ sub prepare_metadata { $node->{provides} = $pkgs if %$pkgs; } ; - $node->{no_index} = $p->{no_index} if exists $p->{no_index}; - - $node->{generated_by} = "Module::Build version $Module::Build::VERSION"; + if (exists $p->{no_index}) { + $add_node->('no_index', $p->{no_index}); + } - $node->{'meta-spec'} = { - version => '1.2', - url => 'http://module-build.sourceforge.net/META-spec-v1.2.html', - }; + $add_node->('generated_by', "Module::Build version $Module::Build::VERSION"); + $add_node->('meta-spec', + {version => '1.2', + url => 'http://module-build.sourceforge.net/META-spec-v1.2.html', + }); while (my($k, $v) = each %{$self->meta_add}) { - $node->{$k} = $v; + $add_node->($k, $v); } while (my($k, $v) = each %{$self->meta_merge}) { @@ -3436,7 +3524,7 @@ sub install_map { ) if @skipping; # Write the packlist into the same place as ExtUtils::MakeMaker. - if (my $module_name = $self->module_name) { + if ($self->create_packlist and my $module_name = $self->module_name) { my $archdir = $self->install_destination('arch'); my @ext = split /::/, $module_name; $map{write} = File::Spec->catdir($archdir, 'auto', @ext, '.packlist'); @@ -3593,17 +3681,17 @@ sub compile_xs { if (defined $lib_typemap and -e $lib_typemap) { push @typemaps, 'typemap'; } - my $typemaps = join ' ', map qq{-typemap "$_"}, @typemaps; + @typemaps = map {+'-typemap', $_} @typemaps; my $cf = $self->config; my $perl = $self->{properties}{perl}; - my $command = (qq{$perl "-I$cf->{installarchlib}" "-I$cf->{installprivlib}" "$xsubpp" -noprototypes } . - qq{$typemaps "$file"}); + my @command = ($perl, "-I$cf->{installarchlib}", "-I$cf->{installprivlib}", $xsubpp, '-noprototypes', + @typemaps, $file); - $self->log_info("$command\n"); + $self->log_info("@command\n"); my $fh = IO::File->new("> $args{outfile}") or die "Couldn't write $args{outfile}: $!"; - print $fh `$command`; + print {$fh} $self->_backticks(@command); close $fh; } } @@ -3632,6 +3720,7 @@ sub run_perl_command { # this before documenting. my ($self, $args) = @_; $args = [ $self->split_like_shell($args) ] unless ref($args); + $args = [ split(/\s+/, $self->_quote_args($args)) ] if $self->os_type eq 'VMS'; my $perl = ref($self) ? $self->perl : $self->find_perl_interpreter; # Make sure our local additions to @INC are propagated to the subprocess diff --git a/lib/Module/Build/Changes b/lib/Module/Build/Changes index 1edb670..4d7690b 100644 --- a/lib/Module/Build/Changes +++ b/lib/Module/Build/Changes @@ -1,5 +1,29 @@ Revision history for Perl extension Module::Build. +0.27_11 Tue Mar 28 22:50:50 CST 2006 + + - Added the create_packlist property, default true, which controls + whether packlist files will be written during installation. This + was already part of Module::Build 0.2609, but for some reason we've + forgotten it in the 0.27_xx series. [Spotted by Steve Kirkup] + + - Document the versions of Module::Build where each feature, action, + constructor argument, and method was first publicly documented. + + - More fixes for find_perl_interpreter() to work with BSD flavored + UNIX: Ensure we always return absolute paths; throw an exception + upon failure to find correct interperter; document everything. + + - We now include our own YAML.pm work-alike that we can use when the + real YAML isn't installed. We might soon even start using it when + YAML is installed, because the YAML API and dependency chain have + been changing in unfavorable ways lately. [Stephen Adkins] + + - Fixed some shell-argument-quoting issues on VMS. In the process, + we have added some support for avoiding tripping over + shell-argument-quoting issues on other platforms too. [Initial + patch by Craig A. Berry] + 0.27_09 Sat Mar 11 22:48:54 EST 2006 - Fixed find_perl_interpreter() so we can find the perl executable diff --git a/lib/Module/Build/Platform/MacOS.pm b/lib/Module/Build/Platform/MacOS.pm index 5452ff7..78c3ad8 100644 --- a/lib/Module/Build/Platform/MacOS.pm +++ b/lib/Module/Build/Platform/MacOS.pm @@ -6,6 +6,8 @@ use base qw(Module::Build::Base); use ExtUtils::Install; +sub have_multiarg_pipeopen { 0 } + sub new { my $class = shift; my $self = $class->SUPER::new(@_); diff --git a/lib/Module/Build/Platform/VMS.pm b/lib/Module/Build/Platform/VMS.pm index b0facab..01a0117 100644 --- a/lib/Module/Build/Platform/VMS.pm +++ b/lib/Module/Build/Platform/VMS.pm @@ -119,6 +119,20 @@ sub _prefixify { } +sub _quote_args { + # Returns a string that can become [part of] a command line with + # proper quoting so that the subprocess sees this same list of args. + my ($self, @args) = @_; + + my $return_args = ''; + for (@args) { + $return_args .= q( ").$_.q(") if !/^\"/ && length($_) > 0; + } + return $return_args; +} + +sub have_multiarg_pipeopen { 0 } + =back =head1 AUTHOR diff --git a/lib/Module/Build/Platform/Windows.pm b/lib/Module/Build/Platform/Windows.pm index 495fd9b..1d3bc9b 100644 --- a/lib/Module/Build/Platform/Windows.pm +++ b/lib/Module/Build/Platform/Windows.pm @@ -17,6 +17,8 @@ sub manpage_separator { return '.'; } +sub have_multiarg_pipeopen { 0 } + sub ACTION_realclean { my ($self) = @_; diff --git a/lib/Module/Build/Platform/os2.pm b/lib/Module/Build/Platform/os2.pm index 0a1ca38..d60202f 100644 --- a/lib/Module/Build/Platform/os2.pm +++ b/lib/Module/Build/Platform/os2.pm @@ -8,6 +8,8 @@ use vars qw(@ISA); sub manpage_separator { '.' } +sub have_multiarg_pipeopen { 0 } + 1; __END__ diff --git a/lib/Module/Build/YAML.pm b/lib/Module/Build/YAML.pm new file mode 100644 index 0000000..ef7eccf --- /dev/null +++ b/lib/Module/Build/YAML.pm @@ -0,0 +1,162 @@ +package Module::Build::YAML; + +use strict; +use warnings; + +our $VERSION = "0.50"; +our @EXPORT = (); +our @EXPORT_OK = qw(Dump Load DumpFile LoadFile); + +sub new { + my $this = shift; + my $class = ref($this) || $this; + my $self = {}; + bless $self, $class; + return($self); +} + +sub Dump { + shift if ($_[0] eq __PACKAGE__ || ref($_[0]) eq __PACKAGE__); + my $yaml = ""; + foreach my $item (@_) { + $yaml .= "---\n"; + $yaml .= &_yaml_chunk("", $item); + } + return $yaml; +} + +sub Load { + shift if ($_[0] eq __PACKAGE__ || ref($_[0]) eq __PACKAGE__); + die "not yet implemented"; +} + +# 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: $!"; + 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: $!"; + 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 { + # XXX doesn't handle embedded newlines + my ($value) = @_; + # undefs and empty strings will become empty strings + if (! defined $value || $value eq "") { + return('""'); + } + # allow simple scalars (without embedded quote chars) to be unquoted + elsif ($value !~ /["'\\]/) { + return($value); + } + # strings without double-quotes get double-quoted + elsif ($value !~ /\"/) { + $value =~ s{\\}{\\\\}g; + return qq{"$value"}; + } + # other strings get single-quoted + else { + $value =~ s{([\\'])}{\\$1}g; + return qq{'$value'}; + } +} + +1; + +__END__ + +=head1 NAME + +Module::Build::YAML - Provides just enough YAML support so that Module::Build works even if YAML.pm is not installed + +=head1 SYNOPSIS + + use Module::Build::YAML; + + ... + +=head1 DESCRIPTION + +Provides just enough YAML support so that Module::Build works even if YAML.pm is not installed. + +Currently, this amounts to the ability to write META.yml files when "perl Build distmeta" +is executed via the Dump() and DumpFile() functions/methods. + +=head1 AUTHOR + +Stephen Adkins + +=head1 COPYRIGHT + +Copyright (c) 2006. Stephen Adkins. All rights reserved. + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +See L + +=cut + diff --git a/lib/Module/Build/t/bundled/Tie/CPHash.pm b/lib/Module/Build/t/bundled/Tie/CPHash.pm index 9695b2c..33c140e 100644 --- a/lib/Module/Build/t/bundled/Tie/CPHash.pm +++ b/lib/Module/Build/t/bundled/Tie/CPHash.pm @@ -3,9 +3,9 @@ package Tie::CPHash; # # Copyright 1997 Christopher J. Madsen # -# Author: Christopher J. Madsen +# Author: Christopher J. Madsen # Created: 08 Nov 1997 -# Version: 1.001 (25-Oct-1998) +# $Revision: 1.2 $ $Date: 2006/03/21 13:27:29 $ # # This program is free software; you can redistribute it and/or modify # it under the same terms as Perl itself. @@ -27,11 +27,7 @@ use vars qw(@ISA $VERSION); #===================================================================== # Package Global Variables: -BEGIN -{ - # Convert RCS revision number to d.ddd format: - $VERSION = sprintf('%d.%03d', '1.001 ' =~ /(\d+)\.(\d+)/); -} # end BEGIN +$VERSION = '1.02'; #===================================================================== # Tied Methods: @@ -85,6 +81,15 @@ sub NEXTKEY } # end NEXTKEY #--------------------------------------------------------------------- +# SCALAR this +# Return bucket usage information for the hash (0 if empty). + +sub SCALAR +{ + scalar %{$_[0]}; +} # end SCALAR + +#--------------------------------------------------------------------- # EXISTS this, key # Verify that *key* exists with the tied hash *this*. @@ -147,8 +152,8 @@ Tie::CPHash - Case preserving but case insensitive hash table =head1 DESCRIPTION -The B provides a hash table that is case preserving but -case insensitive. This means that +The B module provides a hash table that is case +preserving but case insensitive. This means that $cphash{KEY} $cphash{key} $cphash{Key} $cphash{keY} @@ -180,7 +185,7 @@ less overhead than B. =head1 AUTHOR -Christopher J. Madsen EFE +Christopher J. Madsen EFE =cut diff --git a/lib/Module/Build/t/lib/DistGen.pm b/lib/Module/Build/t/lib/DistGen.pm index 835edde..5341f44 100644 --- a/lib/Module/Build/t/lib/DistGen.pm +++ b/lib/Module/Build/t/lib/DistGen.pm @@ -16,6 +16,14 @@ use File::Spec (); use IO::File (); use Tie::CPHash; +BEGIN { + if( $^O eq 'VMS' ) { + # For things like vmsify() + require VMS::Filespec; + VMS::Filespec->import; + } +} + sub new { my $package = shift; my %options = @_; @@ -309,7 +317,11 @@ sub clean { File::Find::finddepth( sub { my $name = File::Spec->canonpath( $File::Find::name ); - $name =~ s/\.\z// if $^O eq 'VMS'; + if ($^O eq 'VMS') { + $name =~ s/\.\z//; + $name = vmspath($name) if -d $name; + $name = File::Spec->rel2abs($name) if $name eq File::Spec->curdir(); + } if ( not exists $names{$name} ) { print "Removing '$name'\n" if $VERBOSE; @@ -322,7 +334,7 @@ sub clean { sub remove { my $self = shift; - File::Path::rmtree( $self->dirname ); + File::Path::rmtree( File::Spec->canonpath($self->dirname) ); } sub revert { diff --git a/lib/Module/Build/t/mbyaml.t b/lib/Module/Build/t/mbyaml.t new file mode 100644 index 0000000..9bae6a2 --- /dev/null +++ b/lib/Module/Build/t/mbyaml.t @@ -0,0 +1,149 @@ +#!/usr/local/bin/perl -w + +use Test::More qw(no_plan); +use lib "lib"; +use lib "../lib"; + +my ($dir); +$dir = "."; +$dir = "t" if (-d "t"); + +{ + use_ok("Module::Build::YAML"); + my ($expected, $got, $var); + $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" ' + ], + '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 = <' +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"); + + $expected = <' +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"); + + $var = [ + "e", + 2.71828, + [ "pi", "is", 3.1416 ], + { fun => "under_sun", 6 => undef, "more", undef }, + ]; + $expected = <new(); + $got = $y->Dump($var); + is($got, $expected, "Dump(): single array of various (OO)"); +} + + diff --git a/lib/Module/Build/t/metadata.t b/lib/Module/Build/t/metadata.t index 0e4fe39..939e665 100644 --- a/lib/Module/Build/t/metadata.t +++ b/lib/Module/Build/t/metadata.t @@ -2,7 +2,7 @@ use strict; use lib $ENV{PERL_CORE} ? '../lib/Module/Build/t/lib' : 't/lib'; -use MBTest tests => 46; +use MBTest tests => 43; use Cwd (); my $cwd = Cwd::cwd; @@ -556,15 +556,6 @@ $dist->regen( clean => 1 ); $mb = new_build(); is_deeply($mb->find_dist_packages, {}); - -{ - # Put our YAML escaper through a few tests. This isn't part of the M::B API. - my $yq = sub {Module::Build->_yaml_quote_string(@_)}; - like $yq->(''), qr{^ (['"]) \1 $}x; - is $yq->('Foo "bar" baz'), q{'Foo "bar" baz'}; - is $yq->("Foo 'bar' baz"), q{"Foo 'bar' baz"}; -} - ############################################################ # cleanup chdir( $cwd ) or die "Can't chdir to '$cwd': $!"; -- 1.8.3.1