1 package ExtUtils::Manifest;
11 use vars qw($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 = (File::Spec->splitpath($INC{"ExtUtils/Manifest.pm"}))[1].
34 my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
35 $read = {} if $manimiss;
37 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
38 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
39 my $skip = _maniskip();
40 my $found = manifind();
41 my($key,$val,$file,%all);
42 %all = (%$found, %$read);
43 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
44 if $manimiss; # add new MANIFEST to known file list
45 foreach $file (sort keys %all) {
47 # Policy: only remove files if they're listed in MANIFEST.SKIP.
48 # Don't remove files just because they don't exist.
49 warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
53 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
55 my $text = $all{$file};
56 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
57 $file = _unmacify($file);
58 my $tabs = (5 - (length($file)+1)/8);
59 $tabs = 1 if $tabs < 1;
60 $tabs = 0 unless $text;
61 print M $file, "\t" x $tabs, $text, "\n";
66 # Geez, shouldn't this use File::Spec or File::Basename or something?
67 # Why so careful about dependencies?
68 sub clean_up_filename {
70 $filename =~ s|^\./||;
71 $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
80 my $name = clean_up_filename($File::Find::name);
81 warn "Debug: diskfile $name\n" if $Debug;
85 $name =~ s#(.*)\.$#\L$1#;
86 $name = uc($name) if $name =~ /^MANIFEST(\.SKIP)?$/i;
91 # We have to use "$File::Find::dir/$_" in preprocess, because
92 # $File::Find::name is unavailable.
93 # Also, it's okay to use / here, because MANIFEST files use Unix-style
95 find({wanted => $wanted},
96 $Is_MacOS ? ":" : ".");
102 return [_check_files()], [_check_manifest()];
106 return _check_files();
110 return _check_manifest();
115 my $found = manifind();
116 my $matches = _maniskip();
119 foreach my $file (sort keys %$found){
120 if (&$matches($file)){
121 warn "Skipping $file\n";
122 push @skipped, $file;
133 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
134 my $read = maniread() || {};
135 my $found = manifind($p);
138 foreach my $file (sort keys %$read){
139 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
142 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
143 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
145 unless ( exists $found->{$file} ) {
146 warn "No such file: $file\n" unless $Quiet;
147 push @missfile, $file;
155 sub _check_manifest {
157 my $read = maniread() || {};
158 my $found = manifind($p);
159 my $skip = _maniskip();
162 foreach my $file (sort keys %$found){
163 next if $skip->($file);
164 warn "Debug: manicheck checking from disk $file\n" if $Debug;
165 unless ( exists $read->{$file} ) {
166 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
167 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
168 push @missentry, $file;
178 $mfile ||= $MANIFEST;
181 unless (open M, $mfile){
189 my($file, $comment) = /^(\S+)\s*(.*)/;
193 $file = _macify($file);
194 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
197 require File::Basename;
198 my($base,$dir) = File::Basename::fileparse($file);
199 # Resolve illegal file specifications in the same way as tar
201 my(@pieces) = split(/\./,$base);
202 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
203 my $okfile = "$dir$base";
204 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
206 $file = lc($file) unless $file =~ /^MANIFEST(\.SKIP)?$/;
209 $read->{$file} = $comment;
215 # returns an anonymous sub that decides if an argument matches
218 my $mfile = "$MANIFEST.SKIP";
220 open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
225 push @skip, _macify($_);
228 my $opts = $Is_VMS ? '(?i)' : '';
230 # Make sure each entry is isolated in its own parentheses, in case
231 # any of them contain alternations
232 my $regex = join '|', map "(?:$_)", @skip;
234 return sub { $_[0] =~ qr{$opts$regex} };
238 my($read,$target,$how)=@_;
239 croak "manicopy() called without target argument" unless defined $target;
242 require File::Basename;
244 $target = VMS::Filespec::unixify($target) if $Is_VMS;
245 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
246 foreach my $file (keys %$read){
249 my $dir = _maccat($target, $file);
251 File::Path::mkpath($dir,1,0755);
253 cp_if_diff($file, _maccat($target, $file), $how);
255 $file = VMS::Filespec::unixify($file) if $Is_VMS;
256 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
257 my $dir = File::Basename::dirname($file);
258 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
259 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
261 cp_if_diff($file, "$target/$file", $how);
267 my($from, $to, $how)=@_;
268 -f $from or carp "$0: $from not found";
271 open(F,"< $from\0") or die "Can't read $from: $!\n";
272 if (open(T,"< $to\0")) {
273 while (<F>) { $diff++,last if $_ ne <T>; }
274 $diff++ unless eof(T);
281 unlink($to) or confess "unlink $to: $!";
284 best($from,$to), last STRICT_SWITCH if $how eq 'best';
285 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
286 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
287 croak("ExtUtils::Manifest::cp_if_diff " .
288 "called with illegal how argument [$how]. " .
289 "Legal values are 'best', 'cp', and 'ln'.");
295 my ($srcFile, $dstFile) = @_;
296 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
297 copy($srcFile,$dstFile);
298 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
300 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile )
301 unless ($^O eq 'MacOS');
305 my ($srcFile, $dstFile) = @_;
306 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
307 link($srcFile, $dstFile);
309 # chmod a+r,go-w+X (except "X" only applies to u=x)
310 local($_) = $dstFile;
311 my $mode= 0444 | (stat)[2] & 0700;
312 if (! chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ )) {
319 unless (defined $Config{d_link}) {
320 # Really cool fix from Ilya :)
321 local $SIG{__WARN__} = sub {
322 warn @_ unless $_[0] =~ /^Subroutine .* redefined/;
331 my ($srcFile, $dstFile) = @_;
333 cp($srcFile, $dstFile);
335 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
342 return $file unless $Is_MacOS;
356 return "$f1/$f2" unless $Is_MacOS;
359 $f1 =~ s/([^:]:):/$1/g;
366 return $file unless $Is_MacOS;
369 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
381 ExtUtils::Manifest - utilities to write and check a MANIFEST file
385 require ExtUtils::Manifest;
387 ExtUtils::Manifest::mkmanifest;
389 ExtUtils::Manifest::manicheck;
391 ExtUtils::Manifest::filecheck;
393 ExtUtils::Manifest::fullcheck;
395 ExtUtils::Manifest::skipcheck;
397 ExtUtils::Manifest::manifind();
399 ExtUtils::Manifest::maniread($file);
401 ExtUtils::Manifest::manicopy($read,$target,$how);
405 mkmanifest() writes all files in and below the current directory to a
406 file named in the global variable $ExtUtils::Manifest::MANIFEST (which
407 defaults to C<MANIFEST>) in the current directory. It works similar to
411 but in doing so checks each line in an existing C<MANIFEST> file and
412 includes any comments that are found in the existing C<MANIFEST> file
413 in the new one. Anything between white space and an end of line within
414 a C<MANIFEST> file is considered to be a comment. Filenames and
415 comments are separated by one or more TAB characters in the
416 output. All files that match any regular expression in a file
417 C<MANIFEST.SKIP> (if such a file exists) are ignored.
419 manicheck() checks if all the files within a C<MANIFEST> in the current
420 directory really do exist. If C<MANIFEST> and the tree below the current
421 directory are in sync it exits silently, returning an empty list. Otherwise
422 it returns a list of files which are listed in the C<MANIFEST> but missing
423 from the directory, and by default also outputs these names to STDERR.
425 filecheck() finds files below the current directory that are not
426 mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
427 will be consulted. Any file matching a regular expression in such a
428 file will not be reported as missing in the C<MANIFEST> file. The list of
429 any extraneous files found is returned, and by default also reported to
432 fullcheck() does both a manicheck() and a filecheck(), returning references
433 to two arrays, the first for files manicheck() found to be missing, the
434 seond for unexpeced files found by filecheck().
436 skipcheck() lists all the files that are skipped due to your
437 C<MANIFEST.SKIP> file.
439 manifind() returns a hash reference. The keys of the hash are the
440 files found below the current directory.
442 maniread($file) reads a named C<MANIFEST> file (defaults to
443 C<MANIFEST> in the current directory) and returns a HASH reference
444 with files being the keys and comments being the values of the HASH.
445 Blank lines and lines which start with C<#> in the C<MANIFEST> file
448 C<manicopy($read,$target,$how)> copies the files that are the keys in
449 the HASH I<%$read> to the named target directory. The HASH reference
450 $read is typically returned by the maniread() function. This
451 function is useful for producing a directory tree identical to the
452 intended distribution tree. The third parameter $how can be used to
453 specify a different methods of "copying". Valid values are C<cp>,
454 which actually copies the files, C<ln> which creates hard links, and
455 C<best> which mostly links the files but copies any symbolic link to
456 make a tree without any symbolic link. Best is the default.
460 The file MANIFEST.SKIP may contain regular expressions of files that
461 should be ignored by mkmanifest() and filecheck(). The regular
462 expressions should appear one on each line. Blank lines and lines
463 which start with C<#> are skipped. Use C<\#> if you need a regular
464 expression to start with a sharp character. A typical example:
466 # Version control files and dirs.
471 # Makemaker generated files and dirs.
477 # Temp, old and emacs backup files.
483 If no MANIFEST.SKIP file is found, a default set of skips will be
484 used, similar to the example above. If you want nothing skipped,
485 simply make an empty MANIFEST.SKIP file.
490 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
491 C<&maniread>, and C<&manicopy> are exportable.
493 =head1 GLOBAL VARIABLES
495 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
496 results in both a different C<MANIFEST> and a different
497 C<MANIFEST.SKIP> file. This is useful if you want to maintain
498 different distributions for different audiences (say a user version
499 and a developer version including RCS).
501 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
502 all functions act silently.
504 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
505 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
510 All diagnostic output is sent to C<STDERR>.
514 =item C<Not in MANIFEST:> I<file>
516 is reported if a file is found which is not in C<MANIFEST>.
518 =item C<Skipping> I<file>
520 is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
522 =item C<No such file:> I<file>
524 is reported if a file mentioned in a C<MANIFEST> file does not
527 =item C<MANIFEST:> I<$!>
529 is reported if C<MANIFEST> could not be opened.
531 =item C<Added to MANIFEST:> I<file>
533 is reported by mkmanifest() if $Verbose is set and a file is added
534 to MANIFEST. $Verbose is set to 1 by default.
542 =item B<PERL_MM_MANIFEST_DEBUG>
550 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
554 Andreas Koenig <F<andreas.koenig@anima.de>>