1 package ExtUtils::Manifest;
7 use File::Spec::Functions qw(splitpath);
11 our ($VERSION,@ISA,@EXPORT_OK,
12 $Is_VMS,$Debug,$Verbose,$Quiet,$MANIFEST,$found,$DEFAULT_MSKIP);
14 $VERSION = substr(q$Revision: 1.33 $, 10);
16 @EXPORT_OK = ('mkmanifest', 'manicheck', 'fullcheck', 'filecheck',
17 'skipcheck', 'maniread', 'manicopy');
19 $Is_MacOS = $^O eq 'MacOS';
20 $Is_VMS = $^O eq 'VMS';
21 if ($Is_VMS) { require File::Basename }
23 $Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
26 $MANIFEST = 'MANIFEST';
27 $DEFAULT_MSKIP = (splitpath($INC{"ExtUtils/Manifest.pm"}))[1]."$MANIFEST.SKIP";
29 # Really cool fix from Ilya :)
30 unless (defined $Config{d_link}) {
37 my $read = maniread() or $manimiss++;
38 $read = {} if $manimiss;
40 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
41 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
42 my $matches = _maniskip();
43 my $found = manifind();
44 my($key,$val,$file,%all);
45 %all = (%$found, %$read);
46 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
47 if $manimiss; # add new MANIFEST to known file list
48 foreach $file (sort keys %all) {
49 next if &$matches($file);
51 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
53 my $text = $all{$file};
54 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
55 $file = _unmacify($file);
56 my $tabs = (5 - (length($file)+1)/8);
57 $tabs = 1 if $tabs < 1;
58 $tabs = 0 unless $text;
59 print M $file, "\t" x $tabs, $text, "\n";
66 find(sub {return if -d $_;
67 (my $name = $File::Find::name) =~ s|^\./||;
68 $name =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
69 warn "Debug: diskfile $name\n" if $Debug;
70 $name =~ s#(.*)\.$#\L$1# if $Is_VMS;
71 $found->{$name} = "";}, $Is_MacOS ? ":" : ".");
80 return @{(_manicheck(1))[0]};
84 return @{(_manicheck(2))[1]};
93 my $read = maniread();
94 my $found = manifind();
96 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
97 my(@missfile,@missentry);
99 foreach $file (sort keys %$read){
100 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
103 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
104 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
106 unless ( exists $found->{$file} ) {
107 warn "No such file: $file\n" unless $Quiet;
108 push @missfile, $file;
114 my $matches = _maniskip();
115 my $skipwarn = $arg & 4;
116 foreach $file (sort keys %$found){
117 if (&$matches($file)){
118 warn "Skipping $file\n" if $skipwarn;
121 warn "Debug: manicheck checking from disk $file\n" if $Debug;
122 unless ( exists $read->{$file} ) {
123 my $canon = "\t" . _unmacify($file) if $Is_MacOS;
124 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
125 push @missentry, $file;
129 (\@missfile,\@missentry);
134 $mfile ||= $MANIFEST;
137 unless (open M, $mfile){
145 my($item,$text) = /^(\S+)\s*(.*)/;
146 $item = _macify($item);
147 $item =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
148 $read->{$item}=$text;
153 my($base,$dir) = File::Basename::fileparse($file);
154 # Resolve illegal file specifications in the same way as tar
156 my(@pieces) = split(/\./,$base);
157 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
158 my $okfile = "$dir$base";
159 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
160 $read->{"\L$okfile"}=$_;
162 else { /^(\S+)\s*(.*)/ and $read->{$1}=$2; }
168 # returns an anonymous sub that decides if an argument matches
171 my $matches = sub {0};
173 $mfile ||= "$MANIFEST.SKIP";
175 open M, $mfile or open M, $DEFAULT_MSKIP or return $matches;
180 push @skip, _macify($_);
183 my $opts = $Is_VMS ? 'oi ' : 'o ';
184 my $sub = "\$matches = "
185 . "sub { my(\$arg)=\@_; return 1 if "
186 . join (" || ", (map {s!/!\\/!g; "\$arg =~ m/$_/$opts"} @skip), 0)
189 print "Debug: $sub\n" if $Debug;
194 my($read,$target,$how)=@_;
195 croak "manicopy() called without target argument" unless defined $target;
198 require File::Basename;
200 $target = VMS::Filespec::unixify($target) if $Is_VMS;
201 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
202 foreach $file (keys %$read){
205 my $dir = _maccat($target, $file);
207 File::Path::mkpath($dir,1,0755);
209 cp_if_diff($file, _maccat($target, $file), $how);
211 $file = VMS::Filespec::unixify($file) if $Is_VMS;
212 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
213 my $dir = File::Basename::dirname($file);
214 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
215 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
217 cp_if_diff($file, "$target/$file", $how);
223 my($from, $to, $how)=@_;
224 -f $from or carp "$0: $from not found";
227 open(F,"< $from\0") or croak "Can't read $from: $!\n";
228 if (open(T,"< $to\0")) {
229 while (<F>) { $diff++,last if $_ ne <T>; }
230 $diff++ unless eof(T);
237 unlink($to) or confess "unlink $to: $!";
240 best($from,$to), last STRICT_SWITCH if $how eq 'best';
241 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
242 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
243 croak("ExtUtils::Manifest::cp_if_diff " .
244 "called with illegal how argument [$how]. " .
245 "Legal values are 'best', 'cp', and 'ln'.");
251 my ($srcFile, $dstFile) = @_;
252 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
253 copy($srcFile,$dstFile);
254 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
256 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile ) unless ($^O eq 'MacOS');
260 my ($srcFile, $dstFile) = @_;
261 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
262 link($srcFile, $dstFile);
263 local($_) = $dstFile; # chmod a+r,go-w+X (except "X" only applies to u=x)
264 my $mode= 0444 | (stat)[2] & 0700;
265 if (! chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ )) {
273 my ($srcFile, $dstFile) = @_;
275 cp($srcFile, $dstFile);
277 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
284 return $file unless $Is_MacOS;
298 return "$f1/$f2" unless $Is_MacOS;
301 $f1 =~ s/([^:]:):/$1/g;
308 return $file unless $Is_MacOS;
311 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
323 ExtUtils::Manifest - utilities to write and check a MANIFEST file
327 require ExtUtils::Manifest;
329 ExtUtils::Manifest::mkmanifest;
331 ExtUtils::Manifest::manicheck;
333 ExtUtils::Manifest::filecheck;
335 ExtUtils::Manifest::fullcheck;
337 ExtUtils::Manifest::skipcheck;
339 ExtUtils::Manifest::manifind();
341 ExtUtils::Manifest::maniread($file);
343 ExtUtils::Manifest::manicopy($read,$target,$how);
347 mkmanifest() writes all files in and below the current directory to a
348 file named in the global variable $ExtUtils::Manifest::MANIFEST (which
349 defaults to C<MANIFEST>) in the current directory. It works similar to
353 but in doing so checks each line in an existing C<MANIFEST> file and
354 includes any comments that are found in the existing C<MANIFEST> file
355 in the new one. Anything between white space and an end of line within
356 a C<MANIFEST> file is considered to be a comment. Filenames and
357 comments are separated by one or more TAB characters in the
358 output. All files that match any regular expression in a file
359 C<MANIFEST.SKIP> (if such a file exists) are ignored.
361 manicheck() checks if all the files within a C<MANIFEST> in the
362 current directory really do exist. It only reports discrepancies and
363 exits silently if MANIFEST and the tree below the current directory
366 filecheck() finds files below the current directory that are not
367 mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
368 will be consulted. Any file matching a regular expression in such a
369 file will not be reported as missing in the C<MANIFEST> file.
371 fullcheck() does both a manicheck() and a filecheck().
373 skipcheck() lists all the files that are skipped due to your
374 C<MANIFEST.SKIP> file.
376 manifind() returns a hash reference. The keys of the hash are the
377 files found below the current directory.
379 maniread($file) reads a named C<MANIFEST> file (defaults to
380 C<MANIFEST> in the current directory) and returns a HASH reference
381 with files being the keys and comments being the values of the HASH.
382 Blank lines and lines which start with C<#> in the C<MANIFEST> file
385 C<manicopy($read,$target,$how)> copies the files that are the keys in
386 the HASH I<%$read> to the named target directory. The HASH reference
387 $read is typically returned by the maniread() function. This
388 function is useful for producing a directory tree identical to the
389 intended distribution tree. The third parameter $how can be used to
390 specify a different methods of "copying". Valid values are C<cp>,
391 which actually copies the files, C<ln> which creates hard links, and
392 C<best> which mostly links the files but copies any symbolic link to
393 make a tree without any symbolic link. Best is the default.
397 The file MANIFEST.SKIP may contain regular expressions of files that
398 should be ignored by mkmanifest() and filecheck(). The regular
399 expressions should appear one on each line. Blank lines and lines
400 which start with C<#> are skipped. Use C<\#> if you need a regular
401 expression to start with a sharp character. A typical example:
403 # Version control files and dirs.
408 # Makemaker generated files and dirs.
414 # Temp, old and emacs backup files.
420 If no MANIFEST.SKIP file is found, a default set of skips will be
421 used, similar to the example above. If you want nothing skipped,
422 simply make an empty MANIFEST.SKIP file.
427 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
428 C<&maniread>, and C<&manicopy> are exportable.
430 =head1 GLOBAL VARIABLES
432 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
433 results in both a different C<MANIFEST> and a different
434 C<MANIFEST.SKIP> file. This is useful if you want to maintain
435 different distributions for different audiences (say a user version
436 and a developer version including RCS).
438 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
439 all functions act silently.
441 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
442 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
447 All diagnostic output is sent to C<STDERR>.
451 =item C<Not in MANIFEST:> I<file>
453 is reported if a file is found, that is missing in the C<MANIFEST>
454 file which is excluded by a regular expression in the file
457 =item C<No such file:> I<file>
459 is reported if a file mentioned in a C<MANIFEST> file does not
462 =item C<MANIFEST:> I<$!>
464 is reported if C<MANIFEST> could not be opened.
466 =item C<Added to MANIFEST:> I<file>
468 is reported by mkmanifest() if $Verbose is set and a file is added
469 to MANIFEST. $Verbose is set to 1 by default.
477 =item B<PERL_MM_MANIFEST_DEBUG>
485 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
489 Andreas Koenig <F<andreas.koenig@anima.de>>