1 package ExtUtils::Manifest;
6 @EXPORT_OK = ('mkmanifest', 'manicheck', 'fullcheck', 'filecheck',
7 'skipcheck', 'maniread', 'manicopy');
11 use File::Copy 'copy';
16 $Is_VMS = $^O eq 'VMS';
18 $VERSION = $VERSION = substr(q$Revision: 1.24 $,10,4);
22 $MANIFEST = 'MANIFEST';
24 # Really cool fix from Ilya :)
25 unless (defined $Config{d_link}) {
31 my $read = maniread() or $manimiss++;
32 $read = {} if $manimiss;
34 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
35 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
36 my $matches = _maniskip();
37 my $found = manifind();
38 my($key,$val,$file,%all);
39 %all = (%$found, %$read);
40 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
41 if $manimiss; # add new MANIFEST to known file list
42 foreach $file (sort keys %all) {
43 next if &$matches($file);
45 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
47 my $text = $all{$file};
48 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
49 my $tabs = (5 - (length($file)+1)/8);
50 $tabs = 1 if $tabs < 1;
51 $tabs = 0 unless $text;
52 print M $file, "\t" x $tabs, $text, "\n";
59 find(sub {return if -d $_;
60 (my $name = $File::Find::name) =~ s|./||;
61 warn "Debug: diskfile $name\n" if $Debug;
62 $name =~ s#(.*)\.$#\L$1# if $Is_VMS;
63 $found->{$name} = "";}, ".");
72 return @{(_manicheck(1))[0]};
76 return @{(_manicheck(2))[1]};
85 my $read = maniread();
87 my(@missfile,@missentry);
89 my $found = manifind();
90 foreach $file (sort keys %$read){
91 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
92 unless ( exists $found->{$file} ) {
93 warn "No such file: $file\n" unless $Quiet;
94 push @missfile, $file;
100 my $matches = _maniskip();
101 my $found = manifind();
102 my $skipwarn = $arg & 4;
103 foreach $file (sort keys %$found){
104 if (&$matches($file)){
105 warn "Skipping $file\n" if $skipwarn;
108 warn "Debug: manicheck checking from disk $file\n" if $Debug;
109 unless ( exists $read->{$file} ) {
110 warn "Not in $MANIFEST: $file\n" unless $Quiet;
111 push @missentry, $file;
115 (\@missfile,\@missentry);
120 $mfile = $MANIFEST unless defined $mfile;
123 unless (open M, $mfile){
129 if ($Is_VMS) { /^(\S+)/ and $read->{"\L$1"}=$_; }
130 else { /^(\S+)\s*(.*)/ and $read->{$1}=$2; }
136 # returns an anonymous sub that decides if an argument matches
139 my $matches = sub {0};
141 $mfile = "$MANIFEST.SKIP" unless defined $mfile;
143 return $matches unless -f $mfile;
144 open M, $mfile or return $matches;
151 my $opts = $Is_VMS ? 'oi ' : 'o ';
152 my $sub = "\$matches = "
153 . "sub { my(\$arg)=\@_; return 1 if "
154 . join (" || ", (map {s!/!\\/!g; "\$arg =~ m/$_/$opts"} @skip), 0)
157 print "Debug: $sub\n" if $Debug;
162 my($read,$target,$how)=@_;
163 croak "manicopy() called without target argument" unless defined $target;
164 $how = 'cp' unless defined $how && $how;
166 require File::Basename;
168 $target = VMS::Filespec::unixify($target) if $Is_VMS;
169 umask 0 unless $Is_VMS;
170 File::Path::mkpath([ $target ],1,$Is_VMS ? undef : 0755);
171 foreach $file (keys %$read){
172 $file = VMS::Filespec::unixify($file) if $Is_VMS;
173 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
174 my $dir = File::Basename::dirname($file);
175 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
176 File::Path::mkpath(["$target/$dir"],1,$Is_VMS ? undef : 0755);
178 if ($Is_VMS) { vms_cp_if_diff($file,"$target/$file"); }
179 else { cp_if_diff($file, "$target/$file", $how); }
184 my($from,$to, $how)=@_;
185 -f $from || carp "$0: $from not found";
188 open(F,$from) or croak "Can't read $from: $!\n";
190 while (<F>) { $diff++,last if $_ ne <T>; }
191 $diff++ unless eof(T);
198 unlink($to) or confess "unlink $to: $!";
204 # Do the comparisons here rather than spawning off another process
209 open(F,$from) or croak "Can't read $from: $!\n";
211 while (<F>) { $diff++,last if $_ ne <T>; }
212 $diff++ unless eof(T);
218 system('copy',VMS::Filespec::vmsify($from),VMS::Filespec::vmsify($to)) & 1
219 or confess "Copy failed: $!";
224 my ($srcFile, $dstFile) = @_;
225 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
226 copy($srcFile,$dstFile);
227 utime $access, $mod, $dstFile;
229 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile );
233 my ($srcFile, $dstFile) = @_;
234 link($srcFile, $dstFile);
235 local($_) = $dstFile; # chmod a+r,go-w+X (except "X" only applies to u=x)
236 my $mode= 0444 | (stat)[2] & 0700;
237 chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ );
241 my ($srcFile, $dstFile) = @_;
243 cp($srcFile, $dstFile);
245 ln($srcFile, $dstFile);
255 ExtUtils::Manifest - utilities to write and check a MANIFEST file
259 C<require ExtUtils::Manifest;>
261 C<ExtUtils::Manifest::mkmanifest;>
263 C<ExtUtils::Manifest::manicheck;>
265 C<ExtUtils::Manifest::filecheck;>
267 C<ExtUtils::Manifest::fullcheck;>
269 C<ExtUtils::Manifest::skipcheck;>
271 C<ExtUtild::Manifest::manifind();>
273 C<ExtUtils::Manifest::maniread($file);>
275 C<ExtUtils::Manifest::manicopy($read,$target,$how);>
279 Mkmanifest() writes all files in and below the current directory to a
280 file named in the global variable $ExtUtils::Manifest::MANIFEST (which
281 defaults to C<MANIFEST>) in the current directory. It works similar to
285 but in doing so checks each line in an existing C<MANIFEST> file and
286 includes any comments that are found in the existing C<MANIFEST> file
287 in the new one. Anything between white space and an end of line within
288 a C<MANIFEST> file is considered to be a comment. Filenames and
289 comments are seperated by one or more TAB characters in the
290 output. All files that match any regular expression in a file
291 C<MANIFEST.SKIP> (if such a file exists) are ignored.
293 Manicheck() checks if all the files within a C<MANIFEST> in the
294 current directory really do exist. It only reports discrepancies and
295 exits silently if MANIFEST and the tree below the current directory
298 Filecheck() finds files below the current directory that are not
299 mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
300 will be consulted. Any file matching a regular expression in such a
301 file will not be reported as missing in the C<MANIFEST> file.
303 Fullcheck() does both a manicheck() and a filecheck().
305 Skipcheck() lists all the files that are skipped due to your
306 C<MANIFEST.SKIP> file.
308 Manifind() retruns a hash reference. The keys of the hash are the
309 files found below the current directory.
311 Maniread($file) reads a named C<MANIFEST> file (defaults to
312 C<MANIFEST> in the current directory) and returns a HASH reference
313 with files being the keys and comments being the values of the HASH.
315 I<Manicopy($read,$target,$how)> copies the files that are the keys in
316 the HASH I<%$read> to the named target directory. The HASH reference
317 I<$read> is typically returned by the maniread() function. This
318 function is useful for producing a directory tree identical to the
319 intended distribution tree. The third parameter $how can be used to
320 specify a different methods of "copying". Valid values are C<cp>,
321 which actually copies the files, C<ln> which creates hard links, and
322 C<best> which mostly links the files but copies any symbolic link to
323 make a tree without any symbolic link. Best is the default.
327 The file MANIFEST.SKIP may contain regular expressions of files that
328 should be ignored by mkmanifest() and filecheck(). The regular
329 expressions should appear one on each line. A typical example:
342 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
343 C<&maniread>, and C<&manicopy> are exportable.
345 =head1 GLOBAL VARIABLES
347 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
348 results in both a different C<MANIFEST> and a different
349 C<MANIFEST.SKIP> file. This is useful if you want to maintain
350 different distributions for different audiences (say a user version
351 and a developer version including RCS).
353 <$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
354 all functions act silently.
358 All diagnostic output is sent to C<STDERR>.
362 =item C<Not in MANIFEST:> I<file>
364 is reported if a file is found, that is missing in the C<MANIFEST>
365 file which is excluded by a regular expression in the file
368 =item C<No such file:> I<file>
370 is reported if a file mentioned in a C<MANIFEST> file does not
373 =item C<MANIFEST:> I<$!>
375 is reported if C<MANIFEST> could not be opened.
377 =item C<Added to MANIFEST:> I<file>
379 is reported by mkmanifest() if $Verbose is set and a file is added
380 to MANIFEST. $Verbose is set to 1 by default.
386 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
390 Andreas Koenig F<E<lt>koenig@franz.ww.TU-Berlin.DEE<gt>>