1 package ExtUtils::Manifest;
7 use File::Spec::Functions qw(splitpath);
11 our ($VERSION,@ISA,@EXPORT_OK,
13 $Debug,$Verbose,$Quiet,$MANIFEST,$DEFAULT_MSKIP);
17 @EXPORT_OK = ('mkmanifest', 'manicheck', 'fullcheck', 'filecheck',
18 'skipcheck', 'maniread', 'manicopy');
20 $Is_MacOS = $^O eq 'MacOS';
21 $Is_VMS = $^O eq 'VMS';
22 require VMS::Filespec if $Is_VMS;
24 $Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
27 $MANIFEST = 'MANIFEST';
28 $DEFAULT_MSKIP = (splitpath($INC{"ExtUtils/Manifest.pm"}))[1]."$MANIFEST.SKIP";
30 # Really cool fix from Ilya :)
31 unless (defined $Config{d_link}) {
38 my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
39 $read = {} if $manimiss;
41 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
42 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
43 my $skip = _maniskip();
44 my $found = manifind();
45 my($key,$val,$file,%all);
46 %all = (%$found, %$read);
47 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
48 if $manimiss; # add new MANIFEST to known file list
49 foreach $file (sort keys %all) {
51 # Policy: only remove files if they're listed in MANIFEST.SKIP.
52 # Don't remove files just because they don't exist.
53 warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
57 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
59 my $text = $all{$file};
60 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
61 $file = _unmacify($file);
62 my $tabs = (5 - (length($file)+1)/8);
63 $tabs = 1 if $tabs < 1;
64 $tabs = 0 unless $text;
65 print M $file, "\t" x $tabs, $text, "\n";
70 # Geez, shouldn't this use File::Spec or File::Basename or something?
71 # Why so careful about dependencies?
72 sub clean_up_filename {
74 $filename =~ s|^\./||;
75 $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
81 my $skip = _maniskip(warn => $p->{warn_on_skip});
85 my $name = clean_up_filename($File::Find::name);
86 warn "Debug: diskfile $name\n" if $Debug;
87 return if $skip->($name) or -d $name;
90 $name =~ s#(.*)\.$#\L$1#;
91 $name = uc($name) if $name =~ /^MANIFEST(\.SKIP)?$/i;
96 # We have to use "$File::Find::dir/$_" in preprocess, because
97 # $File::Find::name is unavailable.
98 # Also, it's okay to use / here, because MANIFEST files use Unix-style
100 find({wanted => $wanted,
102 sub {grep {!$skip->( clean_up_filename("$File::Find::dir/$_") )} @_},
105 $Is_MacOS ? ":" : ".");
111 _manicheck({check_files => 1, check_MANIFEST => 1});
115 return @{(_manicheck({check_files => 1}))[0]};
119 return @{(_manicheck({check_MANIFEST => 1}))[1]};
123 _manicheck({check_MANIFEST => 1, warn_on_skip => 1});
128 my $read = maniread();
129 my $found = manifind($p);
132 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
133 my(@missfile,@missentry);
134 if ($p->{check_files}){
135 foreach $file (sort keys %$read){
136 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
139 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
140 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
142 unless ( exists $found->{$file} ) {
143 warn "No such file: $file\n" unless $Quiet;
144 push @missfile, $file;
148 if ($p->{check_MANIFEST}){
150 my $matches = _maniskip();
151 foreach $file (sort keys %$found){
152 if (&$matches($file)){
153 warn "Skipping $file\n" if $p->{warn_on_skip};
156 warn "Debug: manicheck checking from disk $file\n" if $Debug;
157 unless ( exists $read->{$file} ) {
158 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
159 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
160 push @missentry, $file;
164 (\@missfile,\@missentry);
169 $mfile ||= $MANIFEST;
172 unless (open M, $mfile){
180 my($file, $comment) = /^(\S+)\s*(.*)/;
184 $file = _macify($file);
185 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
188 require File::Basename;
189 my($base,$dir) = File::Basename::fileparse($file);
190 # Resolve illegal file specifications in the same way as tar
192 my(@pieces) = split(/\./,$base);
193 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
194 my $okfile = "$dir$base";
195 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
197 $file = lc($file) unless $file =~ /^MANIFEST(\.SKIP)?$/;
200 $read->{$file} = $comment;
206 # returns an anonymous sub that decides if an argument matches
211 my $mfile ||= "$MANIFEST.SKIP";
213 open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
218 push @skip, _macify($_);
221 my $opts = $Is_VMS ? '(?i)' : '';
223 # Make sure each entry is isolated in its own parentheses, in case
224 # any of them contain alternations
225 my $regex = join '|', map "(?:$_)", @skip;
228 ? sub { $_[0] =~ qr{$opts$regex} && warn "Skipping $_[0]\n" }
229 : sub { $_[0] =~ qr{$opts$regex} }
234 my($read,$target,$how)=@_;
235 croak "manicopy() called without target argument" unless defined $target;
238 require File::Basename;
240 $target = VMS::Filespec::unixify($target) if $Is_VMS;
241 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
242 foreach $file (keys %$read){
245 my $dir = _maccat($target, $file);
247 File::Path::mkpath($dir,1,0755);
249 cp_if_diff($file, _maccat($target, $file), $how);
251 $file = VMS::Filespec::unixify($file) if $Is_VMS;
252 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
253 my $dir = File::Basename::dirname($file);
254 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
255 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
257 cp_if_diff($file, "$target/$file", $how);
263 my($from, $to, $how)=@_;
264 -f $from or carp "$0: $from not found";
267 open(F,"< $from\0") or croak "Can't read $from: $!\n";
268 if (open(T,"< $to\0")) {
269 while (<F>) { $diff++,last if $_ ne <T>; }
270 $diff++ unless eof(T);
277 unlink($to) or confess "unlink $to: $!";
280 best($from,$to), last STRICT_SWITCH if $how eq 'best';
281 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
282 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
283 croak("ExtUtils::Manifest::cp_if_diff " .
284 "called with illegal how argument [$how]. " .
285 "Legal values are 'best', 'cp', and 'ln'.");
291 my ($srcFile, $dstFile) = @_;
292 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
293 copy($srcFile,$dstFile);
294 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
296 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile ) unless ($^O eq 'MacOS');
300 my ($srcFile, $dstFile) = @_;
301 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
302 link($srcFile, $dstFile);
303 local($_) = $dstFile; # chmod a+r,go-w+X (except "X" only applies to u=x)
304 my $mode= 0444 | (stat)[2] & 0700;
305 if (! chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ )) {
313 my ($srcFile, $dstFile) = @_;
315 cp($srcFile, $dstFile);
317 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
324 return $file unless $Is_MacOS;
338 return "$f1/$f2" unless $Is_MacOS;
341 $f1 =~ s/([^:]:):/$1/g;
348 return $file unless $Is_MacOS;
351 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
363 ExtUtils::Manifest - utilities to write and check a MANIFEST file
367 require ExtUtils::Manifest;
369 ExtUtils::Manifest::mkmanifest;
371 ExtUtils::Manifest::manicheck;
373 ExtUtils::Manifest::filecheck;
375 ExtUtils::Manifest::fullcheck;
377 ExtUtils::Manifest::skipcheck;
379 ExtUtils::Manifest::manifind();
381 ExtUtils::Manifest::maniread($file);
383 ExtUtils::Manifest::manicopy($read,$target,$how);
387 mkmanifest() writes all files in and below the current directory to a
388 file named in the global variable $ExtUtils::Manifest::MANIFEST (which
389 defaults to C<MANIFEST>) in the current directory. It works similar to
393 but in doing so checks each line in an existing C<MANIFEST> file and
394 includes any comments that are found in the existing C<MANIFEST> file
395 in the new one. Anything between white space and an end of line within
396 a C<MANIFEST> file is considered to be a comment. Filenames and
397 comments are separated by one or more TAB characters in the
398 output. All files that match any regular expression in a file
399 C<MANIFEST.SKIP> (if such a file exists) are ignored.
401 manicheck() checks if all the files within a C<MANIFEST> in the current
402 directory really do exist. If C<MANIFEST> and the tree below the current
403 directory are in sync it exits silently, returning an empty list. Otherwise
404 it returns a list of files which are listed in the C<MANIFEST> but missing
405 from the directory, and by default also outputs these names to STDERR.
407 filecheck() finds files below the current directory that are not
408 mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
409 will be consulted. Any file matching a regular expression in such a
410 file will not be reported as missing in the C<MANIFEST> file. The list of
411 any extraneous files found is returned, and by default also reported to
414 fullcheck() does both a manicheck() and a filecheck(), returning references
415 to two arrays, the first for files manicheck() found to be missing, the
416 seond for unexpeced files found by filecheck().
418 skipcheck() lists all the files that are skipped due to your
419 C<MANIFEST.SKIP> file.
421 manifind() returns a hash reference. The keys of the hash are the
422 files found below the current directory.
424 maniread($file) reads a named C<MANIFEST> file (defaults to
425 C<MANIFEST> in the current directory) and returns a HASH reference
426 with files being the keys and comments being the values of the HASH.
427 Blank lines and lines which start with C<#> in the C<MANIFEST> file
430 C<manicopy($read,$target,$how)> copies the files that are the keys in
431 the HASH I<%$read> to the named target directory. The HASH reference
432 $read is typically returned by the maniread() function. This
433 function is useful for producing a directory tree identical to the
434 intended distribution tree. The third parameter $how can be used to
435 specify a different methods of "copying". Valid values are C<cp>,
436 which actually copies the files, C<ln> which creates hard links, and
437 C<best> which mostly links the files but copies any symbolic link to
438 make a tree without any symbolic link. Best is the default.
442 The file MANIFEST.SKIP may contain regular expressions of files that
443 should be ignored by mkmanifest() and filecheck(). The regular
444 expressions should appear one on each line. Blank lines and lines
445 which start with C<#> are skipped. Use C<\#> if you need a regular
446 expression to start with a sharp character. A typical example:
448 # Version control files and dirs.
453 # Makemaker generated files and dirs.
459 # Temp, old and emacs backup files.
465 If no MANIFEST.SKIP file is found, a default set of skips will be
466 used, similar to the example above. If you want nothing skipped,
467 simply make an empty MANIFEST.SKIP file.
472 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
473 C<&maniread>, and C<&manicopy> are exportable.
475 =head1 GLOBAL VARIABLES
477 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
478 results in both a different C<MANIFEST> and a different
479 C<MANIFEST.SKIP> file. This is useful if you want to maintain
480 different distributions for different audiences (say a user version
481 and a developer version including RCS).
483 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
484 all functions act silently.
486 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
487 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
492 All diagnostic output is sent to C<STDERR>.
496 =item C<Not in MANIFEST:> I<file>
498 is reported if a file is found, that is missing in the C<MANIFEST>
499 file which is excluded by a regular expression in the file
502 =item C<No such file:> I<file>
504 is reported if a file mentioned in a C<MANIFEST> file does not
507 =item C<MANIFEST:> I<$!>
509 is reported if C<MANIFEST> could not be opened.
511 =item C<Added to MANIFEST:> I<file>
513 is reported by mkmanifest() if $Verbose is set and a file is added
514 to MANIFEST. $Verbose is set to 1 by default.
522 =item B<PERL_MM_MANIFEST_DEBUG>
530 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
534 Andreas Koenig <F<andreas.koenig@anima.de>>