5 use vars qw( $VERSION $VERBOSE @EXPORT_OK);
12 use File::Basename ();
22 # For things like vmsify()
23 require VMS::Filespec;
24 VMS::Filespec->import;
29 *{import} = \&Exporter::import;
39 $options{name} ||= 'Simple';
40 $options{dir} ||= Cwd::cwd();
47 my $self = bless( \%data, $package );
49 tie %{$self->{filedata}}, 'Tie::CPHash';
51 tie %{$self->{pending}{change}}, 'Tie::CPHash';
53 if ( -d $self->dirname ) {
54 warn "Warning: Removing existing directory '@{[$self->dirname]}'\n";
58 $self->_gen_default_filedata();
67 my ($space) = $string =~ m/^(\s+)/;
68 $string =~ s/^$space//gm;
73 sub _gen_default_filedata {
76 # TODO maybe a public method like this (but with a better name?)
77 my $add_unless = sub {
79 my ($member, $data) = @_;
80 $self->add_file($member, $data) unless($self->{filedata}{$member});
83 $self->$add_unless('Build.PL', undent(<<" ---"));
87 my \$builder = Module::Build->new(
88 module_name => '$self->{name}',
92 \$builder->create_build_script();
96 join( '/', ('lib', split(/::/, $self->{name})) ) . '.pm';
98 unless ( $self->{xs} ) {
99 $self->$add_unless($module_filename, undent(<<" ---"));
100 package $self->{name};
102 use vars qw( \$VERSION );
113 $self->{name} - Perl extension for blah blah blah
117 Stub documentation for $self->{name}.
121 A. U. Thor, a.u.thor\@a.galaxy.far.far.away
126 $self->$add_unless('t/basic.t', undent(<<" ---"));
127 use Test::More tests => 1;
135 $self->$add_unless($module_filename, undent(<<" ---"));
136 package $self->{name};
143 \@ISA = qw(Exporter DynaLoader);
144 \@EXPORT_OK = qw( okay );
146 bootstrap $self->{name} \$VERSION;
154 $self->{name} - Perl extension for blah blah blah
158 Stub documentation for $self->{name}.
162 A. U. Thor, a.u.thor\@a.galaxy.far.far.away
168 join( '/', ('lib', split(/::/, $self->{name})) ) . '.xs';
169 $self->$add_unless($xs_filename, undent(<<" ---"));
174 MODULE = $self->{name} PACKAGE = $self->{name}
179 RETVAL = newSVpv( "ok", 0 );
198 $self->$add_unless('t/basic.t', undent(<<" ---"));
199 use Test::More tests => 2;
205 ok( $self->{name}::okay() eq 'ok' );
212 my $manifest = shift;
214 my $fh = IO::File->new( ">$manifest" ) or do {
216 die "Can't write '$manifest'\n";
219 my @files = ( 'MANIFEST', keys %{$self->{filedata}} );
220 my $data = join( "\n", sort @files ) . "\n";
224 $self->{filedata}{MANIFEST} = $data;
225 $self->{pending}{change}{MANIFEST} = 1;
228 sub name { shift()->{name} }
232 my $dist = join( '-', split( /::/, $self->{name} ) );
233 return File::Spec->catdir( $self->{dir}, $dist );
238 my $filename = shift;
239 return File::Spec->catfile( split( /\//, $filename ) );
246 my $dist_dirname = $self->dirname;
248 if ( $opts{clean} ) {
249 $self->clean() if -d $dist_dirname;
251 # TODO: This might leave dangling directories. Eg if the removed file
252 # is 'lib/Simple/Simon.pm', The directory 'lib/Simple' will be left
253 # even if there are no files left in it. However, clean() will remove it.
254 my @files = keys %{$self->{pending}{remove}};
255 foreach my $file ( @files ) {
256 my $real_filename = $self->_real_filename( $file );
257 my $fullname = File::Spec->catfile( $dist_dirname, $real_filename );
258 if ( -e $fullname ) {
259 1 while unlink( $fullname );
261 print "Unlinking pending file '$file'\n" if $VERBOSE;
262 delete( $self->{pending}{remove}{$file} );
266 foreach my $file ( keys( %{$self->{filedata}} ) ) {
267 my $real_filename = $self->_real_filename( $file );
268 my $fullname = File::Spec->catfile( $dist_dirname, $real_filename );
270 if ( ! -e $fullname ||
271 ( -e $fullname && $self->{pending}{change}{$file} ) ) {
273 print "Changed file '$file'.\n" if $VERBOSE;
275 my $dirname = File::Basename::dirname( $fullname );
276 unless ( -d $dirname ) {
277 File::Path::mkpath( $dirname ) or do {
279 die "Can't create '$dirname'\n";
283 if ( -e $fullname ) {
284 1 while unlink( $fullname );
287 my $fh = IO::File->new(">$fullname") or do {
289 die "Can't write '$fullname'\n";
291 print $fh $self->{filedata}{$file};
295 delete( $self->{pending}{change}{$file} );
298 my $manifest = File::Spec->catfile( $dist_dirname, 'MANIFEST' );
299 unless ( $self->{skip_manifest} ) {
300 if ( -e $manifest ) {
301 1 while unlink( $manifest );
303 $self->_gen_manifest( $manifest );
310 my $here = Cwd::abs_path();
311 my $there = File::Spec->rel2abs( $self->dirname() );
314 chdir( $there ) or die "Can't change directory to '$there'\n";
316 die "Distribution not found in '$there'\n";
320 tie %names, 'Tie::CPHash';
321 foreach my $file ( keys %{$self->{filedata}} ) {
322 my $filename = $self->_real_filename( $file );
323 my $dirname = File::Basename::dirname( $filename );
325 $names{$filename} = 0;
327 print "Splitting '$dirname'\n" if $VERBOSE;
328 my @dirs = File::Spec->splitdir( $dirname );
330 my $dir = ( scalar(@dirs) == 1
332 : File::Spec->catdir( @dirs ) );
334 print "Setting directory name '$dir' in \%names\n" if $VERBOSE;
341 File::Find::finddepth( sub {
342 my $name = File::Spec->canonpath( $File::Find::name );
346 $name = vmspath($name) if -d $name;
347 $name = File::Spec->rel2abs($name) if $name eq File::Spec->curdir();
350 if ( not exists $names{$name} ) {
351 print "Removing '$name'\n" if $VERBOSE;
352 File::Path::rmtree( $_ );
354 }, ($^O eq "VMS" ? './' : File::Spec->curdir) );
361 File::Path::rmtree( File::Spec->canonpath($self->dirname) );
366 die "Unimplemented.\n";
371 $self->change_file( @_ );
377 unless ( exists $self->{filedata}{$file} ) {
378 warn "Can't remove '$file': It does not exist.\n" if $VERBOSE;
380 delete( $self->{filedata}{$file} );
381 $self->{pending}{remove}{$file} = 1;
384 sub change_build_pl {
385 my ($self, $opts) = @_;
387 local $Data::Dumper::Terse = 1;
388 (my $args = Dumper($opts)) =~ s/^\s*\{|\}\s*$//g;
390 $self->change_file( 'Build.PL', undent(<<" ---") );
393 my \$b = Module::Build->new(
396 \$b->create_build_script();
404 $self->{filedata}{$file} = $data;
405 $self->{pending}{change}{$file} = 1;
415 DistGen - Creates simple distributions for testing.
421 my $dist = DistGen->new(dir => $tmp);
423 $dist->add_file('t/some_test.t', $contents);
427 chdir($dist->dirname) or
428 die "Cannot chdir to '@{[$dist->dirname]}': $!";
432 chdir($cwd) or die "cannot return to $cwd";
441 Create a new object. Does not write its contents (see L</regen()>.)
443 my $tmp = MBTest->tmpdir;
444 my $dist = DistGen->new(
450 The parameters are as follows.
456 The name of the module this distribution represents. The default is
457 'Simple'. This should be a "Foo::Bar" (module) name, not a "Foo-Bar"
462 The (parent) directory in which to create the distribution directory.
463 The default is File::Spec->curdir. The distribution will be created
464 under this according to the "dist" form of C<name> (e.g. "Foo-Bar".)
468 If true, generates an XS based module.
472 =head2 Manipulating the Distribution
474 These methods immediately affect the filesystem.
478 Regenerate all missing or changed files.
480 $dist->regen(clean => 1);
482 If the optional C<clean> argument is given, it also removes any
483 extraneous files that do not belong to the distribution.
487 Removes any files that are not part of the distribution.
495 [Unimplemented] Returns the object to its initial state, or given a
496 $filename it returns that file to it's initial state if it is one of
500 $dist->revert($filename);
506 Removes the entire distribution directory.
510 Note that C<$filename> should always be specified with unix-style paths,
511 and are relative to the distribution root directory. Eg 'lib/Module.pm'
513 No filesystem action is performed until the distribution is regenerated.
517 Add a $filename containing $content to the distribution.
519 $dist->add_file( $filename, $content );
523 Removes C<$filename> from the distribution.
525 $dist->remove_file( $filename );
529 Changes the contents of $filename to $content. No action is performed
530 until the distribution is regenerated.
532 $dist->change_file( $filename, $content );
538 Returns the name of the distribution.
542 Returns the directory where the distribution is created.
544 $dist->dirname; # e.g. t/_tmp/Simple
550 Removes leading whitespace from a multi-line string according to the
551 amount of whitespace on the first line.
553 my $string = undent(" foo(\n bar => 'baz'\n )");
560 # vim:ts=2:sw=2:et:sta