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 $found->{$name} = "";}, $Is_MacOS ? ":" : ".");
81 return @{(_manicheck(1))[0]};
85 return @{(_manicheck(2))[1]};
94 my $read = maniread();
95 my $found = manifind();
97 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
98 my(@missfile,@missentry);
100 foreach $file (sort keys %$read){
101 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
104 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
105 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
107 unless ( exists $found->{$file} ) {
108 warn "No such file: $file\n" unless $Quiet;
109 push @missfile, $file;
115 my $matches = _maniskip();
116 my $skipwarn = $arg & 4;
117 foreach $file (sort keys %$found){
118 if (&$matches($file)){
119 warn "Skipping $file\n" if $skipwarn;
122 warn "Debug: manicheck checking from disk $file\n" if $Debug;
123 unless ( exists $read->{$file} ) {
124 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
125 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
126 push @missentry, $file;
130 (\@missfile,\@missentry);
135 $mfile ||= $MANIFEST;
138 unless (open M, $mfile){
146 my($file, $comment) = /^(\S+)\s*(.*)/;
150 $file = _macify($file);
151 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
154 my($base,$dir) = File::Basename::fileparse($file);
155 # Resolve illegal file specifications in the same way as tar
157 my(@pieces) = split(/\./,$base);
158 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
159 my $okfile = "$dir$base";
160 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
164 $read->{$file} = $comment;
170 # returns an anonymous sub that decides if an argument matches
173 my $matches = sub {0};
175 $mfile ||= "$MANIFEST.SKIP";
177 open M, $mfile or open M, $DEFAULT_MSKIP or return $matches;
182 push @skip, _macify($_);
185 my $opts = $Is_VMS ? 'oi ' : 'o ';
186 my $sub = "\$matches = "
187 . "sub { my(\$arg)=\@_; return 1 if "
188 . join (" || ", (map {s!/!\\/!g; "\$arg =~ m/$_/$opts"} @skip), 0)
191 print "Debug: $sub\n" if $Debug;
196 my($read,$target,$how)=@_;
197 croak "manicopy() called without target argument" unless defined $target;
200 require File::Basename;
202 $target = VMS::Filespec::unixify($target) if $Is_VMS;
203 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
204 foreach $file (keys %$read){
207 my $dir = _maccat($target, $file);
209 File::Path::mkpath($dir,1,0755);
211 cp_if_diff($file, _maccat($target, $file), $how);
213 $file = VMS::Filespec::unixify($file) if $Is_VMS;
214 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
215 my $dir = File::Basename::dirname($file);
216 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
217 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
219 cp_if_diff($file, "$target/$file", $how);
225 my($from, $to, $how)=@_;
226 -f $from or carp "$0: $from not found";
229 open(F,"< $from\0") or croak "Can't read $from: $!\n";
230 if (open(T,"< $to\0")) {
231 while (<F>) { $diff++,last if $_ ne <T>; }
232 $diff++ unless eof(T);
239 unlink($to) or confess "unlink $to: $!";
242 best($from,$to), last STRICT_SWITCH if $how eq 'best';
243 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
244 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
245 croak("ExtUtils::Manifest::cp_if_diff " .
246 "called with illegal how argument [$how]. " .
247 "Legal values are 'best', 'cp', and 'ln'.");
253 my ($srcFile, $dstFile) = @_;
254 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
255 copy($srcFile,$dstFile);
256 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
258 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile ) unless ($^O eq 'MacOS');
262 my ($srcFile, $dstFile) = @_;
263 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
264 link($srcFile, $dstFile);
265 local($_) = $dstFile; # chmod a+r,go-w+X (except "X" only applies to u=x)
266 my $mode= 0444 | (stat)[2] & 0700;
267 if (! chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ )) {
275 my ($srcFile, $dstFile) = @_;
277 cp($srcFile, $dstFile);
279 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
286 return $file unless $Is_MacOS;
300 return "$f1/$f2" unless $Is_MacOS;
303 $f1 =~ s/([^:]:):/$1/g;
310 return $file unless $Is_MacOS;
313 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
325 ExtUtils::Manifest - utilities to write and check a MANIFEST file
329 require ExtUtils::Manifest;
331 ExtUtils::Manifest::mkmanifest;
333 ExtUtils::Manifest::manicheck;
335 ExtUtils::Manifest::filecheck;
337 ExtUtils::Manifest::fullcheck;
339 ExtUtils::Manifest::skipcheck;
341 ExtUtils::Manifest::manifind();
343 ExtUtils::Manifest::maniread($file);
345 ExtUtils::Manifest::manicopy($read,$target,$how);
349 mkmanifest() writes all files in and below the current directory to a
350 file named in the global variable $ExtUtils::Manifest::MANIFEST (which
351 defaults to C<MANIFEST>) in the current directory. It works similar to
355 but in doing so checks each line in an existing C<MANIFEST> file and
356 includes any comments that are found in the existing C<MANIFEST> file
357 in the new one. Anything between white space and an end of line within
358 a C<MANIFEST> file is considered to be a comment. Filenames and
359 comments are separated by one or more TAB characters in the
360 output. All files that match any regular expression in a file
361 C<MANIFEST.SKIP> (if such a file exists) are ignored.
363 manicheck() checks if all the files within a C<MANIFEST> in the
364 current directory really do exist. It only reports discrepancies and
365 exits silently if MANIFEST and the tree below the current directory
368 filecheck() finds files below the current directory that are not
369 mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
370 will be consulted. Any file matching a regular expression in such a
371 file will not be reported as missing in the C<MANIFEST> file.
373 fullcheck() does both a manicheck() and a filecheck().
375 skipcheck() lists all the files that are skipped due to your
376 C<MANIFEST.SKIP> file.
378 manifind() returns a hash reference. The keys of the hash are the
379 files found below the current directory.
381 maniread($file) reads a named C<MANIFEST> file (defaults to
382 C<MANIFEST> in the current directory) and returns a HASH reference
383 with files being the keys and comments being the values of the HASH.
384 Blank lines and lines which start with C<#> in the C<MANIFEST> file
387 C<manicopy($read,$target,$how)> copies the files that are the keys in
388 the HASH I<%$read> to the named target directory. The HASH reference
389 $read is typically returned by the maniread() function. This
390 function is useful for producing a directory tree identical to the
391 intended distribution tree. The third parameter $how can be used to
392 specify a different methods of "copying". Valid values are C<cp>,
393 which actually copies the files, C<ln> which creates hard links, and
394 C<best> which mostly links the files but copies any symbolic link to
395 make a tree without any symbolic link. Best is the default.
399 The file MANIFEST.SKIP may contain regular expressions of files that
400 should be ignored by mkmanifest() and filecheck(). The regular
401 expressions should appear one on each line. Blank lines and lines
402 which start with C<#> are skipped. Use C<\#> if you need a regular
403 expression to start with a sharp character. A typical example:
405 # Version control files and dirs.
410 # Makemaker generated files and dirs.
416 # Temp, old and emacs backup files.
422 If no MANIFEST.SKIP file is found, a default set of skips will be
423 used, similar to the example above. If you want nothing skipped,
424 simply make an empty MANIFEST.SKIP file.
429 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
430 C<&maniread>, and C<&manicopy> are exportable.
432 =head1 GLOBAL VARIABLES
434 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
435 results in both a different C<MANIFEST> and a different
436 C<MANIFEST.SKIP> file. This is useful if you want to maintain
437 different distributions for different audiences (say a user version
438 and a developer version including RCS).
440 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
441 all functions act silently.
443 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
444 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
449 All diagnostic output is sent to C<STDERR>.
453 =item C<Not in MANIFEST:> I<file>
455 is reported if a file is found, that is missing in the C<MANIFEST>
456 file which is excluded by a regular expression in the file
459 =item C<No such file:> I<file>
461 is reported if a file mentioned in a C<MANIFEST> file does not
464 =item C<MANIFEST:> I<$!>
466 is reported if C<MANIFEST> could not be opened.
468 =item C<Added to MANIFEST:> I<file>
470 is reported by mkmanifest() if $Verbose is set and a file is added
471 to MANIFEST. $Verbose is set to 1 by default.
479 =item B<PERL_MM_MANIFEST_DEBUG>
487 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
491 Andreas Koenig <F<andreas.koenig@anima.de>>