1 package ExtUtils::Manifest;
11 use vars qw($VERSION @ISA @EXPORT_OK
13 $Debug $Verbose $Quiet $MANIFEST $DEFAULT_MSKIP);
17 @EXPORT_OK = qw(mkmanifest
18 manicheck filecheck fullcheck skipcheck
19 manifind maniread manicopy maniadd
22 $Is_MacOS = $^O eq 'MacOS';
23 $Is_VMS = $^O eq 'VMS';
24 require VMS::Filespec if $Is_VMS;
26 $Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
27 $Verbose = defined $ENV{PERL_MM_MANIFEST_VERBOSE} ?
28 $ENV{PERL_MM_MANIFEST_VERBOSE} : 1;
30 $MANIFEST = 'MANIFEST';
32 my $Filename = __FILE__;
33 $DEFAULT_MSKIP = (File::Spec->splitpath($Filename))[1].
39 ExtUtils::Manifest - utilities to write and check a MANIFEST file
43 use ExtUtils::Manifest qw(...funcs to import...);
47 my @missing_files = manicheck;
48 my @skipped = skipcheck;
49 my @extra_files = filecheck;
50 my($missing, $extra) = fullcheck;
52 my $found = manifind();
54 my $manifest = maniread();
56 manicopy($read,$target);
58 maniadd({$file => $comment, ...});
65 ExtUtils::Manifest exports no functions by default. The following are
74 Writes all files in and below the current directory to your F<MANIFEST>.
79 All files that match any regular expression in a file F<MANIFEST.SKIP>
80 (if it exists) are ignored.
82 Any existing F<MANIFEST> file will be saved as F<MANIFEST.bak>. Lines
83 from the old F<MANIFEST> file is preserved, including any comments
84 that are found in the existing F<MANIFEST> file in the new one.
89 return sort { lc $a cmp lc $b } @_;
94 my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
95 $read = {} if $manimiss;
97 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
98 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
99 my $skip = _maniskip();
100 my $found = manifind();
101 my($key,$val,$file,%all);
102 %all = (%$found, %$read);
103 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
104 if $manimiss; # add new MANIFEST to known file list
105 foreach $file (_sort keys %all) {
106 if ($skip->($file)) {
107 # Policy: only remove files if they're listed in MANIFEST.SKIP.
108 # Don't remove files just because they don't exist.
109 warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
113 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
115 my $text = $all{$file};
116 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
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){
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";
351 open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
356 push @skip, _macify($_);
359 my $opts = $Is_VMS ? '(?i)' : '';
361 # Make sure each entry is isolated in its own parentheses, in case
362 # any of them contain alternations
363 my $regex = join '|', map "(?:$_)", @skip;
365 return sub { $_[0] =~ qr{$opts$regex} };
370 manicopy($src, $dest_dir);
371 manicopy($src, $dest_dir, $how);
373 copies the files that are the keys in the HASH I<%$src> to the
374 $dest_dir. The HASH reference $read is typically returned by the
375 maniread() function. This function is useful for producing a directory
376 tree identical to the intended distribution tree. The third parameter
377 $how can be used to specify a different methods of "copying". Valid
378 values are C<cp>, which actually copies the files, C<ln> which creates
379 hard links, and C<best> which mostly links the files but copies any
380 symbolic link to make a tree without any symbolic link. Best is the
386 my($read,$target,$how)=@_;
387 croak "manicopy() called without target argument" unless defined $target;
390 require File::Basename;
392 $target = VMS::Filespec::unixify($target) if $Is_VMS;
393 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
394 foreach my $file (keys %$read){
397 my $dir = _maccat($target, $file);
399 File::Path::mkpath($dir,1,0755);
401 cp_if_diff($file, _maccat($target, $file), $how);
403 $file = VMS::Filespec::unixify($file) if $Is_VMS;
404 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
405 my $dir = File::Basename::dirname($file);
406 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
407 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
409 cp_if_diff($file, "$target/$file", $how);
415 my($from, $to, $how)=@_;
416 -f $from or carp "$0: $from not found";
419 open(F,"< $from\0") or die "Can't read $from: $!\n";
420 if (open(T,"< $to\0")) {
422 while (<F>) { $diff++,last if $_ ne <T>; }
423 $diff++ unless eof(T);
430 unlink($to) or confess "unlink $to: $!";
433 best($from,$to), last STRICT_SWITCH if $how eq 'best';
434 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
435 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
436 croak("ExtUtils::Manifest::cp_if_diff " .
437 "called with illegal how argument [$how]. " .
438 "Legal values are 'best', 'cp', and 'ln'.");
444 my ($srcFile, $dstFile) = @_;
445 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
446 copy($srcFile,$dstFile);
447 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
449 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile )
450 unless ($^O eq 'MacOS');
454 my ($srcFile, $dstFile) = @_;
455 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
456 link($srcFile, $dstFile);
458 # chmod a+r,go-w+X (except "X" only applies to u=x)
459 local($_) = $dstFile;
460 my $mode= 0444 | (stat)[2] & 0700;
461 if (! chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ )) {
468 unless (defined $Config{d_link}) {
469 # Really cool fix from Ilya :)
470 local $SIG{__WARN__} = sub {
471 warn @_ unless $_[0] =~ /^Subroutine .* redefined/;
480 my ($srcFile, $dstFile) = @_;
482 cp($srcFile, $dstFile);
484 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
491 return $file unless $Is_MacOS;
505 return "$f1/$f2" unless $Is_MacOS;
508 $f1 =~ s/([^:]:):/$1/g;
515 return $file unless $Is_MacOS;
518 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
527 maniadd({ $file => $comment, ...});
529 Adds an entry to an existing F<MANIFEST> unless its already there.
531 $file will be normalized (ie. Unixified). B<UNIMPLEMENTED>
536 my($additions) = shift;
538 _normalize($additions);
539 _fix_manifest($MANIFEST);
541 my $manifest = maniread();
543 foreach my $file (_sort keys %$additions) {
544 next if exists $manifest->{$file};
546 $is_open++ or open(MANIFEST, ">>$MANIFEST") or
547 die "Could not open $MANIFEST: $!";
549 my $comment = $additions->{$file} || '';
550 printf MANIFEST "%-40s%s\n", $file, $comment;
552 close MANIFEST if $is_open;
556 # Sometimes MANIFESTs are missing a trailing newline. Fix this.
558 my $manifest_file = shift;
560 open MANIFEST, $MANIFEST or die "Could not open $MANIFEST: $!";
562 # Yes, we should be using seek(), but I'd like to avoid loading POSIX
564 my @manifest = <MANIFEST>;
567 unless( $manifest[-1] =~ /\n\z/ ) {
568 open MANIFEST, ">>$MANIFEST" or die "Could not open $MANIFEST: $!";
585 Anything between white space and an end of line within a C<MANIFEST>
586 file is considered to be a comment. Filenames and comments are
587 separated by one or more TAB characters in the output.
592 The file MANIFEST.SKIP may contain regular expressions of files that
593 should be ignored by mkmanifest() and filecheck(). The regular
594 expressions should appear one on each line. Blank lines and lines
595 which start with C<#> are skipped. Use C<\#> if you need a regular
596 expression to start with a sharp character. A typical example:
598 # Version control files and dirs.
604 # Makemaker generated files and dirs.
610 # Temp, old and emacs backup files.
616 If no MANIFEST.SKIP file is found, a default set of skips will be
617 used, similar to the example above. If you want nothing skipped,
618 simply make an empty MANIFEST.SKIP file.
623 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
624 C<&maniread>, and C<&manicopy> are exportable.
626 =head2 GLOBAL VARIABLES
628 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
629 results in both a different C<MANIFEST> and a different
630 C<MANIFEST.SKIP> file. This is useful if you want to maintain
631 different distributions for different audiences (say a user version
632 and a developer version including RCS).
634 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
635 all functions act silently.
637 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
638 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
643 All diagnostic output is sent to C<STDERR>.
647 =item C<Not in MANIFEST:> I<file>
649 is reported if a file is found which is not in C<MANIFEST>.
651 =item C<Skipping> I<file>
653 is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
655 =item C<No such file:> I<file>
657 is reported if a file mentioned in a C<MANIFEST> file does not
660 =item C<MANIFEST:> I<$!>
662 is reported if C<MANIFEST> could not be opened.
664 =item C<Added to MANIFEST:> I<file>
666 is reported by mkmanifest() if $Verbose is set and a file is added
667 to MANIFEST. $Verbose is set to 1 by default.
675 =item B<PERL_MM_MANIFEST_DEBUG>
683 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
687 Andreas Koenig <F<andreas.koenig@anima.de>>