diff options
-rw-r--r-- | lib/ExtUtils/MANIFEST.SKIP | 1 | ||||
-rw-r--r-- | lib/ExtUtils/Manifest.pm | 75 | ||||
-rw-r--r-- | lib/ExtUtils/t/Manifest.t | 122 |
3 files changed, 172 insertions, 26 deletions
diff --git a/lib/ExtUtils/MANIFEST.SKIP b/lib/ExtUtils/MANIFEST.SKIP index 56686212a0..5e83af9c94 100644 --- a/lib/ExtUtils/MANIFEST.SKIP +++ b/lib/ExtUtils/MANIFEST.SKIP @@ -4,6 +4,7 @@ \bSCCS\b ,v$ \B\.svn\b +\B\.git\b \b_darcs\b # Avoid Makemaker generated and utility files. diff --git a/lib/ExtUtils/Manifest.pm b/lib/ExtUtils/Manifest.pm index ee508c8fa9..bcc476de83 100644 --- a/lib/ExtUtils/Manifest.pm +++ b/lib/ExtUtils/Manifest.pm @@ -13,11 +13,12 @@ use vars qw($VERSION @ISA @EXPORT_OK $Is_MacOS $Is_VMS $Debug $Verbose $Quiet $MANIFEST $DEFAULT_MSKIP); -$VERSION = '1.51_01'; +$VERSION = '1.54'; @ISA=('Exporter'); @EXPORT_OK = qw(mkmanifest manicheck filecheck fullcheck skipcheck manifind maniread manicopy maniadd + maniskip ); $Is_MacOS = $^O eq 'MacOS'; @@ -71,16 +72,14 @@ exported on request mkmanifest(); Writes all files in and below the current directory to your F<MANIFEST>. -It works similar to +It works similar to the result of the Unix command find . > MANIFEST All files that match any regular expression in a file F<MANIFEST.SKIP> (if it exists) are ignored. -Any existing F<MANIFEST> file will be saved as F<MANIFEST.bak>. Lines -from the old F<MANIFEST> file is preserved, including any comments -that are found in the existing F<MANIFEST> file in the new one. +Any existing F<MANIFEST> file will be saved as F<MANIFEST.bak>. =cut @@ -96,8 +95,8 @@ sub mkmanifest { my $bakbase = $MANIFEST; $bakbase =~ s/\./_/g if $Is_VMS; # avoid double dots rename $MANIFEST, "$bakbase.bak" unless $manimiss; - open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!"; - my $skip = _maniskip(); + open M, "> $MANIFEST" or die "Could not open $MANIFEST: $!"; + my $skip = maniskip(); my $found = manifind(); my($key,$val,$file,%all); %all = (%$found, %$read); @@ -118,6 +117,10 @@ sub mkmanifest { my $tabs = (5 - (length($file)+1)/8); $tabs = 1 if $tabs < 1; $tabs = 0 unless $text; + if ($file =~ /\s/) { + $file =~ s/([\\'])/\\$1/g; + $file = "'$file'"; + } print M $file, "\t" x $tabs, $text, "\n"; } close M; @@ -231,7 +234,7 @@ file. sub skipcheck { my($p) = @_; my $found = manifind(); - my $matches = _maniskip(); + my $matches = maniskip(); my @skipped = (); foreach my $file (_sort keys %$found){ @@ -274,7 +277,7 @@ sub _check_manifest { my($p) = @_; my $read = maniread() || {}; my $found = manifind($p); - my $skip = _maniskip(); + my $skip = maniskip(); my @missentry = (); foreach my $file (_sort keys %$found){ @@ -308,7 +311,7 @@ sub maniread { $mfile ||= $MANIFEST; my $read = {}; local *M; - unless (open M, $mfile){ + unless (open M, "< $mfile"){ warn "Problem opening $mfile: $!"; return $read; } @@ -317,7 +320,16 @@ sub maniread { chomp; next if /^\s*#/; - my($file, $comment) = /^(\S+)\s*(.*)/; + my($file, $comment); + + # filename may contain spaces if enclosed in '' + # (in which case, \\ and \' are escapes) + if (($file, $comment) = /^'(\\[\\']|.+)+'\s*(.*)/) { + $file =~ s/\\([\\'])/$1/g; + } + else { + ($file, $comment) = /^(\S+)\s*(.*)/; + } next unless $file; if ($Is_MacOS) { @@ -343,18 +355,33 @@ sub maniread { $read; } +=item maniskip + + my $skipchk = maniskip(); + my $skipchk = maniskip($manifest_skip_file); + + if ($skipchk->($file)) { .. } + +reads a named C<MANIFEST.SKIP> file (defaults to C<MANIFEST.SKIP> in +the current directory) and returns a CODE reference that tests whether +a given filename should be skipped. + +=cut + # returns an anonymous sub that decides if an argument matches -sub _maniskip { +sub maniskip { my @skip ; - my $mfile = "$MANIFEST.SKIP"; + my $mfile = shift || "$MANIFEST.SKIP"; _check_mskip_directives($mfile) if -f $mfile; local(*M, $_); - open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0}; + open M, "< $mfile" or open M, "< $DEFAULT_MSKIP" or return sub {0}; while (<M>){ chomp; s/\r//; next if /^#/; next if /^\s*$/; + s/^'//; + s/'$//; push @skip, _macify($_); } close M; @@ -380,7 +407,7 @@ sub _check_mskip_directives { local (*M, $_); my @lines = (); my $flag = 0; - unless (open M, $mfile) { + unless (open M, "< $mfile") { warn "Problem opening $mfile: $!"; return; } @@ -410,7 +437,7 @@ sub _check_mskip_directives { $bakbase =~ s/\./_/g if $Is_VMS; # avoid double dots rename $mfile, "$bakbase.bak"; warn "Debug: Saving original $mfile as $bakbase.bak\n" if $Debug; - unless (open M, ">$mfile") { + unless (open M, "> $mfile") { warn "Problem opening $mfile: $!"; return; } @@ -428,7 +455,7 @@ sub _include_mskip_file { return; } local (*M, $_); - unless (open M, $mskip) { + unless (open M, "< $mskip") { warn "Problem opening $mskip: $!"; return; } @@ -492,7 +519,10 @@ sub manicopy { sub cp_if_diff { my($from, $to, $how)=@_; - -f $from or carp "$0: $from not found"; + if (! -f $from) { + carp "$from not found"; + return; + } my($diff) = 0; local(*F,*T); open(F,"< $from\0") or die "Can't read $from: $!\n"; @@ -626,6 +656,10 @@ sub maniadd { foreach my $file (_sort @needed) { my $comment = $additions->{$file} || ''; + if ($file =~ /\s/) { + $file =~ s/([\\'])/\\$1/g; + $file = "'$file'"; + } printf MANIFEST "%-40s %s\n", $file, $comment; } close MANIFEST or die "Error closing $MANIFEST: $!"; @@ -669,11 +703,14 @@ means F<foo/bar> style not F<foo\bar>. Anything between white space and an end of line within a C<MANIFEST> file is considered to be a comment. Any line beginning with # is also -a comment. +a comment. Beginning with ExtUtils::Manifest 1.52, a filename may +contain whitespace characters if it is enclosed in single quotes; single +quotes or backslashes in that filename must be backslash-escaped. # this a comment some/file some/other/file comment about some/file + 'some/third file' comment =head2 MANIFEST.SKIP diff --git a/lib/ExtUtils/t/Manifest.t b/lib/ExtUtils/t/Manifest.t index e8732ad9fc..6139202f23 100644 --- a/lib/ExtUtils/t/Manifest.t +++ b/lib/ExtUtils/t/Manifest.t @@ -13,7 +13,7 @@ chdir 't'; use strict; -use Test::More tests => 66; +use Test::More tests => 94; use Cwd; use File::Spec; @@ -33,7 +33,7 @@ sub add_file { my ($file, $data) = @_; $data ||= 'foo'; 1 while unlink $file; # or else we'll get multiple versions on VMS - open( T, '>'.$file) or return; + open( T, '> '.$file) or return; print T $data; ++$Files{$file}; close T; @@ -60,7 +60,7 @@ sub remove_dir { BEGIN { use_ok( 'ExtUtils::Manifest', qw( mkmanifest manicheck filecheck fullcheck - maniread manicopy skipcheck maniadd) ); + maniread manicopy skipcheck maniadd maniskip) ); } my $cwd = Cwd::getcwd(); @@ -173,12 +173,12 @@ $files = maniread(); eval { (undef, $warn) = catch_warning( sub { manicopy( $files, 'copy', 'cp' ) }) }; -like( $@, qr/^Can't read none: /, 'croaked about none' ); # a newline comes through, so get rid of it chomp($warn); - -# the copy should have given one warning and one error +# the copy should have given a warning +like($warn, qr/^none not found/, 'carped about none' ); +($res, $warn) = catch_warning( \&skipcheck ); like($warn, qr/^Skipping MANIFEST.SKIP/i, 'warned about MANIFEST.SKIP' ); # tell ExtUtils::Manifest to use a different file @@ -218,13 +218,67 @@ is( $files->{wibble}, '', 'maniadd() with undef comment' ); is( $files->{yarrow}, 'hock',' with comment' ); is( $files->{foobar}, '', ' preserved old entries' ); +my %funky_files; +# test including a filename with a space +SKIP: { + add_file( 'foo bar' => "space" ) + or skip "couldn't create spaced test file", 2; + local $ExtUtils::Manifest::MANIFEST = "albatross"; + maniadd({ 'foo bar' => "contains space"}); + is( maniread()->{'foo bar'}, "contains space", + 'spaced manifest filename' ); + add_file( 'albatross.bak', '' ); + ($res, $warn) = catch_warning( \&mkmanifest ); + like( $warn, qr/\A(Added to.*\n)+\z/m, + 'no warnings about funky filename' ); + $funky_files{'space'} = 'foo bar'; +} + +# test including a filename with a space and a quote +SKIP: { + add_file( 'foo\' baz\'quux' => "quote" ) + or skip "couldn't create quoted test file", 1; + local $ExtUtils::Manifest::MANIFEST = "albatross"; + maniadd({ 'foo\' baz\'quux' => "contains quote"}); + is( maniread()->{'foo\' baz\'quux'}, "contains quote", + 'quoted manifest filename' ); + $funky_files{'space_quote'} = 'foo\' baz\'quux'; +} + +# test including a filename with a space and a backslash +SKIP: { + add_file( 'foo bar\\baz' => "backslash" ) + or skip "couldn't create backslash test file", 1; + local $ExtUtils::Manifest::MANIFEST = "albatross"; + maniadd({ 'foo bar\\baz' => "contains backslash"}); + is( maniread()->{'foo bar\\baz'}, "contains backslash", + 'backslashed manifest filename' ); + $funky_files{'space_backslash'} = 'foo bar\\baz'; +} + +# test including a filename with a space, quote, and a backslash +SKIP: { + add_file( 'foo bar\\baz\'quux' => "backslash/quote" ) + or skip "couldn't create backslash/quote test file", 1; + local $ExtUtils::Manifest::MANIFEST = "albatross"; + maniadd({ 'foo bar\\baz\'quux' => "backslash and quote"}); + is( maniread()->{'foo bar\\baz\'quux'}, "backslash and quote", + 'backslashed and quoted manifest filename' ); + $funky_files{'space_quote_backslash'} = 'foo bar\\baz\'quux'; +} + +my @funky_keys = qw(space space_quote space_backslash space_quote_backslash); # test including an external manifest.skip file in MANIFEST.SKIP { maniadd({ foo => undef , albatross => undef, 'mymanifest.skip' => undef, 'mydefault.skip' => undef}); + for (@funky_keys) { + maniadd( {$funky_files{$_} => $_} ) if defined $funky_files{$_}; + } + add_file('mymanifest.skip' => "^foo\n"); add_file('mydefault.skip' => "^my\n"); - $ExtUtils::Manifest::DEFAULT_MSKIP = + local $ExtUtils::Manifest::DEFAULT_MSKIP = File::Spec->catfile($cwd, qw(mantest mydefault.skip)); my $skip = File::Spec->catfile($cwd, qw(mantest mymanifest.skip)); add_file('MANIFEST.SKIP' => @@ -234,11 +288,27 @@ is( $files->{foobar}, '', ' preserved old entries' ); like( $warn, qr/Skipping \b$_\b/, "Skipping $_" ); } + for my $funky_key (@funky_keys) { + SKIP: { + my $funky_file = $funky_files{$funky_key}; + skip "'$funky_key' not created", 1 unless $funky_file; + like( $warn, qr/Skipping \b\Q$funky_file\E\b/, + "Skipping $funky_file"); + } + } ($res, $warn) = catch_warning( \&mkmanifest ); for (qw(albatross foo foobar mymanifest.skip mydefault.skip)) { like( $warn, qr/Removed from MANIFEST: \b$_\b/, "Removed $_ from MANIFEST" ); } + for my $funky_key (@funky_keys) { + SKIP: { + my $funky_file = $funky_files{$funky_key}; + skip "'$funky_key' not created", 1 unless $funky_file; + like( $warn, qr/Removed from MANIFEST: \b\Q$funky_file\E\b/, + "Removed $funky_file from MANIFEST"); + } + } my $files = maniread; ok( ! exists $files->{albatross}, 'albatross excluded via MANIFEST.SKIP' ); ok( exists $files->{yarrow}, 'yarrow included in MANIFEST' ); @@ -249,6 +319,44 @@ is( $files->{foobar}, '', ' preserved old entries' ); 'mymanifest.skip excluded via mydefault.skip' ); ok( ! exists $files->{'mydefault.skip'}, 'mydefault.skip excluded via mydefault.skip' ); + + # test exclusion of funky files + for my $funky_key (@funky_keys) { + SKIP: { + my $funky_file = $funky_files{$funky_key}; + skip "'$funky_key' not created", 1 unless $funky_file; + ok( ! exists $files->{$funky_file}, + "'$funky_file' excluded via mymanifest.skip" ); + } + } + + # tests for maniskip + my $skipchk = maniskip(); + is ( $skipchk->('albatross'), 1, + 'albatross excluded via MANIFEST.SKIP' ); + is( $skipchk->('yarrow'), '', + 'yarrow included in MANIFEST' ); + is( $skipchk->('bar'), '', + 'bar included in MANIFEST' ); + $skipchk = maniskip('mymanifest.skip'); + is( $skipchk->('foobar'), 1, + 'foobar excluded via mymanifest.skip' ); + is( $skipchk->('foo'), 1, + 'foo excluded via mymanifest.skip' ); + is( $skipchk->('mymanifest.skip'), '', + 'mymanifest.skip included via mydefault.skip' ); + is( $skipchk->('mydefault.skip'), '', + 'mydefault.skip included via mydefault.skip' ); + $skipchk = maniskip('mydefault.skip'); + is( $skipchk->('foobar'), '', + 'foobar included via mydefault.skip' ); + is( $skipchk->('foo'), '', + 'foo included via mydefault.skip' ); + is( $skipchk->('mymanifest.skip'), 1, + 'mymanifest.skip excluded via mydefault.skip' ); + is( $skipchk->('mydefault.skip'), 1, + 'mydefault.skip excluded via mydefault.skip' ); + my $extsep = $Is_VMS ? '_' : '.'; $Files{"$_.bak"}++ for ('MANIFEST', "MANIFEST${extsep}SKIP"); } |