6 use vars qw( $VERSION $VERBOSE @EXPORT_OK);
15 use File::Basename ();
30 # For things like vmsify()
31 require VMS::Filespec;
32 VMS::Filespec->import;
37 if (eval { local $SIG{__DIE__}; require VMS::Feature; }) {
38 $unix_rpt = VMS::Feature::current("filename_unix_report");
39 $vms_efs_case = VMS::Feature::current("efs_case_preserve");
41 my $env_unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || '';
42 $unix_rpt = $env_unix_rpt =~ /^[ET1]/i;
43 my $efs_case = $ENV{'DECC$EFS_CASE_PRESERVE'} || '';
44 $vms_efs_case = $efs_case =~ /^[ET1]/i;
46 $vms_mode = 0 if $unix_rpt;
47 $vms_lower_case = 0 if $vms_efs_case;
52 *{import} = \&Exporter::import;
61 my ($space) = $string =~ m/^(\s+)/;
62 $string =~ s/^$space//gm;
68 # OS/2 has "current directory per disk", undeletable;
69 # doing chdir() to another disk won't change cur-dir of initial disk...
70 chdir('/') if $^O eq 'os2';
74 ########################################################################
76 END { chdir_all(MBTest->original_cwd); }
79 my $self = bless {}, shift;
87 $options{name} ||= 'Simple';
88 $options{dir} = File::Spec->rel2abs(
89 defined $options{dir} ? $options{dir} : MBTest->tmpdir
100 tie %{$self->{filedata}}, 'Tie::CPHash';
102 tie %{$self->{pending}{change}}, 'Tie::CPHash';
104 # start with a fresh, empty directory
105 if ( -d $self->dirname ) {
106 warn "Warning: Removing existing directory '@{[$self->dirname]}'\n";
107 File::Path::rmtree( $self->dirname );
109 File::Path::mkpath( $self->dirname );
111 $self->_gen_default_filedata();
118 $self->chdir_original if($self->did_chdir);
119 File::Path::rmtree( $self->dirname );
124 my ($self, $file) = @_;
125 if ( defined $file ) {
126 delete $self->{filedata}{$file};
127 delete $self->{pending}{$_}{$file} for qw/change remove/;
130 delete $self->{filedata}{$_} for keys %{ $self->{filedata} };
131 for my $pend ( qw/change remove/ ) {
132 delete $self->{pending}{$pend}{$_} for keys %{ $self->{pending}{$pend} };
135 $self->_gen_default_filedata;
138 sub _gen_default_filedata {
141 # TODO maybe a public method like this (but with a better name?)
142 my $add_unless = sub {
144 my ($member, $data) = @_;
145 $self->add_file($member, $data) unless($self->{filedata}{$member});
148 if ( ! $self->{inc} ) {
149 $self->$add_unless('Build.PL', undent(<<" ---"));
153 my \$builder = Module::Build->new(
154 module_name => '$self->{name}',
158 \$builder->create_build_script();
162 $self->$add_unless('Build.PL', undent(<<" ---"));
164 use inc::latest 'Module::Build';
166 my \$builder = Module::Build->new(
167 module_name => '$self->{name}',
171 \$builder->create_build_script();
175 my $module_filename =
176 join( '/', ('lib', split(/::/, $self->{name})) ) . '.pm';
178 unless ( $self->{xs} ) {
179 $self->$add_unless($module_filename, undent(<<" ---"));
180 package $self->{name};
182 use vars qw( \$VERSION );
194 $self->{name} - Perl extension for blah blah blah
198 Stub documentation for $self->{name}.
202 A. U. Thor, a.u.thor\@a.galaxy.far.far.away
207 $self->$add_unless('t/basic.t', undent(<<" ---"));
208 use Test::More tests => 1;
217 $self->$add_unless($module_filename, undent(<<" ---"));
218 package $self->{name};
225 \@ISA = qw(Exporter DynaLoader);
226 \@EXPORT_OK = qw( okay );
228 bootstrap $self->{name} \$VERSION;
236 $self->{name} - Perl extension for blah blah blah
240 Stub documentation for $self->{name}.
244 A. U. Thor, a.u.thor\@a.galaxy.far.far.away
250 join( '/', ('lib', split(/::/, $self->{name})) ) . '.xs';
251 $self->$add_unless($xs_filename, undent(<<" ---"));
256 MODULE = $self->{name} PACKAGE = $self->{name}
261 RETVAL = newSVpv( "ok", 0 );
280 # 5.6 is missing const char * in its typemap
281 $self->$add_unless('typemap', undent(<<" ---"));
285 $self->$add_unless('t/basic.t', undent(<<" ---"));
286 use Test::More tests => 2;
292 ok( $self->{name}::okay() eq 'ok' );
299 my $manifest = shift;
301 my $fh = IO::File->new( ">$manifest" ) or do {
302 die "Can't write '$manifest'\n";
305 my @files = ( 'MANIFEST', keys %{$self->{filedata}} );
306 my $data = join( "\n", sort @files ) . "\n";
310 $self->{filedata}{MANIFEST} = $data;
311 $self->{pending}{change}{MANIFEST} = 1;
314 sub name { shift()->{name} }
318 my $dist = $self->{distdir} || join( '-', split( /::/, $self->{name} ) );
319 return File::Spec->catdir( $self->{dir}, $dist );
324 my $filename = shift;
325 return File::Spec->catfile( split( /\//, $filename ) );
332 my $dist_dirname = $self->dirname;
334 if ( $opts{clean} ) {
335 $self->clean() if -d $dist_dirname;
337 # TODO: This might leave dangling directories; e.g. if the removed file
338 # is 'lib/Simple/Simon.pm', the directory 'lib/Simple' will be left
339 # even if there are no files left in it. However, clean() will remove it.
340 my @files = keys %{$self->{pending}{remove}};
341 foreach my $file ( @files ) {
342 my $real_filename = $self->_real_filename( $file );
343 my $fullname = File::Spec->catfile( $dist_dirname, $real_filename );
344 if ( -e $fullname ) {
345 1 while unlink( $fullname );
347 print "Unlinking pending file '$file'\n" if $VERBOSE;
348 delete( $self->{pending}{remove}{$file} );
352 foreach my $file ( keys( %{$self->{filedata}} ) ) {
353 my $real_filename = $self->_real_filename( $file );
354 my $fullname = File::Spec->catfile( $dist_dirname, $real_filename );
356 if ( ! -e $fullname ||
357 ( -e $fullname && $self->{pending}{change}{$file} ) ) {
359 print "Changed file '$file'.\n" if $VERBOSE;
361 my $dirname = File::Basename::dirname( $fullname );
362 unless ( -d $dirname ) {
363 File::Path::mkpath( $dirname ) or do {
364 die "Can't create '$dirname'\n";
368 if ( -e $fullname ) {
369 1 while unlink( $fullname );
372 my $fh = IO::File->new(">$fullname") or do {
373 die "Can't write '$fullname'\n";
375 print $fh $self->{filedata}{$file};
379 delete( $self->{pending}{change}{$file} );
382 my $manifest = File::Spec->catfile( $dist_dirname, 'MANIFEST' );
383 unless ( $self->{no_manifest} ) {
384 if ( -e $manifest ) {
385 1 while unlink( $manifest );
387 $self->_gen_manifest( $manifest );
395 my $here = Cwd::abs_path();
396 my $there = File::Spec->rel2abs( $self->dirname() );
399 chdir( $there ) or die "Can't change directory to '$there'\n";
401 die "Distribution not found in '$there'\n";
405 tie %names, 'Tie::CPHash';
406 foreach my $file ( keys %{$self->{filedata}} ) {
407 my $filename = $self->_real_filename( $file );
408 $filename = lc($filename) if $vms_lower_case;
409 my $dirname = File::Basename::dirname( $filename );
411 $names{$filename} = 0;
413 print "Splitting '$dirname'\n" if $VERBOSE;
414 my @dirs = File::Spec->splitdir( $dirname );
416 my $dir = ( scalar(@dirs) == 1
418 : File::Spec->catdir( @dirs ) );
420 print "Setting directory name '$dir' in \%names\n" if $VERBOSE;
427 File::Find::finddepth( sub {
428 my $name = File::Spec->canonpath( $File::Find::name );
433 $name = vmspath($name) if -d $name;
437 $name = File::Spec->rel2abs($name) if $name eq File::Spec->curdir();
440 if ( not exists $names{$name} ) {
441 print "Removing '$name'\n" if $VERBOSE;
442 File::Path::rmtree( $_ );
444 }, ($^O eq 'VMS' ? './' : File::Spec->curdir) );
452 $self->change_file( @_ );
458 unless ( exists $self->{filedata}{$file} ) {
459 warn "Can't remove '$file': It does not exist.\n" if $VERBOSE;
461 delete( $self->{filedata}{$file} );
462 $self->{pending}{remove}{$file} = 1;
466 sub change_build_pl {
467 my ($self, @opts) = @_;
469 my $opts = ref $opts[0] eq 'HASH' ? $opts[0] : { @opts };
471 local $Data::Dumper::Terse = 1;
472 (my $args = Dumper($opts)) =~ s/^\s*\{|\}\s*$//g;
474 $self->change_file( 'Build.PL', undent(<<" ---") );
478 my \$b = Module::Build->new(
479 # Some CPANPLUS::Dist::Build versions need to allow mismatches
480 # On logic: thanks to Module::Install, CPAN.pm must set both keys, but
481 # CPANPLUS sets only the one
482 allow_mb_mismatch => (
483 \$ENV{PERL5_CPANPLUS_IS_RUNNING} && ! \$ENV{PERL5_CPAN_IS_RUNNING} ? 1 : 0
487 \$b->create_build_script();
496 $self->{filedata}{$file} = $data;
497 $self->{pending}{change}{$file} = 1;
504 exists($self->{filedata}{$file}) or croak("no such entry: '$file'");
505 return $self->{filedata}{$file};
510 $self->{original_dir} ||= Cwd::cwd; # only once!
511 my $dir = $self->dirname;
512 chdir($dir) or die "Can't chdir to '$dir': $!";
515 ########################################################################
517 sub did_chdir { exists shift()->{original_dir} }
519 ########################################################################
524 my $dir = delete $self->{original_dir};
525 chdir_all($dir) or die "Can't chdir to '$dir': $!";
528 ########################################################################
530 sub new_from_context {
531 my ($self, @args) = @_;
532 require Module::Build;
533 return Module::Build->new_from_context( quiet => 1, @args );
537 my ($self, @args) = @_;
538 require Module::Build;
539 return Module::Build->run_perl_script('Build.PL', [], [@args])
543 my ($self, @args) = @_;
544 require Module::Build;
545 my $build_script = $^O eq 'VMS' ? 'Build.com' : 'Build';
546 return Module::Build->run_perl_script($build_script, [], [@args])
556 DistGen - Creates simple distributions for testing.
562 # create distribution and prepare to test
563 my $dist = DistGen->new(name => 'Foo::Bar');
566 # change distribution files
567 $dist->add_file('t/some_test.t', $contents);
568 $dist->change_file('MANIFEST.SKIP', $new_contents);
569 $dist->remove_file('t/some_test.t');
572 # undo changes and clean up extraneous files
576 # exercise the command-line interface
577 $dist->run_build_pl();
578 $dist->run_build('test');
580 # start over as a new distribution
581 $dist->reset( name => 'Foo::Bar', xs => 1 );
586 A DistGen object manages a set of files in a distribution directory.
588 The C<new()> constructor initializes the object and creates an empty
589 directory for the distribution. It does not create files or chdir into
590 the directory. The C<reset()> method re-initializes the object in a
591 new directory with new parameters. It also does not create files or change
592 the current directory.
594 Some methods only define the target state of the distribution. They do B<not>
595 make any changes to the filesystem:
603 Other methods then change the filesystem to match the target state of
610 Other methods are provided for a convenience during testing. The
611 most important is the one to enter the distribution directory:
615 Additional methods portably encapsulate running Build.PL and Build:
626 Create a new object and an empty directory to hold the distribution's files.
627 If no C<dir> option is provided, it defaults to MBTest->tmpdir, which sets
628 a different temp directory for Perl core testing and CPAN testing.
630 The C<new> method does not write any files -- see L</regen()> below.
632 my $dist = DistGen->new(
634 dir => MBTest->tmpdir,
639 The parameters are as follows.
645 The name of the module this distribution represents. The default is
646 'Simple'. This should be a "Foo::Bar" (module) name, not a "Foo-Bar"
651 The (parent) directory in which to create the distribution directory. The
652 distribution will be created under this according to C<distdir> parameter
653 below. Defaults to a temporary directory.
655 $dist = DistGen->new( dir => '/tmp/MB-test' );
658 # distribution files have been created in /tmp/MB-test/Simple
662 The name of the distribution directory to create. Defaults to the dist form of
663 C<name>, e.g. 'Foo-Bar' if C<name> is 'Foo::Bar'.
667 If true, generates an XS based module.
671 If true, C<regen()> will not create a MANIFEST file.
675 The following files are added as part of the default distribution:
678 lib/Simple.pm # based on name parameter
681 If an XS module is generated, Simple.pm and basic.t are different and
682 the following files are also added:
685 lib/Simple.xs # based on name parameter
689 The C<reset> method re-initializes the object as if it were generated
690 from a fresh call to C<new>. It takes the same optional parameters as C<new>.
692 $dist->reset( name => 'Foo::Bar', xs => 0 );
694 =head2 Adding and editing files
696 Note that C<$filename> should always be specified with unix-style paths,
697 and are relative to the distribution root directory, e.g. C<lib/Module.pm>.
699 No changes are made to the filesystem until the distribution is regenerated.
703 Add a $filename containing $content to the distribution.
705 $dist->add_file( $filename, $content );
709 Changes the contents of $filename to $content. No action is performed
710 until the distribution is regenerated.
712 $dist->change_file( $filename, $content );
714 =head3 change_build_pl()
716 A wrapper around change_file specifically for setting Build.PL. Instead
717 of file C<$content>, it takes a hash-ref of Module::Build constructor
720 $dist->change_build_pl(
722 module_name => $dist->name,
723 dist_version => '3.14159265',
731 Retrieves the target contents of C<$filename>.
733 $content = $dist->get_file( $filename );
737 Removes C<$filename> from the distribution.
739 $dist->remove_file( $filename );
743 Returns the object to its initial state, or given a $filename it returns that
744 file to its initial state if it is one of the built-in files.
747 $dist->revert($filename);
749 =head2 Changing the distribution directory
751 These methods immediately affect the filesystem.
755 Regenerate all missing or changed files. Also deletes any files
756 flagged for removal with remove_file().
758 $dist->regen(clean => 1);
760 If the optional C<clean> argument is given, it also calls C<clean>. These
761 can also be chained like this, instead:
767 Removes any files that are not part of the distribution.
773 Changes back to the original directory and removes the distribution
774 directory (but not the temporary directory set during C<new()>).
776 $dist = DistGen->new->chdir->regen;
777 # ... do some testing ...
779 $dist->remove->chdir_in->regen;
780 # ... do more testing ...
782 This is like a more aggressive form of C<clean>. Generally, calling C<clean>
783 and C<regen> should be sufficient.
785 =head2 Changing directories
789 Change directory into the dist root.
793 =head3 chdir_original
795 Returns to whatever directory you were in before chdir_in() (regardless
798 $dist->chdir_original;
800 =head2 Command-line helpers
802 These use Module::Build->run_perl_script() to ensure that Build.PL or Build are
803 run in a separate process using the current perl interpreter. (Module::Build
804 is loaded on demand). They also ensure appropriate naming for operating
805 systems that require a suffix for Build.
809 Runs Build.PL using the current perl interpreter. Any arguments are
810 passed on the command line.
812 $dist->run_build_pl('--quiet');
816 Runs Build using the current perl interpreter. Any arguments are
817 passed on the command line.
819 $dist->run_build(qw/test --verbose/);
825 Returns the name of the distribution.
827 $dist->name: # e.g. Foo::Bar
831 Returns the directory where the distribution is created.
833 $dist->dirname; # e.g. t/_tmp/Simple
839 Removes leading whitespace from a multi-line string according to the
840 amount of whitespace on the first line.
842 my $string = undent(" foo(\n bar => 'baz'\n )");
849 # vim:ts=2:sw=2:et:sta