summaryrefslogtreecommitdiff
path: root/cpan/ExtUtils-Manifest
diff options
context:
space:
mode:
authorChris 'BinGOs' Williams <chris@bingosnet.co.uk>2014-08-07 11:09:22 +0100
committerChris 'BinGOs' Williams <chris@bingosnet.co.uk>2014-08-07 11:09:22 +0100
commit854a00d80afb6700138c1b8553393de2eb36e500 (patch)
tree57edbf285c76071827e63f300afed2539068c57f /cpan/ExtUtils-Manifest
parent2ca4a82e4992cef284e3ce9716fea66ec947e01d (diff)
downloadperl-854a00d80afb6700138c1b8553393de2eb36e500.tar.gz
Move ExtUtils-Manifest to cpan/
Maintained by the Perl Toolchain Gang now
Diffstat (limited to 'cpan/ExtUtils-Manifest')
-rw-r--r--cpan/ExtUtils-Manifest/lib/ExtUtils/MANIFEST.SKIP59
-rw-r--r--cpan/ExtUtils-Manifest/lib/ExtUtils/Manifest.pm899
-rw-r--r--cpan/ExtUtils-Manifest/t/Manifest.t461
3 files changed, 1419 insertions, 0 deletions
diff --git a/cpan/ExtUtils-Manifest/lib/ExtUtils/MANIFEST.SKIP b/cpan/ExtUtils-Manifest/lib/ExtUtils/MANIFEST.SKIP
new file mode 100644
index 0000000000..725f84e3d1
--- /dev/null
+++ b/cpan/ExtUtils-Manifest/lib/ExtUtils/MANIFEST.SKIP
@@ -0,0 +1,59 @@
+# Avoid version control files.
+\bRCS\b
+\bCVS\b
+\bSCCS\b
+,v$
+\B\.svn\b
+\B\.git\b
+\B\.gitignore\b
+\b_darcs\b
+\B\.cvsignore$
+
+# Avoid VMS specific MakeMaker generated files
+\bDescrip.MMS$
+\bDESCRIP.MMS$
+\bdescrip.mms$
+
+# Avoid Makemaker generated and utility files.
+\bMANIFEST\.bak
+\bMakefile$
+\bblib/
+\bMakeMaker-\d
+\bpm_to_blib\.ts$
+\bpm_to_blib$
+\bblibdirs\.ts$ # 6.18 through 6.25 generated this
+
+# Avoid Module::Build generated and utility files.
+\bBuild$
+\b_build/
+\bBuild.bat$
+\bBuild.COM$
+\bBUILD.COM$
+\bbuild.com$
+
+# Avoid temp and backup files.
+~$
+\.old$
+\#$
+\b\.#
+\.bak$
+\.tmp$
+\.#
+\.rej$
+\..*\.sw.?$
+
+# Avoid OS-specific files/dirs
+# Mac OSX metadata
+\B\.DS_Store
+# Mac OSX SMB mount metadata files
+\B\._
+
+# Avoid Devel::Cover and Devel::CoverX::Covered files.
+\bcover_db\b
+\bcovered\b
+
+# Avoid prove files
+\B\.prove$
+
+# Avoid MYMETA files
+^MYMETA\.
diff --git a/cpan/ExtUtils-Manifest/lib/ExtUtils/Manifest.pm b/cpan/ExtUtils-Manifest/lib/ExtUtils/Manifest.pm
new file mode 100644
index 0000000000..165a15cc5a
--- /dev/null
+++ b/cpan/ExtUtils-Manifest/lib/ExtUtils/Manifest.pm
@@ -0,0 +1,899 @@
+package ExtUtils::Manifest;
+
+require Exporter;
+use Config;
+use File::Basename;
+use File::Copy 'copy';
+use File::Find;
+use File::Spec;
+use Carp;
+use strict;
+use warnings;
+
+use Exporter 5.57 'import';
+
+our $VERSION = '1.64';
+our @EXPORT_OK = qw(mkmanifest
+ manicheck filecheck fullcheck skipcheck
+ manifind maniread manicopy maniadd
+ maniskip
+ );
+
+our $Is_MacOS = $^O eq 'MacOS';
+our $Is_VMS = $^O eq 'VMS';
+our $Is_VMS_mode = 0;
+our $Is_VMS_lc = 0;
+our $Is_VMS_nodot = 0; # No dots in dir names or double dots in files
+
+if ($Is_VMS) {
+ require VMS::Filespec if $Is_VMS;
+ my $vms_unix_rpt;
+ my $vms_efs;
+ my $vms_case;
+
+ $Is_VMS_mode = 1;
+ $Is_VMS_lc = 1;
+ $Is_VMS_nodot = 1;
+ if (eval { local $SIG{__DIE__}; require VMS::Feature; }) {
+ $vms_unix_rpt = VMS::Feature::current("filename_unix_report");
+ $vms_efs = VMS::Feature::current("efs_charset");
+ $vms_case = VMS::Feature::current("efs_case_preserve");
+ } else {
+ my $unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || '';
+ my $efs_charset = $ENV{'DECC$EFS_CHARSET'} || '';
+ my $efs_case = $ENV{'DECC$EFS_CASE_PRESERVE'} || '';
+ $vms_unix_rpt = $unix_rpt =~ /^[ET1]/i;
+ $vms_efs = $efs_charset =~ /^[ET1]/i;
+ $vms_case = $efs_case =~ /^[ET1]/i;
+ }
+ $Is_VMS_lc = 0 if ($vms_case);
+ $Is_VMS_mode = 0 if ($vms_unix_rpt);
+ $Is_VMS_nodot = 0 if ($vms_efs);
+}
+
+our $Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
+our $Verbose = defined $ENV{PERL_MM_MANIFEST_VERBOSE} ?
+ $ENV{PERL_MM_MANIFEST_VERBOSE} : 1;
+our $Quiet = 0;
+our $MANIFEST = 'MANIFEST';
+
+our $DEFAULT_MSKIP = File::Spec->catfile( dirname(__FILE__), "$MANIFEST.SKIP" );
+
+
+=head1 NAME
+
+ExtUtils::Manifest - utilities to write and check a MANIFEST file
+
+=head1 SYNOPSIS
+
+ use ExtUtils::Manifest qw(...funcs to import...);
+
+ mkmanifest();
+
+ my @missing_files = manicheck;
+ my @skipped = skipcheck;
+ my @extra_files = filecheck;
+ my($missing, $extra) = fullcheck;
+
+ my $found = manifind();
+
+ my $manifest = maniread();
+
+ manicopy($read,$target);
+
+ maniadd({$file => $comment, ...});
+
+
+=head1 DESCRIPTION
+
+=head2 Functions
+
+ExtUtils::Manifest exports no functions by default. The following are
+exported on request
+
+=over 4
+
+=item mkmanifest
+
+ mkmanifest();
+
+Writes all files in and below the current directory to your F<MANIFEST>.
+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>.
+
+=cut
+
+sub _sort {
+ return sort { lc $a cmp lc $b } @_;
+}
+
+sub mkmanifest {
+ my $manimiss = 0;
+ my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
+ $read = {} if $manimiss;
+ local *M;
+ my $bakbase = $MANIFEST;
+ $bakbase =~ s/\./_/g if $Is_VMS_nodot; # avoid double dots
+ rename $MANIFEST, "$bakbase.bak" unless $manimiss;
+ open M, "> $MANIFEST" or die "Could not open $MANIFEST: $!";
+ my $skip = maniskip();
+ my $found = manifind();
+ my($key,$val,$file,%all);
+ %all = (%$found, %$read);
+ $all{$MANIFEST} = ($Is_VMS_mode ? "$MANIFEST\t\t" : '') .
+ 'This list of files'
+ if $manimiss; # add new MANIFEST to known file list
+ foreach $file (_sort keys %all) {
+ if ($skip->($file)) {
+ # Policy: only remove files if they're listed in MANIFEST.SKIP.
+ # Don't remove files just because they don't exist.
+ warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
+ next;
+ }
+ if ($Verbose){
+ warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
+ }
+ my $text = $all{$file};
+ $file = _unmacify($file);
+ 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;
+}
+
+# Geez, shouldn't this use File::Spec or File::Basename or something?
+# Why so careful about dependencies?
+sub clean_up_filename {
+ my $filename = shift;
+ $filename =~ s|^\./||;
+ $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
+ if ( $Is_VMS ) {
+ $filename =~ s/\.$//; # trim trailing dot
+ $filename = VMS::Filespec::unixify($filename); # unescape spaces, etc.
+ if( $Is_VMS_lc ) {
+ $filename = lc($filename);
+ $filename = uc($filename) if $filename =~ /^MANIFEST(\.SKIP)?$/i;
+ }
+ }
+ return $filename;
+}
+
+
+=item manifind
+
+ my $found = manifind();
+
+returns a hash reference. The keys of the hash are the files found
+below the current directory.
+
+=cut
+
+sub manifind {
+ my $p = shift || {};
+ my $found = {};
+
+ my $wanted = sub {
+ my $name = clean_up_filename($File::Find::name);
+ warn "Debug: diskfile $name\n" if $Debug;
+ return if -d $_;
+ $found->{$name} = "";
+ };
+
+ # We have to use "$File::Find::dir/$_" in preprocess, because
+ # $File::Find::name is unavailable.
+ # Also, it's okay to use / here, because MANIFEST files use Unix-style
+ # paths.
+ find({wanted => $wanted},
+ $Is_MacOS ? ":" : ".");
+
+ return $found;
+}
+
+
+=item manicheck
+
+ my @missing_files = manicheck();
+
+checks if all the files within a C<MANIFEST> in the current directory
+really do exist. If C<MANIFEST> and the tree below the current
+directory are in sync it silently returns an empty list.
+Otherwise it returns a list of files which are listed in the
+C<MANIFEST> but missing from the directory, and by default also
+outputs these names to STDERR.
+
+=cut
+
+sub manicheck {
+ return _check_files();
+}
+
+
+=item filecheck
+
+ my @extra_files = filecheck();
+
+finds files below the current directory that are not mentioned in the
+C<MANIFEST> file. An optional file C<MANIFEST.SKIP> will be
+consulted. Any file matching a regular expression in such a file will
+not be reported as missing in the C<MANIFEST> file. The list of any
+extraneous files found is returned, and by default also reported to
+STDERR.
+
+=cut
+
+sub filecheck {
+ return _check_manifest();
+}
+
+
+=item fullcheck
+
+ my($missing, $extra) = fullcheck();
+
+does both a manicheck() and a filecheck(), returning then as two array
+refs.
+
+=cut
+
+sub fullcheck {
+ return [_check_files()], [_check_manifest()];
+}
+
+
+=item skipcheck
+
+ my @skipped = skipcheck();
+
+lists all the files that are skipped due to your C<MANIFEST.SKIP>
+file.
+
+=cut
+
+sub skipcheck {
+ my($p) = @_;
+ my $found = manifind();
+ my $matches = maniskip();
+
+ my @skipped = ();
+ foreach my $file (_sort keys %$found){
+ if (&$matches($file)){
+ warn "Skipping $file\n" unless $Quiet;
+ push @skipped, $file;
+ next;
+ }
+ }
+
+ return @skipped;
+}
+
+
+sub _check_files {
+ my $p = shift;
+ my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
+ my $read = maniread() || {};
+ my $found = manifind($p);
+
+ my(@missfile) = ();
+ foreach my $file (_sort keys %$read){
+ warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
+ if ($dosnames){
+ $file = lc $file;
+ $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
+ $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
+ }
+ unless ( exists $found->{$file} ) {
+ warn "No such file: $file\n" unless $Quiet;
+ push @missfile, $file;
+ }
+ }
+
+ return @missfile;
+}
+
+
+sub _check_manifest {
+ my($p) = @_;
+ my $read = maniread() || {};
+ my $found = manifind($p);
+ my $skip = maniskip();
+
+ my @missentry = ();
+ foreach my $file (_sort keys %$found){
+ next if $skip->($file);
+ warn "Debug: manicheck checking from disk $file\n" if $Debug;
+ unless ( exists $read->{$file} ) {
+ my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
+ warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
+ push @missentry, $file;
+ }
+ }
+
+ return @missentry;
+}
+
+
+=item maniread
+
+ my $manifest = maniread();
+ my $manifest = maniread($manifest_file);
+
+reads a named C<MANIFEST> file (defaults to C<MANIFEST> in the current
+directory) and returns a HASH reference with files being the keys and
+comments being the values of the HASH. Blank lines and lines which
+start with C<#> in the C<MANIFEST> file are discarded.
+
+=cut
+
+sub maniread {
+ my ($mfile) = @_;
+ $mfile ||= $MANIFEST;
+ my $read = {};
+ local *M;
+ unless (open M, "< $mfile"){
+ warn "Problem opening $mfile: $!";
+ return $read;
+ }
+ local $_;
+ while (<M>){
+ chomp;
+ next if /^\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) {
+ $file = _macify($file);
+ $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
+ }
+ elsif ($Is_VMS_mode) {
+ require File::Basename;
+ my($base,$dir) = File::Basename::fileparse($file);
+ # Resolve illegal file specifications in the same way as tar
+ if ($Is_VMS_nodot) {
+ $dir =~ tr/./_/;
+ my(@pieces) = split(/\./,$base);
+ if (@pieces > 2)
+ { $base = shift(@pieces) . '.' . join('_',@pieces); }
+ my $okfile = "$dir$base";
+ warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
+ $file = $okfile;
+ }
+ if( $Is_VMS_lc ) {
+ $file = lc($file);
+ $file = uc($file) if $file =~ /^MANIFEST(\.SKIP)?$/i;
+ }
+ }
+
+ $read->{$file} = $comment;
+ }
+ close M;
+ $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 {
+ my @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};
+ while (<M>){
+ chomp;
+ s/\r//;
+ $_ =~ qr{^\s*(?:(?:'([^\\']*(?:\\.[^\\']*)*)')|([^#\s]\S*))?(?:(?:\s*)|(?:\s+(.*?)\s*))$};
+ #my $comment = $3;
+ my $filename = $2;
+ if ( defined($1) ) {
+ $filename = $1;
+ $filename =~ s/\\(['\\])/$1/g;
+ }
+ next if (not defined($filename) or not $filename);
+ push @skip, _macify($filename);
+ }
+ close M;
+ return sub {0} unless (scalar @skip > 0);
+
+ my $opts = $Is_VMS_mode ? '(?i)' : '';
+
+ # Make sure each entry is isolated in its own parentheses, in case
+ # any of them contain alternations
+ my $regex = join '|', map "(?:$_)", @skip;
+
+ return sub { $_[0] =~ qr{$opts$regex} };
+}
+
+# checks for the special directives
+# #!include_default
+# #!include /path/to/some/manifest.skip
+# in a custom MANIFEST.SKIP for, for including
+# the content of, respectively, the default MANIFEST.SKIP
+# and an external manifest.skip file
+sub _check_mskip_directives {
+ my $mfile = shift;
+ local (*M, $_);
+ my @lines = ();
+ my $flag = 0;
+ unless (open M, "< $mfile") {
+ warn "Problem opening $mfile: $!";
+ return;
+ }
+ while (<M>) {
+ if (/^#!include_default\s*$/) {
+ if (my @default = _include_mskip_file()) {
+ push @lines, @default;
+ warn "Debug: Including default MANIFEST.SKIP\n" if $Debug;
+ $flag++;
+ }
+ next;
+ }
+ if (/^#!include\s+(.*)\s*$/) {
+ my $external_file = $1;
+ if (my @external = _include_mskip_file($external_file)) {
+ push @lines, @external;
+ warn "Debug: Including external $external_file\n" if $Debug;
+ $flag++;
+ }
+ next;
+ }
+ push @lines, $_;
+ }
+ close M;
+ return unless $flag;
+ my $bakbase = $mfile;
+ $bakbase =~ s/\./_/g if $Is_VMS_nodot; # avoid double dots
+ rename $mfile, "$bakbase.bak";
+ warn "Debug: Saving original $mfile as $bakbase.bak\n" if $Debug;
+ unless (open M, "> $mfile") {
+ warn "Problem opening $mfile: $!";
+ return;
+ }
+ print M $_ for (@lines);
+ close M;
+ return;
+}
+
+# returns an array containing the lines of an external
+# manifest.skip file, if given, or $DEFAULT_MSKIP
+sub _include_mskip_file {
+ my $mskip = shift || $DEFAULT_MSKIP;
+ unless (-f $mskip) {
+ warn qq{Included file "$mskip" not found - skipping};
+ return;
+ }
+ local (*M, $_);
+ unless (open M, "< $mskip") {
+ warn "Problem opening $mskip: $!";
+ return;
+ }
+ my @lines = ();
+ push @lines, "\n#!start included $mskip\n";
+ push @lines, $_ while <M>;
+ close M;
+ push @lines, "#!end included $mskip\n\n";
+ return @lines;
+}
+
+=item manicopy
+
+ manicopy(\%src, $dest_dir);
+ manicopy(\%src, $dest_dir, $how);
+
+Copies the files that are the keys in %src to the $dest_dir. %src is
+typically returned by the maniread() function.
+
+ manicopy( maniread(), $dest_dir );
+
+This function is useful for producing a directory tree identical to the
+intended distribution tree.
+
+$how can be used to specify a different methods of "copying". Valid
+values are C<cp>, which actually copies the files, C<ln> which creates
+hard links, and C<best> which mostly links the files but copies any
+symbolic link to make a tree without any symbolic link. C<cp> is the
+default.
+
+=cut
+
+sub manicopy {
+ my($read,$target,$how)=@_;
+ croak "manicopy() called without target argument" unless defined $target;
+ $how ||= 'cp';
+ require File::Path;
+ require File::Basename;
+
+ $target = VMS::Filespec::unixify($target) if $Is_VMS_mode;
+ File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
+ foreach my $file (keys %$read){
+ if ($Is_MacOS) {
+ if ($file =~ m!:!) {
+ my $dir = _maccat($target, $file);
+ $dir =~ s/[^:]+$//;
+ File::Path::mkpath($dir,1,0755);
+ }
+ cp_if_diff($file, _maccat($target, $file), $how);
+ } else {
+ $file = VMS::Filespec::unixify($file) if $Is_VMS_mode;
+ if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
+ my $dir = File::Basename::dirname($file);
+ $dir = VMS::Filespec::unixify($dir) if $Is_VMS_mode;
+ File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
+ }
+ cp_if_diff($file, "$target/$file", $how);
+ }
+ }
+}
+
+sub cp_if_diff {
+ my($from, $to, $how)=@_;
+ 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";
+ if (open(T,"< $to\0")) {
+ local $_;
+ while (<F>) { $diff++,last if $_ ne <T>; }
+ $diff++ unless eof(T);
+ close T;
+ }
+ else { $diff++; }
+ close F;
+ if ($diff) {
+ if (-e $to) {
+ unlink($to) or confess "unlink $to: $!";
+ }
+ STRICT_SWITCH: {
+ best($from,$to), last STRICT_SWITCH if $how eq 'best';
+ cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
+ ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
+ croak("ExtUtils::Manifest::cp_if_diff " .
+ "called with illegal how argument [$how]. " .
+ "Legal values are 'best', 'cp', and 'ln'.");
+ }
+ }
+}
+
+sub cp {
+ my ($srcFile, $dstFile) = @_;
+ my ($access,$mod) = (stat $srcFile)[8,9];
+
+ copy($srcFile,$dstFile);
+ utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
+ _manicopy_chmod($srcFile, $dstFile);
+}
+
+
+sub ln {
+ my ($srcFile, $dstFile) = @_;
+ # Fix-me - VMS can support links.
+ return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
+ link($srcFile, $dstFile);
+
+ unless( _manicopy_chmod($srcFile, $dstFile) ) {
+ unlink $dstFile;
+ return;
+ }
+ 1;
+}
+
+# 1) Strip off all group and world permissions.
+# 2) Let everyone read it.
+# 3) If the owner can execute it, everyone can.
+sub _manicopy_chmod {
+ my($srcFile, $dstFile) = @_;
+
+ my $perm = 0444 | (stat $srcFile)[2] & 0700;
+ chmod( $perm | ( $perm & 0100 ? 0111 : 0 ), $dstFile );
+}
+
+# Files that are often modified in the distdir. Don't hard link them.
+my @Exceptions = qw(MANIFEST META.yml SIGNATURE);
+sub best {
+ my ($srcFile, $dstFile) = @_;
+
+ my $is_exception = grep $srcFile =~ /$_/, @Exceptions;
+ if ($is_exception or !$Config{d_link} or -l $srcFile) {
+ cp($srcFile, $dstFile);
+ } else {
+ ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
+ }
+}
+
+sub _macify {
+ my($file) = @_;
+
+ return $file unless $Is_MacOS;
+
+ $file =~ s|^\./||;
+ if ($file =~ m|/|) {
+ $file =~ s|/+|:|g;
+ $file = ":$file";
+ }
+
+ $file;
+}
+
+sub _maccat {
+ my($f1, $f2) = @_;
+
+ return "$f1/$f2" unless $Is_MacOS;
+
+ $f1 .= ":$f2";
+ $f1 =~ s/([^:]:):/$1/g;
+ return $f1;
+}
+
+sub _unmacify {
+ my($file) = @_;
+
+ return $file unless $Is_MacOS;
+
+ $file =~ s|^:||;
+ $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
+ $file =~ y|:|/|;
+
+ $file;
+}
+
+
+=item maniadd
+
+ maniadd({ $file => $comment, ...});
+
+Adds an entry to an existing F<MANIFEST> unless its already there.
+
+$file will be normalized (ie. Unixified). B<UNIMPLEMENTED>
+
+=cut
+
+sub maniadd {
+ my($additions) = shift;
+
+ _normalize($additions);
+ _fix_manifest($MANIFEST);
+
+ my $manifest = maniread();
+ my @needed = grep { !exists $manifest->{$_} } keys %$additions;
+ return 1 unless @needed;
+
+ open(MANIFEST, ">>$MANIFEST") or
+ die "maniadd() could not open $MANIFEST: $!";
+
+ 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: $!";
+
+ return 1;
+}
+
+
+# Make sure this MANIFEST is consistently written with native
+# newlines and has a terminal newline.
+sub _fix_manifest {
+ my $manifest_file = shift;
+
+ open MANIFEST, $MANIFEST or die "Could not open $MANIFEST: $!";
+ local $/;
+ my @manifest = split /(\015\012|\012|\015)/, <MANIFEST>, -1;
+ close MANIFEST;
+ my $must_rewrite = "";
+ if ($manifest[-1] eq ""){
+ # sane case: last line had a terminal newline
+ pop @manifest;
+ for (my $i=1; $i<=$#manifest; $i+=2) {
+ unless ($manifest[$i] eq "\n") {
+ $must_rewrite = "not a newline at pos $i";
+ last;
+ }
+ }
+ } else {
+ $must_rewrite = "last line without newline";
+ }
+
+ if ( $must_rewrite ) {
+ 1 while unlink $MANIFEST; # avoid multiple versions on VMS
+ open MANIFEST, ">", $MANIFEST or die "(must_rewrite=$must_rewrite) Could not open >$MANIFEST: $!";
+ for (my $i=0; $i<=$#manifest; $i+=2) {
+ print MANIFEST "$manifest[$i]\n";
+ }
+ close MANIFEST or die "could not write $MANIFEST: $!";
+ }
+}
+
+
+# UNIMPLEMENTED
+sub _normalize {
+ return;
+}
+
+
+=back
+
+=head2 MANIFEST
+
+A list of files in the distribution, one file per line. The MANIFEST
+always uses Unix filepath conventions even if you're not on Unix. This
+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. 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
+
+The file MANIFEST.SKIP may contain regular expressions of files that
+should be ignored by mkmanifest() and filecheck(). The regular
+expressions should appear one on each line. Blank lines and lines
+which start with C<#> are skipped. Use C<\#> if you need a regular
+expression to start with a C<#>.
+
+For example:
+
+ # Version control files and dirs.
+ \bRCS\b
+ \bCVS\b
+ ,v$
+ \B\.svn\b
+
+ # Makemaker generated files and dirs.
+ ^MANIFEST\.
+ ^Makefile$
+ ^blib/
+ ^MakeMaker-\d
+
+ # Temp, old and emacs backup files.
+ ~$
+ \.old$
+ ^#.*#$
+ ^\.#
+
+If no MANIFEST.SKIP file is found, a default set of skips will be
+used, similar to the example above. If you want nothing skipped,
+simply make an empty MANIFEST.SKIP file.
+
+In one's own MANIFEST.SKIP file, certain directives
+can be used to include the contents of other MANIFEST.SKIP
+files. At present two such directives are recognized.
+
+=over 4
+
+=item #!include_default
+
+This inserts the contents of the default MANIFEST.SKIP file
+
+=item #!include /Path/to/another/manifest.skip
+
+This inserts the contents of the specified external file
+
+=back
+
+The included contents will be inserted into the MANIFEST.SKIP
+file in between I<#!start included /path/to/manifest.skip>
+and I<#!end included /path/to/manifest.skip> markers.
+The original MANIFEST.SKIP is saved as MANIFEST.SKIP.bak.
+
+=head2 EXPORT_OK
+
+C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
+C<&maniread>, and C<&manicopy> are exportable.
+
+=head2 GLOBAL VARIABLES
+
+C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
+results in both a different C<MANIFEST> and a different
+C<MANIFEST.SKIP> file. This is useful if you want to maintain
+different distributions for different audiences (say a user version
+and a developer version including RCS).
+
+C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
+all functions act silently.
+
+C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
+or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
+produced.
+
+=head1 DIAGNOSTICS
+
+All diagnostic output is sent to C<STDERR>.
+
+=over 4
+
+=item C<Not in MANIFEST:> I<file>
+
+is reported if a file is found which is not in C<MANIFEST>.
+
+=item C<Skipping> I<file>
+
+is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
+
+=item C<No such file:> I<file>
+
+is reported if a file mentioned in a C<MANIFEST> file does not
+exist.
+
+=item C<MANIFEST:> I<$!>
+
+is reported if C<MANIFEST> could not be opened.
+
+=item C<Added to MANIFEST:> I<file>
+
+is reported by mkmanifest() if $Verbose is set and a file is added
+to MANIFEST. $Verbose is set to 1 by default.
+
+=back
+
+=head1 ENVIRONMENT
+
+=over 4
+
+=item B<PERL_MM_MANIFEST_DEBUG>
+
+Turns on debugging
+
+=back
+
+=head1 SEE ALSO
+
+L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
+
+=head1 AUTHOR
+
+Andreas Koenig C<andreas.koenig@anima.de>
+
+Maintained by Michael G Schwern C<schwern@pobox.com> within the
+ExtUtils-MakeMaker package and, as a separate CPAN package, by
+Randy Kobes C<r.kobes@uwinnipeg.ca>.
+
+=cut
+
+1;
diff --git a/cpan/ExtUtils-Manifest/t/Manifest.t b/cpan/ExtUtils-Manifest/t/Manifest.t
new file mode 100644
index 0000000000..a6a89a2d65
--- /dev/null
+++ b/cpan/ExtUtils-Manifest/t/Manifest.t
@@ -0,0 +1,461 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ if( $ENV{PERL_CORE} ) {
+ chdir 't' if -d 't';
+ unshift @INC, '../lib';
+ }
+ else {
+ unshift @INC, 't/lib';
+ }
+}
+chdir 't';
+
+use strict;
+
+use Test::More tests => 96;
+use Cwd;
+
+use File::Spec;
+use File::Path;
+use File::Find;
+use Config;
+
+my $Is_VMS = $^O eq 'VMS';
+my $Is_VMS_noefs = $Is_VMS;
+if ($Is_VMS) {
+ my $vms_efs = 0;
+ if (eval 'require VMS::Feature') {
+ $vms_efs = VMS::Feature::current("efs_charset");
+ } else {
+ my $efs_charset = $ENV{'DECC$EFS_CHARSET'} || '';
+ $vms_efs = $efs_charset =~ /^[ET1]/i;
+ }
+ $Is_VMS_noefs = 0 if $vms_efs;
+}
+
+
+# We're going to be chdir'ing and modules are sometimes loaded on the
+# fly in this test, so we need an absolute @INC.
+@INC = map { File::Spec->rel2abs($_) } @INC;
+
+# keep track of everything added so it can all be deleted
+my %Files;
+sub add_file {
+ my ($file, $data) = @_;
+ $data ||= 'foo';
+ $file =~ s/ /^_/g if $Is_VMS_noefs; # escape spaces
+ 1 while unlink $file; # or else we'll get multiple versions on VMS
+ open( T, '> '.$file) or return;
+ print T $data;
+ close T;
+ return 0 unless -e $file; # exists under the name we gave it ?
+ ++$Files{$file};
+}
+
+sub read_manifest {
+ open( M, 'MANIFEST' ) or return;
+ chomp( my @files = <M> );
+ close M;
+ return @files;
+}
+
+sub catch_warning {
+ my $warn = '';
+ local $SIG{__WARN__} = sub { $warn .= $_[0] };
+ return join('', $_[0]->() ), $warn;
+}
+
+sub remove_dir {
+ ok( rmdir( $_ ), "remove $_ directory" ) for @_;
+}
+
+# use module, import functions
+BEGIN {
+ use_ok( 'ExtUtils::Manifest',
+ qw( mkmanifest manicheck filecheck fullcheck
+ maniread manicopy skipcheck maniadd maniskip) );
+}
+
+my $cwd = Cwd::getcwd();
+
+# Just in case any old files were lying around.
+rmtree('mantest');
+
+ok( mkdir( 'mantest', 0777 ), 'make mantest directory' );
+ok( chdir( 'mantest' ), 'chdir() to mantest' );
+ok( add_file('foo'), 'add a temporary file' );
+
+# This ensures the -x check for manicopy means something
+# Some platforms don't have chmod or an executable bit, in which case
+# this call will do nothing or fail, but on the platforms where chmod()
+# works, we test the executable bit is copied
+chmod( 0744, 'foo') if $Config{'chmod'};
+
+# there shouldn't be a MANIFEST there
+my ($res, $warn) = catch_warning( \&mkmanifest );
+# Canonize the order.
+$warn = join("", map { "$_|" }
+ sort { lc($a) cmp lc($b) } split /\r?\n/, $warn);
+is( $warn, "Added to MANIFEST: foo|Added to MANIFEST: MANIFEST|",
+ "mkmanifest() displayed its additions" );
+
+# and now you see it
+ok( -e 'MANIFEST', 'create MANIFEST file' );
+
+my @list = read_manifest();
+is( @list, 2, 'check files in MANIFEST' );
+ok( ! ExtUtils::Manifest::filecheck(), 'no additional files in directory' );
+
+# after adding bar, the MANIFEST is out of date
+ok( add_file( 'bar' ), 'add another file' );
+ok( ! manicheck(), 'MANIFEST now out of sync' );
+
+# it reports that bar has been added and throws a warning
+($res, $warn) = catch_warning( \&filecheck );
+
+like( $warn, qr/^Not in MANIFEST: bar/, 'warning that bar has been added' );
+is( $res, 'bar', 'bar reported as new' );
+
+# now quiet the warning that bar was added and test again
+($res, $warn) = do { local $ExtUtils::Manifest::Quiet = 1;
+ catch_warning( \&skipcheck )
+ };
+is( $warn, '', 'disabled warnings' );
+
+# add a skip file with a rule to skip itself (and the nonexistent glob '*baz*')
+add_file( 'MANIFEST.SKIP', "baz\n.SKIP" );
+
+# this'll skip the new file
+($res, $warn) = catch_warning( \&skipcheck );
+like( $warn, qr/^Skipping MANIFEST\.SKIP/i, 'got skipping warning' );
+
+my @skipped;
+catch_warning( sub {
+ @skipped = skipcheck()
+});
+
+is( join( ' ', @skipped ), 'MANIFEST.SKIP', 'listed skipped files' );
+
+{
+ local $ExtUtils::Manifest::Quiet = 1;
+ is( join(' ', filecheck() ), 'bar', 'listing skipped with filecheck()' );
+}
+
+# add a subdirectory and a file there that should be found
+ok( mkdir( 'moretest', 0777 ), 'created moretest directory' );
+add_file( File::Spec->catfile('moretest', 'quux'), 'quux' );
+ok( exists( ExtUtils::Manifest::manifind()->{'moretest/quux'} ),
+ "manifind found moretest/quux" );
+
+# only MANIFEST and foo are in the manifest
+$_ = 'foo';
+my $files = maniread();
+is( keys %$files, 2, 'two files found' );
+is( join(' ', sort { lc($a) cmp lc($b) } keys %$files), 'foo MANIFEST',
+ 'both files found' );
+is( $_, 'foo', q{maniread() doesn't clobber $_} );
+
+ok( mkdir( 'copy', 0777 ), 'made copy directory' );
+
+# Check that manicopy copies files.
+manicopy( $files, 'copy', 'cp' );
+my @copies = ();
+find( sub { push @copies, $_ if -f }, 'copy' );
+@copies = map { s/\.$//; $_ } @copies if $Is_VMS; # VMS likes to put dots on
+ # the end of files.
+# Have to compare insensitively for non-case preserving VMS
+is_deeply( [sort map { lc } @copies], [sort map { lc } keys %$files] );
+
+# cp would leave files readonly, so check permissions.
+foreach my $orig (@copies) {
+ my $copy = "copy/$orig";
+ ok( -r $copy, "$copy: must be readable" );
+ is( -w $copy, -w $orig, " writable if original was" );
+ is( -x $copy, -x $orig, " executable if original was" );
+}
+rmtree('copy');
+
+
+# poison the manifest, and add a comment that should be reported
+add_file( 'MANIFEST', 'none #none' );
+is( ExtUtils::Manifest::maniread()->{none}, '#none',
+ 'maniread found comment' );
+
+ok( mkdir( 'copy', 0777 ), 'made copy directory' );
+$files = maniread();
+eval { (undef, $warn) = catch_warning( sub {
+ manicopy( $files, 'copy', 'cp' ) })
+};
+
+# a newline comes through, so get rid of it
+chomp($warn);
+# 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
+{
+ local $ExtUtils::Manifest::MANIFEST = 'albatross';
+ ($res, $warn) = catch_warning( \&mkmanifest );
+ like( $warn, qr/Added to albatross: /, 'using a new manifest file' );
+
+ # add the new file to the list of files to be deleted
+ $Files{'albatross'}++;
+}
+
+
+# Make sure MANIFEST.SKIP is using complete relative paths
+add_file( 'MANIFEST.SKIP' => "^moretest/q\n" );
+
+# This'll skip moretest/quux
+($res, $warn) = catch_warning( \&skipcheck );
+like( $warn, qr{^Skipping moretest/quux$}i, 'got skipping warning again' );
+
+
+# There was a bug where entries in MANIFEST would be blotted out
+# by MANIFEST.SKIP rules.
+add_file( 'MANIFEST.SKIP' => 'foo' );
+add_file( 'MANIFEST' => "foobar\n" );
+add_file( 'foobar' => '123' );
+($res, $warn) = catch_warning( \&manicheck );
+is( $res, '', 'MANIFEST overrides MANIFEST.SKIP' );
+is( $warn, '', 'MANIFEST overrides MANIFEST.SKIP, no warnings' );
+
+$files = maniread;
+ok( !$files->{wibble}, 'MANIFEST in good state' );
+maniadd({ wibble => undef });
+maniadd({ yarrow => "hock" });
+$files = maniread;
+is( $files->{wibble}, '', 'maniadd() with undef comment' );
+is( $files->{yarrow}, 'hock',' with comment' );
+is( $files->{foobar}, '', ' preserved old entries' );
+
+{
+ # EOL normalization in maniadd()
+
+ # move manifest away:
+ rename "MANIFEST", "MANIFEST.bak" or die "Could not rename MANIFEST to MANIFEST.bak: $!";
+ my $prev_maniaddresult;
+ my @eol = ("\012","\015","\015\012");
+ # for all line-endings:
+ for my $i (0..$#eol) {
+ my $eol = $eol[$i];
+ # cp the backup of the manifest to MANIFEST, line-endings adjusted
+ my $content = do { local $/; open my $fh, "MANIFEST.bak" or die; <$fh> };
+ SPLITTER: for my $eol2 (@eol) {
+ if ( index($content, $eol2) > -1 ) {
+ my @lines = split /$eol2/, $content;
+ pop @lines while $lines[-1] eq "";
+ open my $fh, ">", "MANIFEST" or die "Could not open >MANIFEST: $!";
+ print $fh map { "$_$eol" } @lines;
+ close $fh or die "Could not close: $!";
+ last SPLITTER;
+ }
+ }
+ # try maniadd
+ maniadd({eoltest => "end of line normalization test"});
+ # slurp result and compare to previous result
+ my $maniaddresult = do { local $/; open my $fh, "MANIFEST" or die; <$fh> };
+ if ($prev_maniaddresult) {
+ if ( $maniaddresult eq $prev_maniaddresult ) {
+ pass "normalization success with i=$i";
+ } else {
+ require Data::Dumper;
+ no warnings "once";
+ local $Data::Dumper::Useqq = 1;
+ local $Data::Dumper::Terse = 1;
+ is Data::Dumper::Dumper($maniaddresult), Data::Dumper::Dumper($prev_maniaddresult), "eol normalization failed with i=$i";
+ }
+ }
+ $prev_maniaddresult = $maniaddresult;
+ }
+ # move backup over MANIFEST
+ rename "MANIFEST.bak", "MANIFEST" or die "Could not rename MANIFEST.bak to MANIFEST: $!";
+}
+
+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");
+ 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' =>
+ "albatross\n#!include $skip\n#!include_default");
+ my ($res, $warn) = catch_warning( \&skipcheck );
+ for (qw(albatross foo foobar mymanifest.skip mydefault.skip)) {
+ 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' );
+ ok( exists $files->{bar}, 'bar included in MANIFEST' );
+ ok( ! exists $files->{foobar}, 'foobar excluded via mymanifest.skip' );
+ ok( ! exists $files->{foo}, 'foo excluded via mymanifest.skip' );
+ ok( ! exists $files->{'mymanifest.skip'},
+ '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_noefs ? '_' : '.';
+ $Files{"$_.bak"}++ for ('MANIFEST', "MANIFEST${extsep}SKIP");
+}
+
+add_file('MANIFEST' => 'Makefile.PL');
+maniadd({ foo => 'bar' });
+$files = maniread;
+# VMS downcases the MANIFEST. We normalize it here to match.
+%$files = map { (lc $_ => $files->{$_}) } keys %$files;
+my %expect = ( 'makefile.pl' => '',
+ 'foo' => 'bar'
+ );
+is_deeply( $files, \%expect, 'maniadd() vs MANIFEST without trailing newline');
+
+#add_file('MANIFEST' => 'Makefile.PL');
+#maniadd({ foo => 'bar' });
+
+SKIP: {
+ chmod( 0400, 'MANIFEST' );
+ skip "Can't make MANIFEST read-only", 2 if -w 'MANIFEST';
+
+ eval {
+ maniadd({ 'foo' => 'bar' });
+ };
+ is( $@, '', "maniadd() won't open MANIFEST if it doesn't need to" );
+
+ eval {
+ maniadd({ 'grrrwoof' => 'yippie' });
+ };
+ like( $@, qr/^\Qmaniadd() could not open MANIFEST:\E/,
+ "maniadd() dies if it can't open the MANIFEST" );
+
+ chmod( 0600, 'MANIFEST' );
+}
+
+
+END {
+ is( unlink( keys %Files ), keys %Files, 'remove all added files' );
+ for my $file ( keys %Files ) { 1 while unlink $file; } # all versions
+ remove_dir( 'moretest', 'copy' );
+
+ # now get rid of the parent directory
+ ok( chdir( $cwd ), 'return to parent directory' );
+ remove_dir( 'mantest' );
+}