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){
311 warn "Problem opening $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";
349 _check_mskip_directives($mfile) if -f $mfile;
351 open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
357 push @skip, _macify($_);
360 return sub {0} unless (scalar @skip > 0);
362 my $opts = $Is_VMS ? '(?i)' : '';
364 # Make sure each entry is isolated in its own parentheses, in case
365 # any of them contain alternations
366 my $regex = join '|', map "(?:$_)", @skip;
368 return sub { $_[0] =~ qr{$opts$regex} };
371 # checks for the special directives
373 # #!include /path/to/some/manifest.skip
374 # in a custom MANIFEST.SKIP for, for including
375 # the content of, respectively, the default MANIFEST.SKIP
376 # and an external manifest.skip file
377 sub _check_mskip_directives {
382 unless (open M, $mfile) {
383 warn "Problem opening $mfile: $!";
387 if (/^#!include_default\s*$/) {
388 if (my @default = _include_mskip_file()) {
389 push @lines, @default;
390 warn "Debug: Including default MANIFEST.SKIP\n" if $Debug;
395 if (/^#!include\s+(.*)\s*$/) {
396 my $external_file = $1;
397 if (my @external = _include_mskip_file($external_file)) {
398 push @lines, @external;
399 warn "Debug: Including external $external_file\n" if $Debug;
408 rename $mfile, "$mfile.bak";
409 warn "Debug: Saving original $mfile as $mfile.bak\n" if $Debug;
410 unless (open M, ">$mfile") {
411 warn "Problem opening $mfile: $!";
414 print M $_ for (@lines);
419 # returns an array containing the lines of an external
420 # manifest.skip file, if given, or $DEFAULT_MSKIP
421 sub _include_mskip_file {
422 my $mskip = shift || $DEFAULT_MSKIP;
424 warn qq{Included file "$mskip" not found - skipping};
428 unless (open M, $mskip) {
429 warn "Problem opening $mskip: $!";
433 push @lines, "\n#!start included $mskip\n";
434 push @lines, $_ while <M>;
436 push @lines, "#!end included $mskip\n\n";
442 manicopy(\%src, $dest_dir);
443 manicopy(\%src, $dest_dir, $how);
445 Copies the files that are the keys in %src to the $dest_dir. %src is
446 typically returned by the maniread() function.
448 manicopy( maniread(), $dest_dir );
450 This function is useful for producing a directory tree identical to the
451 intended distribution tree.
453 $how can be used to specify a different methods of "copying". Valid
454 values are C<cp>, which actually copies the files, C<ln> which creates
455 hard links, and C<best> which mostly links the files but copies any
456 symbolic link to make a tree without any symbolic link. C<cp> is the
462 my($read,$target,$how)=@_;
463 croak "manicopy() called without target argument" unless defined $target;
466 require File::Basename;
468 $target = VMS::Filespec::unixify($target) if $Is_VMS;
469 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
470 foreach my $file (keys %$read){
473 my $dir = _maccat($target, $file);
475 File::Path::mkpath($dir,1,0755);
477 cp_if_diff($file, _maccat($target, $file), $how);
479 $file = VMS::Filespec::unixify($file) if $Is_VMS;
480 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
481 my $dir = File::Basename::dirname($file);
482 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
483 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
485 cp_if_diff($file, "$target/$file", $how);
491 my($from, $to, $how)=@_;
492 -f $from or carp "$0: $from not found";
495 open(F,"< $from\0") or die "Can't read $from: $!\n";
496 if (open(T,"< $to\0")) {
498 while (<F>) { $diff++,last if $_ ne <T>; }
499 $diff++ unless eof(T);
506 unlink($to) or confess "unlink $to: $!";
509 best($from,$to), last STRICT_SWITCH if $how eq 'best';
510 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
511 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
512 croak("ExtUtils::Manifest::cp_if_diff " .
513 "called with illegal how argument [$how]. " .
514 "Legal values are 'best', 'cp', and 'ln'.");
520 my ($srcFile, $dstFile) = @_;
521 my ($access,$mod) = (stat $srcFile)[8,9];
523 copy($srcFile,$dstFile);
524 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
525 _manicopy_chmod($srcFile, $dstFile);
530 my ($srcFile, $dstFile) = @_;
531 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
532 link($srcFile, $dstFile);
534 unless( _manicopy_chmod($srcFile, $dstFile) ) {
541 # 1) Strip off all group and world permissions.
542 # 2) Let everyone read it.
543 # 3) If the owner can execute it, everyone can.
544 sub _manicopy_chmod {
545 my($srcFile, $dstFile) = @_;
547 my $perm = 0444 | (stat $srcFile)[2] & 0700;
548 chmod( $perm | ( $perm & 0100 ? 0111 : 0 ), $dstFile );
551 # Files that are often modified in the distdir. Don't hard link them.
552 my @Exceptions = qw(MANIFEST META.yml SIGNATURE);
554 my ($srcFile, $dstFile) = @_;
556 my $is_exception = grep $srcFile =~ /$_/, @Exceptions;
557 if ($is_exception or !$Config{d_link} or -l $srcFile) {
558 cp($srcFile, $dstFile);
560 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
567 return $file unless $Is_MacOS;
581 return "$f1/$f2" unless $Is_MacOS;
584 $f1 =~ s/([^:]:):/$1/g;
591 return $file unless $Is_MacOS;
594 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
603 maniadd({ $file => $comment, ...});
605 Adds an entry to an existing F<MANIFEST> unless its already there.
607 $file will be normalized (ie. Unixified). B<UNIMPLEMENTED>
612 my($additions) = shift;
614 _normalize($additions);
615 _fix_manifest($MANIFEST);
617 my $manifest = maniread();
618 my @needed = grep { !exists $manifest->{$_} } keys %$additions;
619 return 1 unless @needed;
621 open(MANIFEST, ">>$MANIFEST") or
622 die "maniadd() could not open $MANIFEST: $!";
624 foreach my $file (_sort @needed) {
625 my $comment = $additions->{$file} || '';
626 printf MANIFEST "%-40s %s\n", $file, $comment;
628 close MANIFEST or die "Error closing $MANIFEST: $!";
634 # Sometimes MANIFESTs are missing a trailing newline. Fix this.
636 my $manifest_file = shift;
638 open MANIFEST, $MANIFEST or die "Could not open $MANIFEST: $!";
640 # Yes, we should be using seek(), but I'd like to avoid loading POSIX
642 my @manifest = <MANIFEST>;
645 unless( $manifest[-1] =~ /\n\z/ ) {
646 open MANIFEST, ">>$MANIFEST" or die "Could not open $MANIFEST: $!";
663 A list of files in the distribution, one file per line. The MANIFEST
664 always uses Unix filepath conventions even if you're not on Unix. This
665 means F<foo/bar> style not F<foo\bar>.
667 Anything between white space and an end of line within a C<MANIFEST>
668 file is considered to be a comment. Any line beginning with # is also
673 some/other/file comment about some/file
678 The file MANIFEST.SKIP may contain regular expressions of files that
679 should be ignored by mkmanifest() and filecheck(). The regular
680 expressions should appear one on each line. Blank lines and lines
681 which start with C<#> are skipped. Use C<\#> if you need a regular
682 expression to start with a C<#>.
686 # Version control files and dirs.
692 # Makemaker generated files and dirs.
698 # Temp, old and emacs backup files.
704 If no MANIFEST.SKIP file is found, a default set of skips will be
705 used, similar to the example above. If you want nothing skipped,
706 simply make an empty MANIFEST.SKIP file.
708 In one's own MANIFEST.SKIP file, certain directives
709 can be used to include the contents of other MANIFEST.SKIP
710 files. At present two such directives are recognized.
714 =item #!include_default
716 This inserts the contents of the default MANIFEST.SKIP file
718 =item #!include /Path/to/another/manifest.skip
720 This inserts the contents of the specified external file
724 The included contents will be inserted into the MANIFEST.SKIP
725 file in between I<#!start included /path/to/manifest.skip>
726 and I<#!end included /path/to/manifest.skip> markers.
727 The original MANIFEST.SKIP is saved as MANIFEST.SKIP.bak.
731 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
732 C<&maniread>, and C<&manicopy> are exportable.
734 =head2 GLOBAL VARIABLES
736 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
737 results in both a different C<MANIFEST> and a different
738 C<MANIFEST.SKIP> file. This is useful if you want to maintain
739 different distributions for different audiences (say a user version
740 and a developer version including RCS).
742 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
743 all functions act silently.
745 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
746 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
751 All diagnostic output is sent to C<STDERR>.
755 =item C<Not in MANIFEST:> I<file>
757 is reported if a file is found which is not in C<MANIFEST>.
759 =item C<Skipping> I<file>
761 is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
763 =item C<No such file:> I<file>
765 is reported if a file mentioned in a C<MANIFEST> file does not
768 =item C<MANIFEST:> I<$!>
770 is reported if C<MANIFEST> could not be opened.
772 =item C<Added to MANIFEST:> I<file>
774 is reported by mkmanifest() if $Verbose is set and a file is added
775 to MANIFEST. $Verbose is set to 1 by default.
783 =item B<PERL_MM_MANIFEST_DEBUG>
791 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
795 Andreas Koenig C<andreas.koenig@anima.de>
797 Maintained by Michael G Schwern C<schwern@pobox.com> within the
798 ExtUtils-MakeMaker package and, as a separate CPAN package, by
799 Randy Kobes C<r.kobes@uwinnipeg.ca>.