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 my $bakbase = $MANIFEST;
97 $bakbase =~ s/\./_/g if $Is_VMS; # avoid double dots
98 rename $MANIFEST, "$bakbase.bak" unless $manimiss;
99 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
100 my $skip = _maniskip();
101 my $found = manifind();
102 my($key,$val,$file,%all);
103 %all = (%$found, %$read);
104 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
105 if $manimiss; # add new MANIFEST to known file list
106 foreach $file (_sort keys %all) {
107 if ($skip->($file)) {
108 # Policy: only remove files if they're listed in MANIFEST.SKIP.
109 # Don't remove files just because they don't exist.
110 warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
114 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
116 my $text = $all{$file};
117 $file = _unmacify($file);
118 my $tabs = (5 - (length($file)+1)/8);
119 $tabs = 1 if $tabs < 1;
120 $tabs = 0 unless $text;
121 print M $file, "\t" x $tabs, $text, "\n";
126 # Geez, shouldn't this use File::Spec or File::Basename or something?
127 # Why so careful about dependencies?
128 sub clean_up_filename {
129 my $filename = shift;
130 $filename =~ s|^\./||;
131 $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
138 my $found = manifind();
140 returns a hash reference. The keys of the hash are the files found
141 below the current directory.
150 my $name = clean_up_filename($File::Find::name);
151 warn "Debug: diskfile $name\n" if $Debug;
155 $name =~ s#(.*)\.$#\L$1#;
156 $name = uc($name) if $name =~ /^MANIFEST(\.SKIP)?$/i;
158 $found->{$name} = "";
161 # We have to use "$File::Find::dir/$_" in preprocess, because
162 # $File::Find::name is unavailable.
163 # Also, it's okay to use / here, because MANIFEST files use Unix-style
165 find({wanted => $wanted},
166 $Is_MacOS ? ":" : ".");
174 my @missing_files = manicheck();
176 checks if all the files within a C<MANIFEST> in the current directory
177 really do exist. If C<MANIFEST> and the tree below the current
178 directory are in sync it silently returns an empty list.
179 Otherwise it returns a list of files which are listed in the
180 C<MANIFEST> but missing from the directory, and by default also
181 outputs these names to STDERR.
186 return _check_files();
192 my @extra_files = filecheck();
194 finds files below the current directory that are not mentioned in the
195 C<MANIFEST> file. An optional file C<MANIFEST.SKIP> will be
196 consulted. Any file matching a regular expression in such a file will
197 not be reported as missing in the C<MANIFEST> file. The list of any
198 extraneous files found is returned, and by default also reported to
204 return _check_manifest();
210 my($missing, $extra) = fullcheck();
212 does both a manicheck() and a filecheck(), returning then as two array
218 return [_check_files()], [_check_manifest()];
224 my @skipped = skipcheck();
226 lists all the files that are skipped due to your C<MANIFEST.SKIP>
233 my $found = manifind();
234 my $matches = _maniskip();
237 foreach my $file (_sort keys %$found){
238 if (&$matches($file)){
239 warn "Skipping $file\n";
240 push @skipped, $file;
251 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
252 my $read = maniread() || {};
253 my $found = manifind($p);
256 foreach my $file (_sort keys %$read){
257 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
260 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
261 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
263 unless ( exists $found->{$file} ) {
264 warn "No such file: $file\n" unless $Quiet;
265 push @missfile, $file;
273 sub _check_manifest {
275 my $read = maniread() || {};
276 my $found = manifind($p);
277 my $skip = _maniskip();
280 foreach my $file (_sort keys %$found){
281 next if $skip->($file);
282 warn "Debug: manicheck checking from disk $file\n" if $Debug;
283 unless ( exists $read->{$file} ) {
284 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
285 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
286 push @missentry, $file;
296 my $manifest = maniread();
297 my $manifest = maniread($manifest_file);
299 reads a named C<MANIFEST> file (defaults to C<MANIFEST> in the current
300 directory) and returns a HASH reference with files being the keys and
301 comments being the values of the HASH. Blank lines and lines which
302 start with C<#> in the C<MANIFEST> file are discarded.
308 $mfile ||= $MANIFEST;
311 unless (open M, $mfile){
312 warn "Problem opening $mfile: $!";
320 my($file, $comment) = /^(\S+)\s*(.*)/;
324 $file = _macify($file);
325 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
328 require File::Basename;
329 my($base,$dir) = File::Basename::fileparse($file);
330 # Resolve illegal file specifications in the same way as tar
332 my(@pieces) = split(/\./,$base);
333 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
334 my $okfile = "$dir$base";
335 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
337 $file = lc($file) unless $file =~ /^MANIFEST(\.SKIP)?$/;
340 $read->{$file} = $comment;
346 # returns an anonymous sub that decides if an argument matches
349 my $mfile = "$MANIFEST.SKIP";
350 _check_mskip_directives($mfile) if -f $mfile;
352 open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
358 push @skip, _macify($_);
361 return sub {0} unless (scalar @skip > 0);
363 my $opts = $Is_VMS ? '(?i)' : '';
365 # Make sure each entry is isolated in its own parentheses, in case
366 # any of them contain alternations
367 my $regex = join '|', map "(?:$_)", @skip;
369 return sub { $_[0] =~ qr{$opts$regex} };
372 # checks for the special directives
374 # #!include /path/to/some/manifest.skip
375 # in a custom MANIFEST.SKIP for, for including
376 # the content of, respectively, the default MANIFEST.SKIP
377 # and an external manifest.skip file
378 sub _check_mskip_directives {
383 unless (open M, $mfile) {
384 warn "Problem opening $mfile: $!";
388 if (/^#!include_default\s*$/) {
389 if (my @default = _include_mskip_file()) {
390 push @lines, @default;
391 warn "Debug: Including default MANIFEST.SKIP\n" if $Debug;
396 if (/^#!include\s+(.*)\s*$/) {
397 my $external_file = $1;
398 if (my @external = _include_mskip_file($external_file)) {
399 push @lines, @external;
400 warn "Debug: Including external $external_file\n" if $Debug;
409 my $bakbase = $mfile;
410 $bakbase =~ s/\./_/g if $Is_VMS; # avoid double dots
411 rename $mfile, "$bakbase.bak";
412 warn "Debug: Saving original $mfile as $bakbase.bak\n" if $Debug;
413 unless (open M, ">$mfile") {
414 warn "Problem opening $mfile: $!";
417 print M $_ for (@lines);
422 # returns an array containing the lines of an external
423 # manifest.skip file, if given, or $DEFAULT_MSKIP
424 sub _include_mskip_file {
425 my $mskip = shift || $DEFAULT_MSKIP;
427 warn qq{Included file "$mskip" not found - skipping};
431 unless (open M, $mskip) {
432 warn "Problem opening $mskip: $!";
436 push @lines, "\n#!start included $mskip\n";
437 push @lines, $_ while <M>;
439 push @lines, "#!end included $mskip\n\n";
445 manicopy(\%src, $dest_dir);
446 manicopy(\%src, $dest_dir, $how);
448 Copies the files that are the keys in %src to the $dest_dir. %src is
449 typically returned by the maniread() function.
451 manicopy( maniread(), $dest_dir );
453 This function is useful for producing a directory tree identical to the
454 intended distribution tree.
456 $how can be used to specify a different methods of "copying". Valid
457 values are C<cp>, which actually copies the files, C<ln> which creates
458 hard links, and C<best> which mostly links the files but copies any
459 symbolic link to make a tree without any symbolic link. C<cp> is the
465 my($read,$target,$how)=@_;
466 croak "manicopy() called without target argument" unless defined $target;
469 require File::Basename;
471 $target = VMS::Filespec::unixify($target) if $Is_VMS;
472 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
473 foreach my $file (keys %$read){
476 my $dir = _maccat($target, $file);
478 File::Path::mkpath($dir,1,0755);
480 cp_if_diff($file, _maccat($target, $file), $how);
482 $file = VMS::Filespec::unixify($file) if $Is_VMS;
483 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
484 my $dir = File::Basename::dirname($file);
485 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
486 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
488 cp_if_diff($file, "$target/$file", $how);
494 my($from, $to, $how)=@_;
495 -f $from or carp "$0: $from not found";
498 open(F,"< $from\0") or die "Can't read $from: $!\n";
499 if (open(T,"< $to\0")) {
501 while (<F>) { $diff++,last if $_ ne <T>; }
502 $diff++ unless eof(T);
509 unlink($to) or confess "unlink $to: $!";
512 best($from,$to), last STRICT_SWITCH if $how eq 'best';
513 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
514 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
515 croak("ExtUtils::Manifest::cp_if_diff " .
516 "called with illegal how argument [$how]. " .
517 "Legal values are 'best', 'cp', and 'ln'.");
523 my ($srcFile, $dstFile) = @_;
524 my ($access,$mod) = (stat $srcFile)[8,9];
526 copy($srcFile,$dstFile);
527 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
528 _manicopy_chmod($srcFile, $dstFile);
533 my ($srcFile, $dstFile) = @_;
534 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
535 link($srcFile, $dstFile);
537 unless( _manicopy_chmod($srcFile, $dstFile) ) {
544 # 1) Strip off all group and world permissions.
545 # 2) Let everyone read it.
546 # 3) If the owner can execute it, everyone can.
547 sub _manicopy_chmod {
548 my($srcFile, $dstFile) = @_;
550 my $perm = 0444 | (stat $srcFile)[2] & 0700;
551 chmod( $perm | ( $perm & 0100 ? 0111 : 0 ), $dstFile );
554 # Files that are often modified in the distdir. Don't hard link them.
555 my @Exceptions = qw(MANIFEST META.yml SIGNATURE);
557 my ($srcFile, $dstFile) = @_;
559 my $is_exception = grep $srcFile =~ /$_/, @Exceptions;
560 if ($is_exception or !$Config{d_link} or -l $srcFile) {
561 cp($srcFile, $dstFile);
563 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
570 return $file unless $Is_MacOS;
584 return "$f1/$f2" unless $Is_MacOS;
587 $f1 =~ s/([^:]:):/$1/g;
594 return $file unless $Is_MacOS;
597 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
606 maniadd({ $file => $comment, ...});
608 Adds an entry to an existing F<MANIFEST> unless its already there.
610 $file will be normalized (ie. Unixified). B<UNIMPLEMENTED>
615 my($additions) = shift;
617 _normalize($additions);
618 _fix_manifest($MANIFEST);
620 my $manifest = maniread();
621 my @needed = grep { !exists $manifest->{$_} } keys %$additions;
622 return 1 unless @needed;
624 open(MANIFEST, ">>$MANIFEST") or
625 die "maniadd() could not open $MANIFEST: $!";
627 foreach my $file (_sort @needed) {
628 my $comment = $additions->{$file} || '';
629 printf MANIFEST "%-40s %s\n", $file, $comment;
631 close MANIFEST or die "Error closing $MANIFEST: $!";
637 # Sometimes MANIFESTs are missing a trailing newline. Fix this.
639 my $manifest_file = shift;
641 open MANIFEST, $MANIFEST or die "Could not open $MANIFEST: $!";
643 # Yes, we should be using seek(), but I'd like to avoid loading POSIX
645 my @manifest = <MANIFEST>;
648 unless( $manifest[-1] =~ /\n\z/ ) {
649 open MANIFEST, ">>$MANIFEST" or die "Could not open $MANIFEST: $!";
666 A list of files in the distribution, one file per line. The MANIFEST
667 always uses Unix filepath conventions even if you're not on Unix. This
668 means F<foo/bar> style not F<foo\bar>.
670 Anything between white space and an end of line within a C<MANIFEST>
671 file is considered to be a comment. Any line beginning with # is also
676 some/other/file comment about some/file
681 The file MANIFEST.SKIP may contain regular expressions of files that
682 should be ignored by mkmanifest() and filecheck(). The regular
683 expressions should appear one on each line. Blank lines and lines
684 which start with C<#> are skipped. Use C<\#> if you need a regular
685 expression to start with a C<#>.
689 # Version control files and dirs.
695 # Makemaker generated files and dirs.
701 # Temp, old and emacs backup files.
707 If no MANIFEST.SKIP file is found, a default set of skips will be
708 used, similar to the example above. If you want nothing skipped,
709 simply make an empty MANIFEST.SKIP file.
711 In one's own MANIFEST.SKIP file, certain directives
712 can be used to include the contents of other MANIFEST.SKIP
713 files. At present two such directives are recognized.
717 =item #!include_default
719 This inserts the contents of the default MANIFEST.SKIP file
721 =item #!include /Path/to/another/manifest.skip
723 This inserts the contents of the specified external file
727 The included contents will be inserted into the MANIFEST.SKIP
728 file in between I<#!start included /path/to/manifest.skip>
729 and I<#!end included /path/to/manifest.skip> markers.
730 The original MANIFEST.SKIP is saved as MANIFEST.SKIP.bak.
734 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
735 C<&maniread>, and C<&manicopy> are exportable.
737 =head2 GLOBAL VARIABLES
739 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
740 results in both a different C<MANIFEST> and a different
741 C<MANIFEST.SKIP> file. This is useful if you want to maintain
742 different distributions for different audiences (say a user version
743 and a developer version including RCS).
745 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
746 all functions act silently.
748 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
749 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
754 All diagnostic output is sent to C<STDERR>.
758 =item C<Not in MANIFEST:> I<file>
760 is reported if a file is found which is not in C<MANIFEST>.
762 =item C<Skipping> I<file>
764 is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
766 =item C<No such file:> I<file>
768 is reported if a file mentioned in a C<MANIFEST> file does not
771 =item C<MANIFEST:> I<$!>
773 is reported if C<MANIFEST> could not be opened.
775 =item C<Added to MANIFEST:> I<file>
777 is reported by mkmanifest() if $Verbose is set and a file is added
778 to MANIFEST. $Verbose is set to 1 by default.
786 =item B<PERL_MM_MANIFEST_DEBUG>
794 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
798 Andreas Koenig C<andreas.koenig@anima.de>
800 Maintained by Michael G Schwern C<schwern@pobox.com> within the
801 ExtUtils-MakeMaker package and, as a separate CPAN package, by
802 Randy Kobes C<r.kobes@uwinnipeg.ca>.