require Exporter;
use Config;
-use File::Find;
+use File::Basename;
use File::Copy 'copy';
+use File::Find;
use File::Spec;
use Carp;
use strict;
$Is_MacOS $Is_VMS
$Debug $Verbose $Quiet $MANIFEST $DEFAULT_MSKIP);
-$VERSION = 1.42;
+$VERSION = '1.51_01';
@ISA=('Exporter');
@EXPORT_OK = qw(mkmanifest
manicheck filecheck fullcheck skipcheck
$Quiet = 0;
$MANIFEST = 'MANIFEST';
-my $Filename = __FILE__;
-$DEFAULT_MSKIP = (File::Spec->splitpath($Filename))[1].
- "$MANIFEST.SKIP";
+$DEFAULT_MSKIP = File::Spec->catfile( dirname(__FILE__), "$MANIFEST.SKIP" );
=head1 NAME
my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
$read = {} if $manimiss;
local *M;
- rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
+ 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();
my $found = manifind();
warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
}
my $text = $all{$file};
- ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
$file = _unmacify($file);
my $tabs = (5 - (length($file)+1)/8);
$tabs = 1 if $tabs < 1;
my $read = {};
local *M;
unless (open M, $mfile){
- warn "$mfile: $!";
+ warn "Problem opening $mfile: $!";
return $read;
}
local $_;
sub _maniskip {
my @skip ;
my $mfile = "$MANIFEST.SKIP";
- local(*M,$_);
+ _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//;
next if /^#/;
next if /^\s*$/;
push @skip, _macify($_);
}
close M;
+ return sub {0} unless (scalar @skip > 0);
+
my $opts = $Is_VMS ? '(?i)' : '';
# Make sure each entry is isolated in its own parentheses, in case
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; # 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);
+ 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.
-copies the files that are the keys in the HASH I<%$src> to the
-$dest_dir. The HASH reference $read is typically returned by the
-maniread() function. This function is useful for producing a directory
-tree identical to the intended distribution tree. The third parameter
-$how can be used to specify a different methods of "copying". Valid
+$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. Best is the
+symbolic link to make a tree without any symbolic link. C<cp> is the
default.
=cut
if (-e $to) {
unlink($to) or confess "unlink $to: $!";
}
- STRICT_SWITCH: {
+ 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';
sub cp {
my ($srcFile, $dstFile) = @_;
- my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
+ my ($access,$mod) = (stat $srcFile)[8,9];
+
copy($srcFile,$dstFile);
utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
- # chmod a+rX-w,go-w
- chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile )
- unless ($^O eq 'MacOS');
+ _manicopy_chmod($srcFile, $dstFile);
}
+
sub ln {
my ($srcFile, $dstFile) = @_;
return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
link($srcFile, $dstFile);
- # chmod a+r,go-w+X (except "X" only applies to u=x)
- local($_) = $dstFile;
- my $mode= 0444 | (stat)[2] & 0700;
- if (! chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ )) {
+ unless( _manicopy_chmod($srcFile, $dstFile) ) {
unlink $dstFile;
return;
}
1;
}
-unless (defined $Config{d_link}) {
- # Really cool fix from Ilya :)
- local $SIG{__WARN__} = sub {
- warn @_ unless $_[0] =~ /^Subroutine .* redefined/;
- };
- *ln = \&cp;
-}
-
-
+# 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) = @_;
- if (-l $srcFile) {
+
+ 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);
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;
my($file) = @_;
return $file unless $Is_MacOS;
-
+
$file =~ s|^:||;
$file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
$file =~ y|:|/|;
-
+
$file;
}
close MANIFEST;
}
}
-
+
# UNIMPLEMENTED
sub _normalize {
=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. Filenames and comments are
-separated by one or more TAB characters in the output.
+file is considered to be a comment. Any line beginning with # is also
+a comment.
+
+ # this a comment
+ some/file
+ some/other/file comment about some/file
=head2 MANIFEST.SKIP
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 sharp character. A typical example:
+expression to start with a C<#>.
+
+For example:
# Version control files and dirs.
\bRCS\b
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
=head1 AUTHOR
-Andreas Koenig <F<andreas.koenig@anima.de>>
+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