1 package ExtUtils::Manifest;
12 use vars qw($VERSION @ISA @EXPORT_OK
14 $Debug $Verbose $Quiet $MANIFEST $DEFAULT_MSKIP);
18 @EXPORT_OK = qw(mkmanifest
19 manicheck filecheck fullcheck skipcheck
20 manifind maniread manicopy maniadd
23 $Is_MacOS = $^O eq 'MacOS';
24 $Is_VMS = $^O eq 'VMS';
25 require VMS::Filespec if $Is_VMS;
27 $Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
28 $Verbose = defined $ENV{PERL_MM_MANIFEST_VERBOSE} ?
29 $ENV{PERL_MM_MANIFEST_VERBOSE} : 1;
31 $MANIFEST = 'MANIFEST';
33 $DEFAULT_MSKIP = File::Spec->catfile( dirname(__FILE__), "$MANIFEST.SKIP" );
38 ExtUtils::Manifest - utilities to write and check a MANIFEST file
42 use ExtUtils::Manifest qw(...funcs to import...);
46 my @missing_files = manicheck;
47 my @skipped = skipcheck;
48 my @extra_files = filecheck;
49 my($missing, $extra) = fullcheck;
51 my $found = manifind();
53 my $manifest = maniread();
55 manicopy($read,$target);
57 maniadd({$file => $comment, ...});
64 ExtUtils::Manifest exports no functions by default. The following are
73 Writes all files in and below the current directory to your F<MANIFEST>.
78 All files that match any regular expression in a file F<MANIFEST.SKIP>
79 (if it exists) are ignored.
81 Any existing F<MANIFEST> file will be saved as F<MANIFEST.bak>. Lines
82 from the old F<MANIFEST> file is preserved, including any comments
83 that are found in the existing F<MANIFEST> file in the new one.
88 return sort { lc $a cmp lc $b } @_;
93 my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
94 $read = {} if $manimiss;
96 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
97 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
98 my $skip = _maniskip();
99 my $found = manifind();
100 my($key,$val,$file,%all);
101 %all = (%$found, %$read);
102 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
103 if $manimiss; # add new MANIFEST to known file list
104 foreach $file (_sort keys %all) {
105 if ($skip->($file)) {
106 # Policy: only remove files if they're listed in MANIFEST.SKIP.
107 # Don't remove files just because they don't exist.
108 warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
112 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
114 my $text = $all{$file};
115 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
116 $file = _unmacify($file);
117 my $tabs = (5 - (length($file)+1)/8);
118 $tabs = 1 if $tabs < 1;
119 $tabs = 0 unless $text;
120 print M $file, "\t" x $tabs, $text, "\n";
125 # Geez, shouldn't this use File::Spec or File::Basename or something?
126 # Why so careful about dependencies?
127 sub clean_up_filename {
128 my $filename = shift;
129 $filename =~ s|^\./||;
130 $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
137 my $found = manifind();
139 returns a hash reference. The keys of the hash are the files found
140 below the current directory.
149 my $name = clean_up_filename($File::Find::name);
150 warn "Debug: diskfile $name\n" if $Debug;
154 $name =~ s#(.*)\.$#\L$1#;
155 $name = uc($name) if $name =~ /^MANIFEST(\.SKIP)?$/i;
157 $found->{$name} = "";
160 # We have to use "$File::Find::dir/$_" in preprocess, because
161 # $File::Find::name is unavailable.
162 # Also, it's okay to use / here, because MANIFEST files use Unix-style
164 find({wanted => $wanted},
165 $Is_MacOS ? ":" : ".");
173 my @missing_files = manicheck();
175 checks if all the files within a C<MANIFEST> in the current directory
176 really do exist. If C<MANIFEST> and the tree below the current
177 directory are in sync it silently returns an empty list.
178 Otherwise it returns a list of files which are listed in the
179 C<MANIFEST> but missing from the directory, and by default also
180 outputs these names to STDERR.
185 return _check_files();
191 my @extra_files = filecheck();
193 finds files below the current directory that are not mentioned in the
194 C<MANIFEST> file. An optional file C<MANIFEST.SKIP> will be
195 consulted. Any file matching a regular expression in such a file will
196 not be reported as missing in the C<MANIFEST> file. The list of any
197 extraneous files found is returned, and by default also reported to
203 return _check_manifest();
209 my($missing, $extra) = fullcheck();
211 does both a manicheck() and a filecheck(), returning then as two array
217 return [_check_files()], [_check_manifest()];
223 my @skipped = skipcheck();
225 lists all the files that are skipped due to your C<MANIFEST.SKIP>
232 my $found = manifind();
233 my $matches = _maniskip();
236 foreach my $file (_sort keys %$found){
237 if (&$matches($file)){
238 warn "Skipping $file\n";
239 push @skipped, $file;
250 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
251 my $read = maniread() || {};
252 my $found = manifind($p);
255 foreach my $file (_sort keys %$read){
256 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
259 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
260 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
262 unless ( exists $found->{$file} ) {
263 warn "No such file: $file\n" unless $Quiet;
264 push @missfile, $file;
272 sub _check_manifest {
274 my $read = maniread() || {};
275 my $found = manifind($p);
276 my $skip = _maniskip();
279 foreach my $file (_sort keys %$found){
280 next if $skip->($file);
281 warn "Debug: manicheck checking from disk $file\n" if $Debug;
282 unless ( exists $read->{$file} ) {
283 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
284 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
285 push @missentry, $file;
295 my $manifest = maniread();
296 my $manifest = maniread($manifest_file);
298 reads a named C<MANIFEST> file (defaults to C<MANIFEST> in the current
299 directory) and returns a HASH reference with files being the keys and
300 comments being the values of the HASH. Blank lines and lines which
301 start with C<#> in the C<MANIFEST> file are discarded.
307 $mfile ||= $MANIFEST;
310 unless (open M, $mfile){
319 my($file, $comment) = /^(\S+)\s*(.*)/;
323 $file = _macify($file);
324 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
327 require File::Basename;
328 my($base,$dir) = File::Basename::fileparse($file);
329 # Resolve illegal file specifications in the same way as tar
331 my(@pieces) = split(/\./,$base);
332 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
333 my $okfile = "$dir$base";
334 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
336 $file = lc($file) unless $file =~ /^MANIFEST(\.SKIP)?$/;
339 $read->{$file} = $comment;
345 # returns an anonymous sub that decides if an argument matches
348 my $mfile = "$MANIFEST.SKIP";
350 open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
356 push @skip, _macify($_);
359 return sub {0} unless (scalar @skip > 0);
361 my $opts = $Is_VMS ? '(?i)' : '';
363 # Make sure each entry is isolated in its own parentheses, in case
364 # any of them contain alternations
365 my $regex = join '|', map "(?:$_)", @skip;
367 return sub { $_[0] =~ qr{$opts$regex} };
372 manicopy(\%src, $dest_dir);
373 manicopy(\%src, $dest_dir, $how);
375 Copies the files that are the keys in %src to the $dest_dir. %src is
376 typically returned by the maniread() function.
378 manicopy( maniread(), $dest_dir );
380 This function is useful for producing a directory tree identical to the
381 intended distribution tree.
383 $how can be used to specify a different methods of "copying". Valid
384 values are C<cp>, which actually copies the files, C<ln> which creates
385 hard links, and C<best> which mostly links the files but copies any
386 symbolic link to make a tree without any symbolic link. C<cp> is the
392 my($read,$target,$how)=@_;
393 croak "manicopy() called without target argument" unless defined $target;
396 require File::Basename;
398 $target = VMS::Filespec::unixify($target) if $Is_VMS;
399 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
400 foreach my $file (keys %$read){
403 my $dir = _maccat($target, $file);
405 File::Path::mkpath($dir,1,0755);
407 cp_if_diff($file, _maccat($target, $file), $how);
409 $file = VMS::Filespec::unixify($file) if $Is_VMS;
410 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
411 my $dir = File::Basename::dirname($file);
412 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
413 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
415 cp_if_diff($file, "$target/$file", $how);
421 my($from, $to, $how)=@_;
422 -f $from or carp "$0: $from not found";
425 open(F,"< $from\0") or die "Can't read $from: $!\n";
426 if (open(T,"< $to\0")) {
428 while (<F>) { $diff++,last if $_ ne <T>; }
429 $diff++ unless eof(T);
436 unlink($to) or confess "unlink $to: $!";
439 best($from,$to), last STRICT_SWITCH if $how eq 'best';
440 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
441 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
442 croak("ExtUtils::Manifest::cp_if_diff " .
443 "called with illegal how argument [$how]. " .
444 "Legal values are 'best', 'cp', and 'ln'.");
450 my ($srcFile, $dstFile) = @_;
451 my ($access,$mod) = (stat $srcFile)[8,9];
453 copy($srcFile,$dstFile);
454 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
455 _manicopy_chmod($dstFile);
460 my ($srcFile, $dstFile) = @_;
461 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
462 link($srcFile, $dstFile);
464 unless( _manicopy_chmod($dstFile) ) {
471 # 1) Strip off all group and world permissions.
472 # 2) Let everyone read it.
473 # 3) If the owner can execute it, everyone can.
474 sub _manicopy_chmod {
477 my $perm = 0444 | (stat $file)[2] & 0700;
478 chmod( $perm | ( $perm & 0100 ? 0111 : 0 ), $file );
481 # Files that are often modified in the distdir. Don't hard link them.
482 my @Exceptions = qw(MANIFEST META.yml SIGNATURE);
484 my ($srcFile, $dstFile) = @_;
486 my $is_exception = grep $srcFile =~ /$_/, @Exceptions;
487 if ($is_exception or !$Config{d_link} or -l $srcFile) {
488 cp($srcFile, $dstFile);
490 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
497 return $file unless $Is_MacOS;
511 return "$f1/$f2" unless $Is_MacOS;
514 $f1 =~ s/([^:]:):/$1/g;
521 return $file unless $Is_MacOS;
524 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
533 maniadd({ $file => $comment, ...});
535 Adds an entry to an existing F<MANIFEST> unless its already there.
537 $file will be normalized (ie. Unixified). B<UNIMPLEMENTED>
542 my($additions) = shift;
544 _normalize($additions);
545 _fix_manifest($MANIFEST);
547 my $manifest = maniread();
548 my @needed = grep { !exists $manifest->{$_} } keys %$additions;
549 return 1 unless @needed;
551 open(MANIFEST, ">>$MANIFEST") or
552 die "maniadd() could not open $MANIFEST: $!";
554 foreach my $file (_sort @needed) {
555 my $comment = $additions->{$file} || '';
556 printf MANIFEST "%-40s %s\n", $file, $comment;
558 close MANIFEST or die "Error closing $MANIFEST: $!";
564 # Sometimes MANIFESTs are missing a trailing newline. Fix this.
566 my $manifest_file = shift;
568 open MANIFEST, $MANIFEST or die "Could not open $MANIFEST: $!";
570 # Yes, we should be using seek(), but I'd like to avoid loading POSIX
572 my @manifest = <MANIFEST>;
575 unless( $manifest[-1] =~ /\n\z/ ) {
576 open MANIFEST, ">>$MANIFEST" or die "Could not open $MANIFEST: $!";
593 A list of files in the distribution, one file per line. The MANIFEST
594 always uses Unix filepath conventions even if you're not on Unix. This
595 means F<foo/bar> style not F<foo\bar>.
597 Anything between white space and an end of line within a C<MANIFEST>
598 file is considered to be a comment. Any line beginning with # is also
603 some/other/file comment about some/file
608 The file MANIFEST.SKIP may contain regular expressions of files that
609 should be ignored by mkmanifest() and filecheck(). The regular
610 expressions should appear one on each line. Blank lines and lines
611 which start with C<#> are skipped. Use C<\#> if you need a regular
612 expression to start with a C<#>.
616 # Version control files and dirs.
622 # Makemaker generated files and dirs.
628 # Temp, old and emacs backup files.
634 If no MANIFEST.SKIP file is found, a default set of skips will be
635 used, similar to the example above. If you want nothing skipped,
636 simply make an empty MANIFEST.SKIP file.
641 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
642 C<&maniread>, and C<&manicopy> are exportable.
644 =head2 GLOBAL VARIABLES
646 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
647 results in both a different C<MANIFEST> and a different
648 C<MANIFEST.SKIP> file. This is useful if you want to maintain
649 different distributions for different audiences (say a user version
650 and a developer version including RCS).
652 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
653 all functions act silently.
655 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
656 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
661 All diagnostic output is sent to C<STDERR>.
665 =item C<Not in MANIFEST:> I<file>
667 is reported if a file is found which is not in C<MANIFEST>.
669 =item C<Skipping> I<file>
671 is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
673 =item C<No such file:> I<file>
675 is reported if a file mentioned in a C<MANIFEST> file does not
678 =item C<MANIFEST:> I<$!>
680 is reported if C<MANIFEST> could not be opened.
682 =item C<Added to MANIFEST:> I<file>
684 is reported by mkmanifest() if $Verbose is set and a file is added
685 to MANIFEST. $Verbose is set to 1 by default.
693 =item B<PERL_MM_MANIFEST_DEBUG>
701 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
705 Andreas Koenig C<andreas.koenig@anima.de>
707 Maintained by Michael G Schwern C<schwern@pobox.com> within the
708 ExtUtils-MakeMaker package and, as a separate CPAN package, by
709 Randy Kobes C<r.kobes@uwinnipeg.ca>.