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;
25 $Verbose = defined $ENV{PERL_MM_MANIFEST_VERBOSE} ?
26 $ENV{PERL_MM_MANIFEST_VERBOSE} : 1;
28 $MANIFEST = 'MANIFEST';
29 $DEFAULT_MSKIP = (splitpath($INC{"ExtUtils/Manifest.pm"}))[1]."$MANIFEST.SKIP";
31 # Really cool fix from Ilya :)
32 unless (defined $Config{d_link}) {
39 my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
40 $read = {} if $manimiss;
42 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
43 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
44 my $skip = _maniskip();
45 my $found = manifind();
46 my($key,$val,$file,%all);
47 %all = (%$found, %$read);
48 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
49 if $manimiss; # add new MANIFEST to known file list
50 foreach $file (sort keys %all) {
52 # Policy: only remove files if they're listed in MANIFEST.SKIP.
53 # Don't remove files just because they don't exist.
54 warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
58 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
60 my $text = $all{$file};
61 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
62 $file = _unmacify($file);
63 my $tabs = (5 - (length($file)+1)/8);
64 $tabs = 1 if $tabs < 1;
65 $tabs = 0 unless $text;
66 print M $file, "\t" x $tabs, $text, "\n";
71 # Geez, shouldn't this use File::Spec or File::Basename or something?
72 # Why so careful about dependencies?
73 sub clean_up_filename {
75 $filename =~ s|^\./||;
76 $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
85 my $name = clean_up_filename($File::Find::name);
86 warn "Debug: diskfile $name\n" if $Debug;
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,
103 $Is_MacOS ? ":" : ".");
109 return [_check_files()], [_check_manifest()];
113 return _check_files();
117 return _check_manifest();
122 my $found = manifind();
123 my $matches = _maniskip();
126 foreach my $file (sort keys %$found){
127 if (&$matches($file)){
128 warn "Skipping $file\n";
129 push @skipped, $file;
140 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
141 my $read = maniread() || {};
142 my $found = manifind($p);
145 foreach my $file (sort keys %$read){
146 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
149 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
150 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
152 unless ( exists $found->{$file} ) {
153 warn "No such file: $file\n" unless $Quiet;
154 push @missfile, $file;
162 sub _check_manifest {
164 my $read = maniread() || {};
165 my $found = manifind($p);
166 my $skip = _maniskip();
169 foreach my $file (sort keys %$found){
170 next if $skip->($file);
171 warn "Debug: manicheck checking from disk $file\n" if $Debug;
172 unless ( exists $read->{$file} ) {
173 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
174 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
175 push @missentry, $file;
185 $mfile ||= $MANIFEST;
188 unless (open M, $mfile){
196 my($file, $comment) = /^(\S+)\s*(.*)/;
200 $file = _macify($file);
201 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
204 require File::Basename;
205 my($base,$dir) = File::Basename::fileparse($file);
206 # Resolve illegal file specifications in the same way as tar
208 my(@pieces) = split(/\./,$base);
209 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
210 my $okfile = "$dir$base";
211 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
213 $file = lc($file) unless $file =~ /^MANIFEST(\.SKIP)?$/;
216 $read->{$file} = $comment;
222 # returns an anonymous sub that decides if an argument matches
225 my $mfile = "$MANIFEST.SKIP";
227 open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
232 push @skip, _macify($_);
235 my $opts = $Is_VMS ? '(?i)' : '';
237 # Make sure each entry is isolated in its own parentheses, in case
238 # any of them contain alternations
239 my $regex = join '|', map "(?:$_)", @skip;
241 return sub { $_[0] =~ qr{$opts$regex} };
245 my($read,$target,$how)=@_;
246 croak "manicopy() called without target argument" unless defined $target;
249 require File::Basename;
251 $target = VMS::Filespec::unixify($target) if $Is_VMS;
252 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
253 foreach $file (keys %$read){
256 my $dir = _maccat($target, $file);
258 File::Path::mkpath($dir,1,0755);
260 cp_if_diff($file, _maccat($target, $file), $how);
262 $file = VMS::Filespec::unixify($file) if $Is_VMS;
263 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
264 my $dir = File::Basename::dirname($file);
265 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
266 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
268 cp_if_diff($file, "$target/$file", $how);
274 my($from, $to, $how)=@_;
275 -f $from or carp "$0: $from not found";
278 open(F,"< $from\0") or croak "Can't read $from: $!\n";
279 if (open(T,"< $to\0")) {
280 while (<F>) { $diff++,last if $_ ne <T>; }
281 $diff++ unless eof(T);
288 unlink($to) or confess "unlink $to: $!";
291 best($from,$to), last STRICT_SWITCH if $how eq 'best';
292 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
293 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
294 croak("ExtUtils::Manifest::cp_if_diff " .
295 "called with illegal how argument [$how]. " .
296 "Legal values are 'best', 'cp', and 'ln'.");
302 my ($srcFile, $dstFile) = @_;
303 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
304 copy($srcFile,$dstFile);
305 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
307 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile )
308 unless ($^O eq 'MacOS');
312 my ($srcFile, $dstFile) = @_;
313 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
314 link($srcFile, $dstFile);
315 local($_) = $dstFile; # chmod a+r,go-w+X (except "X" only applies to u=x)
316 my $mode= 0444 | (stat)[2] & 0700;
317 if (! chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ )) {
325 my ($srcFile, $dstFile) = @_;
327 cp($srcFile, $dstFile);
329 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
336 return $file unless $Is_MacOS;
350 return "$f1/$f2" unless $Is_MacOS;
353 $f1 =~ s/([^:]:):/$1/g;
360 return $file unless $Is_MacOS;
363 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
375 ExtUtils::Manifest - utilities to write and check a MANIFEST file
379 require ExtUtils::Manifest;
381 ExtUtils::Manifest::mkmanifest;
383 ExtUtils::Manifest::manicheck;
385 ExtUtils::Manifest::filecheck;
387 ExtUtils::Manifest::fullcheck;
389 ExtUtils::Manifest::skipcheck;
391 ExtUtils::Manifest::manifind();
393 ExtUtils::Manifest::maniread($file);
395 ExtUtils::Manifest::manicopy($read,$target,$how);
399 mkmanifest() writes all files in and below the current directory to a
400 file named in the global variable $ExtUtils::Manifest::MANIFEST (which
401 defaults to C<MANIFEST>) in the current directory. It works similar to
405 but in doing so checks each line in an existing C<MANIFEST> file and
406 includes any comments that are found in the existing C<MANIFEST> file
407 in the new one. Anything between white space and an end of line within
408 a C<MANIFEST> file is considered to be a comment. Filenames and
409 comments are separated by one or more TAB characters in the
410 output. All files that match any regular expression in a file
411 C<MANIFEST.SKIP> (if such a file exists) are ignored.
413 manicheck() checks if all the files within a C<MANIFEST> in the current
414 directory really do exist. If C<MANIFEST> and the tree below the current
415 directory are in sync it exits silently, returning an empty list. Otherwise
416 it returns a list of files which are listed in the C<MANIFEST> but missing
417 from the directory, and by default also outputs these names to STDERR.
419 filecheck() finds files below the current directory that are not
420 mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
421 will be consulted. Any file matching a regular expression in such a
422 file will not be reported as missing in the C<MANIFEST> file. The list of
423 any extraneous files found is returned, and by default also reported to
426 fullcheck() does both a manicheck() and a filecheck(), returning references
427 to two arrays, the first for files manicheck() found to be missing, the
428 seond for unexpeced files found by filecheck().
430 skipcheck() lists all the files that are skipped due to your
431 C<MANIFEST.SKIP> file.
433 manifind() returns a hash reference. The keys of the hash are the
434 files found below the current directory.
436 maniread($file) reads a named C<MANIFEST> file (defaults to
437 C<MANIFEST> in the current directory) and returns a HASH reference
438 with files being the keys and comments being the values of the HASH.
439 Blank lines and lines which start with C<#> in the C<MANIFEST> file
442 C<manicopy($read,$target,$how)> copies the files that are the keys in
443 the HASH I<%$read> to the named target directory. The HASH reference
444 $read is typically returned by the maniread() function. This
445 function is useful for producing a directory tree identical to the
446 intended distribution tree. The third parameter $how can be used to
447 specify a different methods of "copying". Valid values are C<cp>,
448 which actually copies the files, C<ln> which creates hard links, and
449 C<best> which mostly links the files but copies any symbolic link to
450 make a tree without any symbolic link. Best is the default.
454 The file MANIFEST.SKIP may contain regular expressions of files that
455 should be ignored by mkmanifest() and filecheck(). The regular
456 expressions should appear one on each line. Blank lines and lines
457 which start with C<#> are skipped. Use C<\#> if you need a regular
458 expression to start with a sharp character. A typical example:
460 # Version control files and dirs.
465 # Makemaker generated files and dirs.
471 # Temp, old and emacs backup files.
477 If no MANIFEST.SKIP file is found, a default set of skips will be
478 used, similar to the example above. If you want nothing skipped,
479 simply make an empty MANIFEST.SKIP file.
484 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
485 C<&maniread>, and C<&manicopy> are exportable.
487 =head1 GLOBAL VARIABLES
489 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
490 results in both a different C<MANIFEST> and a different
491 C<MANIFEST.SKIP> file. This is useful if you want to maintain
492 different distributions for different audiences (say a user version
493 and a developer version including RCS).
495 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
496 all functions act silently.
498 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
499 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
504 All diagnostic output is sent to C<STDERR>.
508 =item C<Not in MANIFEST:> I<file>
510 is reported if a file is found which is not in C<MANIFEST>.
512 =item C<Skipping> I<file>
514 is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
516 =item C<No such file:> I<file>
518 is reported if a file mentioned in a C<MANIFEST> file does not
521 =item C<MANIFEST:> I<$!>
523 is reported if C<MANIFEST> could not be opened.
525 =item C<Added to MANIFEST:> I<file>
527 is reported by mkmanifest() if $Verbose is set and a file is added
528 to MANIFEST. $Verbose is set to 1 by default.
536 =item B<PERL_MM_MANIFEST_DEBUG>
544 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
548 Andreas Koenig <F<andreas.koenig@anima.de>>