1 package ExtUtils::Manifest;
11 use vars qw($VERSION @ISA @EXPORT_OK
13 $Debug $Verbose $Quiet $MANIFEST $DEFAULT_MSKIP);
17 @EXPORT_OK = qw(mkmanifest
18 manicheck filecheck fullcheck skipcheck
19 manifind maniread manicopy maniadd
22 $Is_MacOS = $^O eq 'MacOS';
23 $Is_VMS = $^O eq 'VMS';
24 require VMS::Filespec if $Is_VMS;
26 $Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
27 $Verbose = defined $ENV{PERL_MM_MANIFEST_VERBOSE} ?
28 $ENV{PERL_MM_MANIFEST_VERBOSE} : 1;
30 $MANIFEST = 'MANIFEST';
32 my $manifest_mod = $INC{"ExtUtils/Manifest.pm"} ||
33 ($Is_VMS ? $INC{'extutils/manifest.pm'} : '');
34 $DEFAULT_MSKIP = (File::Spec->splitpath($manifest_mod))[1].
40 ExtUtils::Manifest - utilities to write and check a MANIFEST file
44 use ExtUtils::Manifest qw(...funcs to import...);
48 my @missing_files = manicheck;
49 my @skipped = skipcheck;
50 my @extra_files = filecheck;
51 my($missing, $extra) = fullcheck;
53 my $found = manifind();
55 my $manifest = maniread();
57 manicopy($read,$target);
59 maniadd({$file => $comment, ...});
66 ExtUtils::Manifest exports no functions by default. The following are
75 Writes all files in and below the current directory to your F<MANIFEST>.
80 All files that match any regular expression in a file F<MANIFEST.SKIP>
81 (if it exists) are ignored.
83 Any existing F<MANIFEST> file will be saved as F<MANIFEST.bak>. Lines
84 from the old F<MANIFEST> file is preserved, including any comments
85 that are found in the existing F<MANIFEST> file in the new one.
91 my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
92 $read = {} if $manimiss;
94 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
95 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
96 my $skip = _maniskip();
97 my $found = manifind();
98 my($key,$val,$file,%all);
99 %all = (%$found, %$read);
100 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
101 if $manimiss; # add new MANIFEST to known file list
102 foreach $file (sort keys %all) {
103 if ($skip->($file)) {
104 # Policy: only remove files if they're listed in MANIFEST.SKIP.
105 # Don't remove files just because they don't exist.
106 warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
110 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
112 my $text = $all{$file};
113 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
114 $file = _unmacify($file);
115 my $tabs = (5 - (length($file)+1)/8);
116 $tabs = 1 if $tabs < 1;
117 $tabs = 0 unless $text;
118 print M $file, "\t" x $tabs, $text, "\n";
123 # Geez, shouldn't this use File::Spec or File::Basename or something?
124 # Why so careful about dependencies?
125 sub clean_up_filename {
126 my $filename = shift;
127 $filename =~ s|^\./||;
128 $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
135 my $found = manifind();
137 returns a hash reference. The keys of the hash are the files found
138 below the current directory.
147 my $name = clean_up_filename($File::Find::name);
148 warn "Debug: diskfile $name\n" if $Debug;
152 $name =~ s#(.*)\.$#\L$1#;
153 $name = uc($name) if $name =~ /^MANIFEST(\.SKIP)?$/i;
155 $found->{$name} = "";
158 # We have to use "$File::Find::dir/$_" in preprocess, because
159 # $File::Find::name is unavailable.
160 # Also, it's okay to use / here, because MANIFEST files use Unix-style
162 find({wanted => $wanted},
163 $Is_MacOS ? ":" : ".");
171 my @missing_files = manicheck();
173 checks if all the files within a C<MANIFEST> in the current directory
174 really do exist. If C<MANIFEST> and the tree below the current
175 directory are in sync it exits silently, returning an empty list.
176 Otherwise it returns a list of files which are listed in the
177 C<MANIFEST> but missing from the directory, and by default also
178 outputs these names to STDERR.
183 return _check_files();
189 my @extra_files = filecheck();
191 finds files below the current directory that are not mentioned in the
192 C<MANIFEST> file. An optional file C<MANIFEST.SKIP> will be
193 consulted. Any file matching a regular expression in such a file will
194 not be reported as missing in the C<MANIFEST> file. The list of any
195 extraneous files found is returned, and by default also reported to
201 return _check_manifest();
207 my($missing, $extra) = fullcheck();
209 does both a manicheck() and a filecheck(), returning then as two array
215 return [_check_files()], [_check_manifest()];
221 my @skipped = skipcheck();
223 lists all the files that are skipped due to your C<MANIFEST.SKIP>
230 my $found = manifind();
231 my $matches = _maniskip();
234 foreach my $file (sort keys %$found){
235 if (&$matches($file)){
236 warn "Skipping $file\n";
237 push @skipped, $file;
248 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
249 my $read = maniread() || {};
250 my $found = manifind($p);
253 foreach my $file (sort keys %$read){
254 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
257 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
258 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
260 unless ( exists $found->{$file} ) {
261 warn "No such file: $file\n" unless $Quiet;
262 push @missfile, $file;
270 sub _check_manifest {
272 my $read = maniread() || {};
273 my $found = manifind($p);
274 my $skip = _maniskip();
277 foreach my $file (sort keys %$found){
278 next if $skip->($file);
279 warn "Debug: manicheck checking from disk $file\n" if $Debug;
280 unless ( exists $read->{$file} ) {
281 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
282 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
283 push @missentry, $file;
293 my $manifest = maniread();
294 my $manifest = maniread($manifest_file);
296 reads a named C<MANIFEST> file (defaults to C<MANIFEST> in the current
297 directory) and returns a HASH reference with files being the keys and
298 comments being the values of the HASH. Blank lines and lines which
299 start with C<#> in the C<MANIFEST> file are discarded.
305 $mfile ||= $MANIFEST;
308 unless (open M, $mfile){
316 my($file, $comment) = /^(\S+)\s*(.*)/;
320 $file = _macify($file);
321 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
324 require File::Basename;
325 my($base,$dir) = File::Basename::fileparse($file);
326 # Resolve illegal file specifications in the same way as tar
328 my(@pieces) = split(/\./,$base);
329 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
330 my $okfile = "$dir$base";
331 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
333 $file = lc($file) unless $file =~ /^MANIFEST(\.SKIP)?$/;
336 $read->{$file} = $comment;
342 # returns an anonymous sub that decides if an argument matches
345 my $mfile = "$MANIFEST.SKIP";
347 open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
352 push @skip, _macify($_);
355 my $opts = $Is_VMS ? '(?i)' : '';
357 # Make sure each entry is isolated in its own parentheses, in case
358 # any of them contain alternations
359 my $regex = join '|', map "(?:$_)", @skip;
361 return sub { $_[0] =~ qr{$opts$regex} };
366 manicopy($src, $dest_dir);
367 manicopy($src, $dest_dir, $how);
369 copies the files that are the keys in the HASH I<%$src> to the
370 $dest_dir. The HASH reference $read is typically returned by the
371 maniread() function. This function is useful for producing a directory
372 tree identical to the intended distribution tree. The third parameter
373 $how can be used to specify a different methods of "copying". Valid
374 values are C<cp>, which actually copies the files, C<ln> which creates
375 hard links, and C<best> which mostly links the files but copies any
376 symbolic link to make a tree without any symbolic link. Best is the
382 my($read,$target,$how)=@_;
383 croak "manicopy() called without target argument" unless defined $target;
386 require File::Basename;
388 $target = VMS::Filespec::unixify($target) if $Is_VMS;
389 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
390 foreach my $file (keys %$read){
393 my $dir = _maccat($target, $file);
395 File::Path::mkpath($dir,1,0755);
397 cp_if_diff($file, _maccat($target, $file), $how);
399 $file = VMS::Filespec::unixify($file) if $Is_VMS;
400 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
401 my $dir = File::Basename::dirname($file);
402 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
403 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
405 cp_if_diff($file, "$target/$file", $how);
411 my($from, $to, $how)=@_;
412 -f $from or carp "$0: $from not found";
415 open(F,"< $from\0") or die "Can't read $from: $!\n";
416 if (open(T,"< $to\0")) {
417 while (<F>) { $diff++,last if $_ ne <T>; }
418 $diff++ unless eof(T);
425 unlink($to) or confess "unlink $to: $!";
428 best($from,$to), last STRICT_SWITCH if $how eq 'best';
429 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
430 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
431 croak("ExtUtils::Manifest::cp_if_diff " .
432 "called with illegal how argument [$how]. " .
433 "Legal values are 'best', 'cp', and 'ln'.");
439 my ($srcFile, $dstFile) = @_;
440 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
441 copy($srcFile,$dstFile);
442 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
444 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile )
445 unless ($^O eq 'MacOS');
449 my ($srcFile, $dstFile) = @_;
450 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
451 link($srcFile, $dstFile);
453 # chmod a+r,go-w+X (except "X" only applies to u=x)
454 local($_) = $dstFile;
455 my $mode= 0444 | (stat)[2] & 0700;
456 if (! chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ )) {
463 unless (defined $Config{d_link}) {
464 # Really cool fix from Ilya :)
465 local $SIG{__WARN__} = sub {
466 warn @_ unless $_[0] =~ /^Subroutine .* redefined/;
475 my ($srcFile, $dstFile) = @_;
477 cp($srcFile, $dstFile);
479 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
486 return $file unless $Is_MacOS;
500 return "$f1/$f2" unless $Is_MacOS;
503 $f1 =~ s/([^:]:):/$1/g;
510 return $file unless $Is_MacOS;
513 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
522 maniadd({ $file => $comment, ...});
524 Adds an entry to an existing F<MANIFEST>.
526 $file will be normalized (ie. Unixified). B<UNIMPLEMENTED>
531 my($additions) = shift;
533 _normalize($additions);
535 my $manifest = maniread();
536 open(MANIFEST, ">>$MANIFEST") or die "Could not open $MANIFEST: $!";
537 while( my($file, $comment) = each %$additions ) {
539 printf MANIFEST "%-40s%s\n", $file, $comment unless
540 exists $manifest->{$file};
555 Anything between white space and an end of line within a C<MANIFEST>
556 file is considered to be a comment. Filenames and comments are
557 separated by one or more TAB characters in the output.
562 The file MANIFEST.SKIP may contain regular expressions of files that
563 should be ignored by mkmanifest() and filecheck(). The regular
564 expressions should appear one on each line. Blank lines and lines
565 which start with C<#> are skipped. Use C<\#> if you need a regular
566 expression to start with a sharp character. A typical example:
568 # Version control files and dirs.
574 # Makemaker generated files and dirs.
580 # Temp, old and emacs backup files.
586 If no MANIFEST.SKIP file is found, a default set of skips will be
587 used, similar to the example above. If you want nothing skipped,
588 simply make an empty MANIFEST.SKIP file.
593 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
594 C<&maniread>, and C<&manicopy> are exportable.
596 =head2 GLOBAL VARIABLES
598 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
599 results in both a different C<MANIFEST> and a different
600 C<MANIFEST.SKIP> file. This is useful if you want to maintain
601 different distributions for different audiences (say a user version
602 and a developer version including RCS).
604 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
605 all functions act silently.
607 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
608 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
613 All diagnostic output is sent to C<STDERR>.
617 =item C<Not in MANIFEST:> I<file>
619 is reported if a file is found which is not in C<MANIFEST>.
621 =item C<Skipping> I<file>
623 is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
625 =item C<No such file:> I<file>
627 is reported if a file mentioned in a C<MANIFEST> file does not
630 =item C<MANIFEST:> I<$!>
632 is reported if C<MANIFEST> could not be opened.
634 =item C<Added to MANIFEST:> I<file>
636 is reported by mkmanifest() if $Verbose is set and a file is added
637 to MANIFEST. $Verbose is set to 1 by default.
645 =item B<PERL_MM_MANIFEST_DEBUG>
653 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
657 Andreas Koenig <F<andreas.koenig@anima.de>>