1 package ExtUtils::Manifest;
7 use File::Spec::Functions qw(splitpath);
11 our ($VERSION,@ISA,@EXPORT_OK,
13 $Debug,$Verbose,$Quiet,$MANIFEST,$found,$DEFAULT_MSKIP);
15 $VERSION = substr(q$Revision: 1.35 $, 10);
17 @EXPORT_OK = ('mkmanifest', 'manicheck', 'fullcheck', 'filecheck',
18 'skipcheck', 'maniread', 'manicopy');
20 $Is_MacOS = $^O eq 'MacOS';
21 $Is_VMS = $^O eq 'VMS';
22 if ($Is_VMS) { require File::Basename }
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 $matches = _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) {
50 next if &$matches($file);
52 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
54 my $text = $all{$file};
55 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
56 $file = _unmacify($file);
57 my $tabs = (5 - (length($file)+1)/8);
58 $tabs = 1 if $tabs < 1;
59 $tabs = 0 unless $text;
60 print M $file, "\t" x $tabs, $text, "\n";
67 find(sub {return if -d $_;
68 (my $name = $File::Find::name) =~ s|^\./||;
69 $name =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
70 warn "Debug: diskfile $name\n" if $Debug;
71 $name =~ s#(.*)\.$#\L$1# if $Is_VMS;
72 $name = uc($name) if /^MANIFEST/i && $Is_VMS;
73 $found->{$name} = "";}, $Is_MacOS ? ":" : ".");
82 return @{(_manicheck(1))[0]};
86 return @{(_manicheck(2))[1]};
95 my $read = maniread();
96 my $found = manifind();
98 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
99 my(@missfile,@missentry);
101 foreach $file (sort keys %$read){
102 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
105 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
106 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
108 unless ( exists $found->{$file} ) {
109 warn "No such file: $file\n" unless $Quiet;
110 push @missfile, $file;
116 my $matches = _maniskip();
117 my $skipwarn = $arg & 4;
118 foreach $file (sort keys %$found){
119 if (&$matches($file)){
120 warn "Skipping $file\n" if $skipwarn;
123 warn "Debug: manicheck checking from disk $file\n" if $Debug;
124 unless ( exists $read->{$file} ) {
125 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
126 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
127 push @missentry, $file;
131 (\@missfile,\@missentry);
136 $mfile ||= $MANIFEST;
139 unless (open M, $mfile){
147 my($file, $comment) = /^(\S+)\s*(.*)/;
151 $file = _macify($file);
152 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
155 my($base,$dir) = File::Basename::fileparse($file);
156 # Resolve illegal file specifications in the same way as tar
158 my(@pieces) = split(/\./,$base);
159 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
160 my $okfile = "$dir$base";
161 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
163 $file = lc($file) unless $file =~ /^MANIFEST/i;
166 $read->{$file} = $comment;
172 # returns an anonymous sub that decides if an argument matches
175 my $matches = sub {0};
177 $mfile ||= "$MANIFEST.SKIP";
179 open M, $mfile or open M, $DEFAULT_MSKIP or return $matches;
184 push @skip, _macify($_);
187 my $opts = $Is_VMS ? 'oi ' : 'o ';
188 my $sub = "\$matches = "
189 . "sub { my(\$arg)=\@_; return 1 if "
190 . join (" || ", (map {s!/!\\/!g; "\$arg =~ m/$_/$opts"} @skip), 0)
193 print "Debug: $sub\n" if $Debug;
198 my($read,$target,$how)=@_;
199 croak "manicopy() called without target argument" unless defined $target;
202 require File::Basename;
204 $target = VMS::Filespec::unixify($target) if $Is_VMS;
205 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
206 foreach $file (keys %$read){
209 my $dir = _maccat($target, $file);
211 File::Path::mkpath($dir,1,0755);
213 cp_if_diff($file, _maccat($target, $file), $how);
215 $file = VMS::Filespec::unixify($file) if $Is_VMS;
216 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
217 my $dir = File::Basename::dirname($file);
218 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
219 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
221 cp_if_diff($file, "$target/$file", $how);
227 my($from, $to, $how)=@_;
228 -f $from or carp "$0: $from not found";
231 open(F,"< $from\0") or croak "Can't read $from: $!\n";
232 if (open(T,"< $to\0")) {
233 while (<F>) { $diff++,last if $_ ne <T>; }
234 $diff++ unless eof(T);
241 unlink($to) or confess "unlink $to: $!";
244 best($from,$to), last STRICT_SWITCH if $how eq 'best';
245 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
246 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
247 croak("ExtUtils::Manifest::cp_if_diff " .
248 "called with illegal how argument [$how]. " .
249 "Legal values are 'best', 'cp', and 'ln'.");
255 my ($srcFile, $dstFile) = @_;
256 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
257 copy($srcFile,$dstFile);
258 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
260 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile ) unless ($^O eq 'MacOS');
264 my ($srcFile, $dstFile) = @_;
265 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
266 link($srcFile, $dstFile);
267 local($_) = $dstFile; # chmod a+r,go-w+X (except "X" only applies to u=x)
268 my $mode= 0444 | (stat)[2] & 0700;
269 if (! chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ )) {
277 my ($srcFile, $dstFile) = @_;
279 cp($srcFile, $dstFile);
281 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
288 return $file unless $Is_MacOS;
302 return "$f1/$f2" unless $Is_MacOS;
305 $f1 =~ s/([^:]:):/$1/g;
312 return $file unless $Is_MacOS;
315 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
327 ExtUtils::Manifest - utilities to write and check a MANIFEST file
331 require ExtUtils::Manifest;
333 ExtUtils::Manifest::mkmanifest;
335 ExtUtils::Manifest::manicheck;
337 ExtUtils::Manifest::filecheck;
339 ExtUtils::Manifest::fullcheck;
341 ExtUtils::Manifest::skipcheck;
343 ExtUtils::Manifest::manifind();
345 ExtUtils::Manifest::maniread($file);
347 ExtUtils::Manifest::manicopy($read,$target,$how);
351 mkmanifest() writes all files in and below the current directory to a
352 file named in the global variable $ExtUtils::Manifest::MANIFEST (which
353 defaults to C<MANIFEST>) in the current directory. It works similar to
357 but in doing so checks each line in an existing C<MANIFEST> file and
358 includes any comments that are found in the existing C<MANIFEST> file
359 in the new one. Anything between white space and an end of line within
360 a C<MANIFEST> file is considered to be a comment. Filenames and
361 comments are separated by one or more TAB characters in the
362 output. All files that match any regular expression in a file
363 C<MANIFEST.SKIP> (if such a file exists) are ignored.
365 manicheck() checks if all the files within a C<MANIFEST> in the
366 current directory really do exist. It only reports discrepancies and
367 exits silently if MANIFEST and the tree below the current directory
370 filecheck() finds files below the current directory that are not
371 mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
372 will be consulted. Any file matching a regular expression in such a
373 file will not be reported as missing in the C<MANIFEST> file.
375 fullcheck() does both a manicheck() and a filecheck().
377 skipcheck() lists all the files that are skipped due to your
378 C<MANIFEST.SKIP> file.
380 manifind() returns a hash reference. The keys of the hash are the
381 files found below the current directory.
383 maniread($file) reads a named C<MANIFEST> file (defaults to
384 C<MANIFEST> in the current directory) and returns a HASH reference
385 with files being the keys and comments being the values of the HASH.
386 Blank lines and lines which start with C<#> in the C<MANIFEST> file
389 C<manicopy($read,$target,$how)> copies the files that are the keys in
390 the HASH I<%$read> to the named target directory. The HASH reference
391 $read is typically returned by the maniread() function. This
392 function is useful for producing a directory tree identical to the
393 intended distribution tree. The third parameter $how can be used to
394 specify a different methods of "copying". Valid values are C<cp>,
395 which actually copies the files, C<ln> which creates hard links, and
396 C<best> which mostly links the files but copies any symbolic link to
397 make a tree without any symbolic link. Best is the default.
401 The file MANIFEST.SKIP may contain regular expressions of files that
402 should be ignored by mkmanifest() and filecheck(). The regular
403 expressions should appear one on each line. Blank lines and lines
404 which start with C<#> are skipped. Use C<\#> if you need a regular
405 expression to start with a sharp character. A typical example:
407 # Version control files and dirs.
412 # Makemaker generated files and dirs.
418 # Temp, old and emacs backup files.
424 If no MANIFEST.SKIP file is found, a default set of skips will be
425 used, similar to the example above. If you want nothing skipped,
426 simply make an empty MANIFEST.SKIP file.
431 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
432 C<&maniread>, and C<&manicopy> are exportable.
434 =head1 GLOBAL VARIABLES
436 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
437 results in both a different C<MANIFEST> and a different
438 C<MANIFEST.SKIP> file. This is useful if you want to maintain
439 different distributions for different audiences (say a user version
440 and a developer version including RCS).
442 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
443 all functions act silently.
445 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
446 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
451 All diagnostic output is sent to C<STDERR>.
455 =item C<Not in MANIFEST:> I<file>
457 is reported if a file is found, that is missing in the C<MANIFEST>
458 file which is excluded by a regular expression in the file
461 =item C<No such file:> I<file>
463 is reported if a file mentioned in a C<MANIFEST> file does not
466 =item C<MANIFEST:> I<$!>
468 is reported if C<MANIFEST> could not be opened.
470 =item C<Added to MANIFEST:> I<file>
472 is reported by mkmanifest() if $Verbose is set and a file is added
473 to MANIFEST. $Verbose is set to 1 by default.
481 =item B<PERL_MM_MANIFEST_DEBUG>
489 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
493 Andreas Koenig <F<andreas.koenig@anima.de>>