Commit | Line | Data |
7a4e305a |
1 | package DistGen; |
2 | |
3 | use strict; |
eed8b6fa |
4 | use warnings; |
7a4e305a |
5 | |
6 | use vars qw( $VERSION $VERBOSE @EXPORT_OK); |
7 | |
8 | $VERSION = '0.01'; |
9 | $VERBOSE = 0; |
10 | |
11 | use Carp; |
12 | |
13 | use MBTest (); |
14 | use Cwd (); |
15 | use File::Basename (); |
16 | use File::Find (); |
17 | use File::Path (); |
18 | use File::Spec (); |
19 | use IO::File (); |
20 | use Tie::CPHash; |
21 | use Data::Dumper; |
22 | |
23 | my $vms_mode; |
24 | my $vms_lower_case; |
25 | |
26 | BEGIN { |
27 | $vms_mode = 0; |
28 | $vms_lower_case = 0; |
29 | if( $^O eq 'VMS' ) { |
30 | # For things like vmsify() |
31 | require VMS::Filespec; |
32 | VMS::Filespec->import; |
33 | $vms_mode = 1; |
34 | $vms_lower_case = 1; |
35 | my $vms_efs_case = 0; |
36 | my $unix_rpt = 0; |
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"); |
40 | } else { |
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; |
45 | } |
46 | $vms_mode = 0 if $unix_rpt; |
47 | $vms_lower_case = 0 if $vms_efs_case; |
48 | } |
49 | } |
50 | BEGIN { |
51 | require Exporter; |
52 | *{import} = \&Exporter::import; |
53 | @EXPORT_OK = qw( |
54 | undent |
55 | ); |
56 | } |
57 | |
58 | sub undent { |
59 | my ($string) = @_; |
60 | |
61 | my ($space) = $string =~ m/^(\s+)/; |
62 | $string =~ s/^$space//gm; |
63 | |
64 | return($string); |
65 | } |
66 | |
67 | sub chdir_all ($) { |
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'; |
71 | chdir shift; |
72 | } |
73 | |
74 | ######################################################################## |
75 | |
76 | END { chdir_all(MBTest->original_cwd); } |
77 | |
78 | sub new { |
79 | my $self = bless {}, shift; |
80 | $self->reset(@_); |
81 | } |
82 | |
83 | sub reset { |
84 | my $self = shift; |
85 | my %options = @_; |
86 | |
87 | $options{name} ||= 'Simple'; |
88 | $options{dir} = File::Spec->rel2abs( |
89 | defined $options{dir} ? $options{dir} : MBTest->tmpdir |
90 | ); |
91 | |
92 | my %data = ( |
93 | no_manifest => 0, |
94 | xs => 0, |
95 | inc => 0, |
96 | %options, |
97 | ); |
98 | %$self = %data; |
99 | |
100 | tie %{$self->{filedata}}, 'Tie::CPHash'; |
101 | |
102 | tie %{$self->{pending}{change}}, 'Tie::CPHash'; |
103 | |
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 ); |
108 | } |
109 | File::Path::mkpath( $self->dirname ); |
110 | |
111 | $self->_gen_default_filedata(); |
112 | |
113 | return $self; |
114 | } |
115 | |
116 | sub remove { |
117 | my $self = shift; |
118 | $self->chdir_original if($self->did_chdir); |
119 | File::Path::rmtree( $self->dirname ); |
120 | return $self; |
121 | } |
122 | |
123 | sub revert { |
124 | my ($self, $file) = @_; |
125 | if ( defined $file ) { |
126 | delete $self->{filedata}{$file}; |
127 | delete $self->{pending}{$_}{$file} for qw/change remove/; |
128 | } |
129 | else { |
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} }; |
133 | } |
134 | } |
135 | $self->_gen_default_filedata; |
136 | } |
137 | |
138 | sub _gen_default_filedata { |
139 | my $self = shift; |
140 | |
141 | # TODO maybe a public method like this (but with a better name?) |
142 | my $add_unless = sub { |
143 | my $self = shift; |
144 | my ($member, $data) = @_; |
145 | $self->add_file($member, $data) unless($self->{filedata}{$member}); |
146 | }; |
147 | |
148 | if ( ! $self->{inc} ) { |
149 | $self->$add_unless('Build.PL', undent(<<" ---")); |
150 | use strict; |
151 | use Module::Build; |
152 | |
153 | my \$builder = Module::Build->new( |
154 | module_name => '$self->{name}', |
155 | license => 'perl', |
156 | ); |
157 | |
158 | \$builder->create_build_script(); |
159 | --- |
160 | } |
161 | else { |
162 | $self->$add_unless('Build.PL', undent(<<" ---")); |
163 | use strict; |
164 | use inc::latest 'Module::Build'; |
165 | |
166 | my \$builder = Module::Build->new( |
167 | module_name => '$self->{name}', |
168 | license => 'perl', |
169 | ); |
170 | |
171 | \$builder->create_build_script(); |
172 | --- |
173 | } |
174 | |
175 | my $module_filename = |
176 | join( '/', ('lib', split(/::/, $self->{name})) ) . '.pm'; |
177 | |
178 | unless ( $self->{xs} ) { |
179 | $self->$add_unless($module_filename, undent(<<" ---")); |
180 | package $self->{name}; |
181 | |
182 | use vars qw( \$VERSION ); |
183 | \$VERSION = '0.01'; |
184 | |
185 | use strict; |
eed8b6fa |
186 | use warnings; |
7a4e305a |
187 | |
188 | 1; |
189 | |
190 | __END__ |
191 | |
192 | =head1 NAME |
193 | |
194 | $self->{name} - Perl extension for blah blah blah |
195 | |
196 | =head1 DESCRIPTION |
197 | |
198 | Stub documentation for $self->{name}. |
199 | |
200 | =head1 AUTHOR |
201 | |
202 | A. U. Thor, a.u.thor\@a.galaxy.far.far.away |
203 | |
204 | =cut |
205 | --- |
206 | |
207 | $self->$add_unless('t/basic.t', undent(<<" ---")); |
208 | use Test::More tests => 1; |
209 | use strict; |
eed8b6fa |
210 | use warnings; |
7a4e305a |
211 | |
212 | use $self->{name}; |
213 | ok 1; |
214 | --- |
215 | |
216 | } else { |
217 | $self->$add_unless($module_filename, undent(<<" ---")); |
218 | package $self->{name}; |
219 | |
220 | \$VERSION = '0.01'; |
221 | |
222 | require Exporter; |
223 | require DynaLoader; |
224 | |
225 | \@ISA = qw(Exporter DynaLoader); |
226 | \@EXPORT_OK = qw( okay ); |
227 | |
228 | bootstrap $self->{name} \$VERSION; |
229 | |
230 | 1; |
231 | |
232 | __END__ |
233 | |
234 | =head1 NAME |
235 | |
236 | $self->{name} - Perl extension for blah blah blah |
237 | |
238 | =head1 DESCRIPTION |
239 | |
240 | Stub documentation for $self->{name}. |
241 | |
242 | =head1 AUTHOR |
243 | |
244 | A. U. Thor, a.u.thor\@a.galaxy.far.far.away |
245 | |
246 | =cut |
247 | --- |
248 | |
249 | my $xs_filename = |
250 | join( '/', ('lib', split(/::/, $self->{name})) ) . '.xs'; |
251 | $self->$add_unless($xs_filename, undent(<<" ---")); |
252 | #include "EXTERN.h" |
253 | #include "perl.h" |
254 | #include "XSUB.h" |
255 | |
256 | MODULE = $self->{name} PACKAGE = $self->{name} |
257 | |
258 | SV * |
259 | okay() |
260 | CODE: |
261 | RETVAL = newSVpv( "ok", 0 ); |
262 | OUTPUT: |
263 | RETVAL |
264 | |
265 | const char * |
266 | xs_version() |
267 | CODE: |
268 | RETVAL = XS_VERSION; |
269 | OUTPUT: |
270 | RETVAL |
271 | |
272 | const char * |
273 | version() |
274 | CODE: |
275 | RETVAL = VERSION; |
276 | OUTPUT: |
277 | RETVAL |
278 | --- |
279 | |
280 | # 5.6 is missing const char * in its typemap |
281 | $self->$add_unless('typemap', undent(<<" ---")); |
282 | const char *\tT_PV |
283 | --- |
284 | |
285 | $self->$add_unless('t/basic.t', undent(<<" ---")); |
286 | use Test::More tests => 2; |
287 | use strict; |
288 | |
289 | use $self->{name}; |
290 | ok 1; |
291 | |
292 | ok( $self->{name}::okay() eq 'ok' ); |
293 | --- |
294 | } |
295 | } |
296 | |
297 | sub _gen_manifest { |
298 | my $self = shift; |
299 | my $manifest = shift; |
300 | |
301 | my $fh = IO::File->new( ">$manifest" ) or do { |
302 | die "Can't write '$manifest'\n"; |
303 | }; |
304 | |
305 | my @files = ( 'MANIFEST', keys %{$self->{filedata}} ); |
306 | my $data = join( "\n", sort @files ) . "\n"; |
307 | print $fh $data; |
308 | close( $fh ); |
309 | |
310 | $self->{filedata}{MANIFEST} = $data; |
311 | $self->{pending}{change}{MANIFEST} = 1; |
312 | } |
313 | |
314 | sub name { shift()->{name} } |
315 | |
316 | sub dirname { |
317 | my $self = shift; |
318 | my $dist = $self->{distdir} || join( '-', split( /::/, $self->{name} ) ); |
319 | return File::Spec->catdir( $self->{dir}, $dist ); |
320 | } |
321 | |
322 | sub _real_filename { |
323 | my $self = shift; |
324 | my $filename = shift; |
325 | return File::Spec->catfile( split( /\//, $filename ) ); |
326 | } |
327 | |
328 | sub regen { |
329 | my $self = shift; |
330 | my %opts = @_; |
331 | |
332 | my $dist_dirname = $self->dirname; |
333 | |
334 | if ( $opts{clean} ) { |
335 | $self->clean() if -d $dist_dirname; |
336 | } else { |
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 ); |
346 | } |
347 | print "Unlinking pending file '$file'\n" if $VERBOSE; |
348 | delete( $self->{pending}{remove}{$file} ); |
349 | } |
350 | } |
351 | |
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 ); |
355 | |
356 | if ( ! -e $fullname || |
357 | ( -e $fullname && $self->{pending}{change}{$file} ) ) { |
358 | |
359 | print "Changed file '$file'.\n" if $VERBOSE; |
360 | |
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"; |
365 | }; |
366 | } |
367 | |
368 | if ( -e $fullname ) { |
369 | 1 while unlink( $fullname ); |
370 | } |
371 | |
372 | my $fh = IO::File->new(">$fullname") or do { |
373 | die "Can't write '$fullname'\n"; |
374 | }; |
375 | print $fh $self->{filedata}{$file}; |
376 | close( $fh ); |
377 | } |
378 | |
379 | delete( $self->{pending}{change}{$file} ); |
380 | } |
381 | |
382 | my $manifest = File::Spec->catfile( $dist_dirname, 'MANIFEST' ); |
383 | unless ( $self->{no_manifest} ) { |
384 | if ( -e $manifest ) { |
385 | 1 while unlink( $manifest ); |
386 | } |
387 | $self->_gen_manifest( $manifest ); |
388 | } |
389 | return $self; |
390 | } |
391 | |
392 | sub clean { |
393 | my $self = shift; |
394 | |
395 | my $here = Cwd::abs_path(); |
396 | my $there = File::Spec->rel2abs( $self->dirname() ); |
397 | |
398 | if ( -d $there ) { |
399 | chdir( $there ) or die "Can't change directory to '$there'\n"; |
400 | } else { |
401 | die "Distribution not found in '$there'\n"; |
402 | } |
403 | |
404 | my %names; |
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 ); |
410 | |
411 | $names{$filename} = 0; |
412 | |
413 | print "Splitting '$dirname'\n" if $VERBOSE; |
414 | my @dirs = File::Spec->splitdir( $dirname ); |
415 | while ( @dirs ) { |
416 | my $dir = ( scalar(@dirs) == 1 |
417 | ? $dirname |
418 | : File::Spec->catdir( @dirs ) ); |
419 | if (length $dir) { |
420 | print "Setting directory name '$dir' in \%names\n" if $VERBOSE; |
421 | $names{$dir} = 0; |
422 | } |
423 | pop( @dirs ); |
424 | } |
425 | } |
426 | |
427 | File::Find::finddepth( sub { |
428 | my $name = File::Spec->canonpath( $File::Find::name ); |
429 | |
430 | if ($vms_mode) { |
431 | if ($name ne '.') { |
432 | $name =~ s/\.\z//; |
433 | $name = vmspath($name) if -d $name; |
434 | } |
435 | } |
436 | if ($^O eq 'VMS') { |
437 | $name = File::Spec->rel2abs($name) if $name eq File::Spec->curdir(); |
438 | } |
439 | |
440 | if ( not exists $names{$name} ) { |
441 | print "Removing '$name'\n" if $VERBOSE; |
442 | File::Path::rmtree( $_ ); |
443 | } |
444 | }, ($^O eq 'VMS' ? './' : File::Spec->curdir) ); |
445 | |
446 | chdir_all( $here ); |
447 | return $self; |
448 | } |
449 | |
450 | sub add_file { |
451 | my $self = shift; |
452 | $self->change_file( @_ ); |
453 | } |
454 | |
455 | sub remove_file { |
456 | my $self = shift; |
457 | my $file = shift; |
458 | unless ( exists $self->{filedata}{$file} ) { |
459 | warn "Can't remove '$file': It does not exist.\n" if $VERBOSE; |
460 | } |
461 | delete( $self->{filedata}{$file} ); |
462 | $self->{pending}{remove}{$file} = 1; |
463 | return $self; |
464 | } |
465 | |
466 | sub change_build_pl { |
467 | my ($self, @opts) = @_; |
468 | |
469 | my $opts = ref $opts[0] eq 'HASH' ? $opts[0] : { @opts }; |
470 | |
471 | local $Data::Dumper::Terse = 1; |
472 | (my $args = Dumper($opts)) =~ s/^\s*\{|\}\s*$//g; |
473 | |
474 | $self->change_file( 'Build.PL', undent(<<" ---") ); |
475 | use strict; |
eed8b6fa |
476 | use warnings; |
7a4e305a |
477 | use Module::Build; |
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 |
484 | ), |
485 | $args |
486 | ); |
487 | \$b->create_build_script(); |
488 | --- |
489 | return $self; |
490 | } |
491 | |
492 | sub change_file { |
493 | my $self = shift; |
494 | my $file = shift; |
495 | my $data = shift; |
496 | $self->{filedata}{$file} = $data; |
497 | $self->{pending}{change}{$file} = 1; |
498 | return $self; |
499 | } |
500 | |
501 | sub get_file { |
502 | my $self = shift; |
503 | my $file = shift; |
504 | exists($self->{filedata}{$file}) or croak("no such entry: '$file'"); |
505 | return $self->{filedata}{$file}; |
506 | } |
507 | |
508 | sub chdir_in { |
509 | my $self = shift; |
510 | $self->{original_dir} ||= Cwd::cwd; # only once! |
511 | my $dir = $self->dirname; |
512 | chdir($dir) or die "Can't chdir to '$dir': $!"; |
513 | return $self; |
514 | } |
515 | ######################################################################## |
516 | |
517 | sub did_chdir { exists shift()->{original_dir} } |
518 | |
519 | ######################################################################## |
520 | |
521 | sub chdir_original { |
522 | my $self = shift; |
523 | |
524 | my $dir = delete $self->{original_dir}; |
525 | chdir_all($dir) or die "Can't chdir to '$dir': $!"; |
526 | return $self; |
527 | } |
528 | ######################################################################## |
529 | |
530 | sub new_from_context { |
531 | my ($self, @args) = @_; |
532 | require Module::Build; |
533 | return Module::Build->new_from_context( quiet => 1, @args ); |
534 | } |
535 | |
536 | sub run_build_pl { |
537 | my ($self, @args) = @_; |
538 | require Module::Build; |
539 | return Module::Build->run_perl_script('Build.PL', [], [@args]) |
540 | } |
541 | |
542 | sub run_build { |
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]) |
547 | } |
548 | |
549 | 1; |
550 | |
551 | __END__ |
552 | |
553 | |
554 | =head1 NAME |
555 | |
556 | DistGen - Creates simple distributions for testing. |
557 | |
558 | =head1 SYNOPSIS |
559 | |
560 | use DistGen; |
561 | |
562 | # create distribution and prepare to test |
563 | my $dist = DistGen->new(name => 'Foo::Bar'); |
564 | $dist->chdir_in; |
565 | |
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'); |
570 | $dist->regen; |
571 | |
572 | # undo changes and clean up extraneous files |
573 | $dist->revert; |
574 | $dist->clean; |
575 | |
576 | # exercise the command-line interface |
577 | $dist->run_build_pl(); |
578 | $dist->run_build('test'); |
579 | |
580 | # start over as a new distribution |
581 | $dist->reset( name => 'Foo::Bar', xs => 1 ); |
582 | $dist->chdir_in; |
583 | |
584 | =head1 USAGE |
585 | |
586 | A DistGen object manages a set of files in a distribution directory. |
587 | |
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. |
593 | |
594 | Some methods only define the target state of the distribution. They do B<not> |
595 | make any changes to the filesystem: |
596 | |
597 | add_file |
598 | change_file |
599 | change_build_pl |
600 | remove_file |
601 | revert |
602 | |
603 | Other methods then change the filesystem to match the target state of |
604 | the distribution: |
605 | |
606 | clean |
607 | regen |
608 | remove |
609 | |
610 | Other methods are provided for a convenience during testing. The |
611 | most important is the one to enter the distribution directory: |
612 | |
613 | chdir_in |
614 | |
615 | Additional methods portably encapsulate running Build.PL and Build: |
616 | |
617 | run_build_pl |
618 | run_build |
619 | |
620 | =head1 API |
621 | |
622 | =head2 Constructors |
623 | |
624 | =head3 new() |
625 | |
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. |
629 | |
630 | The C<new> method does not write any files -- see L</regen()> below. |
631 | |
632 | my $dist = DistGen->new( |
633 | name => 'Foo::Bar', |
634 | dir => MBTest->tmpdir, |
635 | xs => 1, |
636 | no_manifest => 0, |
637 | ); |
638 | |
639 | The parameters are as follows. |
640 | |
641 | =over |
642 | |
643 | =item name |
644 | |
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" |
647 | dist name. |
648 | |
649 | =item dir |
650 | |
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. |
654 | |
655 | $dist = DistGen->new( dir => '/tmp/MB-test' ); |
656 | $dist->regen; |
657 | |
658 | # distribution files have been created in /tmp/MB-test/Simple |
659 | |
660 | =item distdir |
661 | |
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'. |
664 | |
665 | =item xs |
666 | |
667 | If true, generates an XS based module. |
668 | |
669 | =item no_manifest |
670 | |
671 | If true, C<regen()> will not create a MANIFEST file. |
672 | |
673 | =back |
674 | |
675 | The following files are added as part of the default distribution: |
676 | |
677 | Build.PL |
678 | lib/Simple.pm # based on name parameter |
679 | t/basic.t |
680 | |
681 | If an XS module is generated, Simple.pm and basic.t are different and |
682 | the following files are also added: |
683 | |
684 | typemap |
685 | lib/Simple.xs # based on name parameter |
686 | |
687 | =head3 reset() |
688 | |
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>. |
691 | |
692 | $dist->reset( name => 'Foo::Bar', xs => 0 ); |
693 | |
694 | =head2 Adding and editing files |
695 | |
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>. |
698 | |
699 | No changes are made to the filesystem until the distribution is regenerated. |
700 | |
701 | =head3 add_file() |
702 | |
703 | Add a $filename containing $content to the distribution. |
704 | |
705 | $dist->add_file( $filename, $content ); |
706 | |
707 | =head3 change_file() |
708 | |
709 | Changes the contents of $filename to $content. No action is performed |
710 | until the distribution is regenerated. |
711 | |
712 | $dist->change_file( $filename, $content ); |
713 | |
714 | =head3 change_build_pl() |
715 | |
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 |
718 | arguments: |
719 | |
720 | $dist->change_build_pl( |
721 | { |
722 | module_name => $dist->name, |
723 | dist_version => '3.14159265', |
724 | license => 'perl', |
725 | create_readme => 1, |
726 | } |
727 | ); |
728 | |
729 | =head3 get_file |
730 | |
731 | Retrieves the target contents of C<$filename>. |
732 | |
733 | $content = $dist->get_file( $filename ); |
734 | |
735 | =head3 remove_file() |
736 | |
737 | Removes C<$filename> from the distribution. |
738 | |
739 | $dist->remove_file( $filename ); |
740 | |
741 | =head3 revert() |
742 | |
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. |
745 | |
746 | $dist->revert; |
747 | $dist->revert($filename); |
748 | |
749 | =head2 Changing the distribution directory |
750 | |
751 | These methods immediately affect the filesystem. |
752 | |
753 | =head3 regen() |
754 | |
755 | Regenerate all missing or changed files. Also deletes any files |
756 | flagged for removal with remove_file(). |
757 | |
758 | $dist->regen(clean => 1); |
759 | |
760 | If the optional C<clean> argument is given, it also calls C<clean>. These |
761 | can also be chained like this, instead: |
762 | |
763 | $dist->clean->regen; |
764 | |
765 | =head3 clean() |
766 | |
767 | Removes any files that are not part of the distribution. |
768 | |
769 | $dist->clean; |
770 | |
771 | =head3 remove() |
772 | |
773 | Changes back to the original directory and removes the distribution |
774 | directory (but not the temporary directory set during C<new()>). |
775 | |
776 | $dist = DistGen->new->chdir->regen; |
777 | # ... do some testing ... |
778 | |
779 | $dist->remove->chdir_in->regen; |
780 | # ... do more testing ... |
781 | |
782 | This is like a more aggressive form of C<clean>. Generally, calling C<clean> |
783 | and C<regen> should be sufficient. |
784 | |
785 | =head2 Changing directories |
786 | |
787 | =head3 chdir_in |
788 | |
789 | Change directory into the dist root. |
790 | |
791 | $dist->chdir_in; |
792 | |
793 | =head3 chdir_original |
794 | |
795 | Returns to whatever directory you were in before chdir_in() (regardless |
796 | of the cwd.) |
797 | |
798 | $dist->chdir_original; |
799 | |
800 | =head2 Command-line helpers |
801 | |
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. |
806 | |
807 | =head3 run_build_pl |
808 | |
809 | Runs Build.PL using the current perl interpreter. Any arguments are |
810 | passed on the command line. |
811 | |
812 | $dist->run_build_pl('--quiet'); |
813 | |
814 | =head3 run_build |
815 | |
816 | Runs Build using the current perl interpreter. Any arguments are |
817 | passed on the command line. |
818 | |
819 | $dist->run_build(qw/test --verbose/); |
820 | |
821 | =head2 Properties |
822 | |
823 | =head3 name() |
824 | |
825 | Returns the name of the distribution. |
826 | |
827 | $dist->name: # e.g. Foo::Bar |
828 | |
829 | =head3 dirname() |
830 | |
831 | Returns the directory where the distribution is created. |
832 | |
833 | $dist->dirname; # e.g. t/_tmp/Simple |
834 | |
835 | =head2 Functions |
836 | |
837 | =head3 undent() |
838 | |
839 | Removes leading whitespace from a multi-line string according to the |
840 | amount of whitespace on the first line. |
841 | |
842 | my $string = undent(" foo(\n bar => 'baz'\n )"); |
843 | $string eq "foo( |
844 | bar => 'baz' |
845 | )"; |
846 | |
847 | =cut |
848 | |
849 | # vim:ts=2:sw=2:et:sta |