Upgrade to ExtUtils-Manifest-1.54
Steve Peters [Sun, 10 Aug 2008 16:58:49 +0000 (16:58 +0000)]
p4raw-id: //depot/perl@34193

lib/ExtUtils/MANIFEST.SKIP
lib/ExtUtils/Manifest.pm
lib/ExtUtils/t/Manifest.t

index 5668621..5e83af9 100644 (file)
@@ -4,6 +4,7 @@
 \bSCCS\b
 ,v$
 \B\.svn\b
+\B\.git\b
 \b_darcs\b
 
 # Avoid Makemaker generated and utility files.
index ee508c8..bcc476d 100644 (file)
@@ -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
index e8732ad..6139202 100644 (file)
@@ -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");
 }