1 package ExtUtils::Manifest;
10 use vars qw(@ISA @EXPORT_OK $VERSION $Debug $Verbose $Is_VMS $Quiet $MANIFEST $found);
13 @EXPORT_OK = ('mkmanifest', 'manicheck', 'fullcheck', 'filecheck',
14 'skipcheck', 'maniread', 'manicopy');
18 $Is_VMS = $^O eq 'VMS';
20 $VERSION = substr(q$Revision: 1.27 $,10,4);
24 $MANIFEST = 'MANIFEST';
26 # Really cool fix from Ilya :)
27 unless (defined $Config{d_link}) {
28 local($^W) = 0; # avoid sub redefined message
34 my $read = maniread() or $manimiss++;
35 $read = {} if $manimiss;
37 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
38 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
39 my $matches = _maniskip();
40 my $found = manifind();
41 my($key,$val,$file,%all);
42 %all = (%$found, %$read);
43 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
44 if $manimiss; # add new MANIFEST to known file list
45 foreach $file (sort keys %all) {
46 next if &$matches($file);
48 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
50 my $text = $all{$file};
51 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
52 my $tabs = (5 - (length($file)+1)/8);
53 $tabs = 1 if $tabs < 1;
54 $tabs = 0 unless $text;
55 print M $file, "\t" x $tabs, $text, "\n";
62 find(sub {return if -d $_;
63 (my $name = $File::Find::name) =~ s|./||;
64 warn "Debug: diskfile $name\n" if $Debug;
65 $name =~ s#(.*)\.$#\L$1# if $Is_VMS;
66 $found->{$name} = "";}, ".");
75 return @{(_manicheck(1))[0]};
79 return @{(_manicheck(2))[1]};
88 my $read = maniread();
90 my(@missfile,@missentry);
92 my $found = manifind();
93 foreach $file (sort keys %$read){
94 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
95 unless ( exists $found->{$file} ) {
96 warn "No such file: $file\n" unless $Quiet;
97 push @missfile, $file;
103 my $matches = _maniskip();
104 my $found = manifind();
105 my $skipwarn = $arg & 4;
106 foreach $file (sort keys %$found){
107 if (&$matches($file)){
108 warn "Skipping $file\n" if $skipwarn;
111 warn "Debug: manicheck checking from disk $file\n" if $Debug;
112 unless ( exists $read->{$file} ) {
113 warn "Not in $MANIFEST: $file\n" unless $Quiet;
114 push @missentry, $file;
118 (\@missfile,\@missentry);
123 $mfile = $MANIFEST unless defined $mfile;
126 unless (open M, $mfile){
132 if ($Is_VMS) { /^(\S+)/ and $read->{"\L$1"}=$_; }
133 else { /^(\S+)\s*(.*)/ and $read->{$1}=$2; }
139 # returns an anonymous sub that decides if an argument matches
142 my $matches = sub {0};
144 $mfile = "$MANIFEST.SKIP" unless defined $mfile;
146 return $matches unless -f $mfile;
147 open M, $mfile or return $matches;
154 my $opts = $Is_VMS ? 'oi ' : 'o ';
155 my $sub = "\$matches = "
156 . "sub { my(\$arg)=\@_; return 1 if "
157 . join (" || ", (map {s!/!\\/!g; "\$arg =~ m/$_/$opts"} @skip), 0)
160 print "Debug: $sub\n" if $Debug;
165 my($read,$target,$how)=@_;
166 croak "manicopy() called without target argument" unless defined $target;
167 $how = 'cp' unless defined $how && $how;
169 require File::Basename;
171 $target = VMS::Filespec::unixify($target) if $Is_VMS;
172 umask 0 unless $Is_VMS;
173 File::Path::mkpath([ $target ],1,$Is_VMS ? undef : 0755);
174 foreach $file (keys %$read){
175 $file = VMS::Filespec::unixify($file) if $Is_VMS;
176 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
177 my $dir = File::Basename::dirname($file);
178 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
179 File::Path::mkpath(["$target/$dir"],1,$Is_VMS ? undef : 0755);
181 if ($Is_VMS) { vms_cp_if_diff($file,"$target/$file"); }
182 else { cp_if_diff($file, "$target/$file", $how); }
187 my($from, $to, $how)=@_;
188 -f $from || carp "$0: $from not found";
191 open(F,$from) or croak "Can't read $from: $!\n";
193 while (<F>) { $diff++,last if $_ ne <T>; }
194 $diff++ unless eof(T);
201 unlink($to) or confess "unlink $to: $!";
204 best($from,$to), last STRICT_SWITCH if $how eq 'best';
205 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
206 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
211 # Do the comparisons here rather than spawning off another process
216 open(F,$from) or croak "Can't read $from: $!\n";
218 while (<F>) { $diff++,last if $_ ne <T>; }
219 $diff++ unless eof(T);
225 system('copy',VMS::Filespec::vmsify($from),VMS::Filespec::vmsify($to)) & 1
226 or confess "Copy failed: $!";
231 my ($srcFile, $dstFile) = @_;
232 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
233 copy($srcFile,$dstFile);
234 utime $access, $mod, $dstFile;
236 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile );
240 my ($srcFile, $dstFile) = @_;
241 link($srcFile, $dstFile);
242 local($_) = $dstFile; # chmod a+r,go-w+X (except "X" only applies to u=x)
243 my $mode= 0444 | (stat)[2] & 0700;
244 chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ );
248 my ($srcFile, $dstFile) = @_;
250 cp($srcFile, $dstFile);
252 ln($srcFile, $dstFile);
262 ExtUtils::Manifest - utilities to write and check a MANIFEST file
266 C<require ExtUtils::Manifest;>
268 C<ExtUtils::Manifest::mkmanifest;>
270 C<ExtUtils::Manifest::manicheck;>
272 C<ExtUtils::Manifest::filecheck;>
274 C<ExtUtils::Manifest::fullcheck;>
276 C<ExtUtils::Manifest::skipcheck;>
278 C<ExtUtild::Manifest::manifind();>
280 C<ExtUtils::Manifest::maniread($file);>
282 C<ExtUtils::Manifest::manicopy($read,$target,$how);>
286 Mkmanifest() writes all files in and below the current directory to a
287 file named in the global variable $ExtUtils::Manifest::MANIFEST (which
288 defaults to C<MANIFEST>) in the current directory. It works similar to
292 but in doing so checks each line in an existing C<MANIFEST> file and
293 includes any comments that are found in the existing C<MANIFEST> file
294 in the new one. Anything between white space and an end of line within
295 a C<MANIFEST> file is considered to be a comment. Filenames and
296 comments are seperated by one or more TAB characters in the
297 output. All files that match any regular expression in a file
298 C<MANIFEST.SKIP> (if such a file exists) are ignored.
300 Manicheck() checks if all the files within a C<MANIFEST> in the
301 current directory really do exist. It only reports discrepancies and
302 exits silently if MANIFEST and the tree below the current directory
305 Filecheck() finds files below the current directory that are not
306 mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
307 will be consulted. Any file matching a regular expression in such a
308 file will not be reported as missing in the C<MANIFEST> file.
310 Fullcheck() does both a manicheck() and a filecheck().
312 Skipcheck() lists all the files that are skipped due to your
313 C<MANIFEST.SKIP> file.
315 Manifind() retruns a hash reference. The keys of the hash are the
316 files found below the current directory.
318 Maniread($file) reads a named C<MANIFEST> file (defaults to
319 C<MANIFEST> in the current directory) and returns a HASH reference
320 with files being the keys and comments being the values of the HASH.
322 I<Manicopy($read,$target,$how)> copies the files that are the keys in
323 the HASH I<%$read> to the named target directory. The HASH reference
324 I<$read> is typically returned by the maniread() function. This
325 function is useful for producing a directory tree identical to the
326 intended distribution tree. The third parameter $how can be used to
327 specify a different methods of "copying". Valid values are C<cp>,
328 which actually copies the files, C<ln> which creates hard links, and
329 C<best> which mostly links the files but copies any symbolic link to
330 make a tree without any symbolic link. Best is the default.
334 The file MANIFEST.SKIP may contain regular expressions of files that
335 should be ignored by mkmanifest() and filecheck(). The regular
336 expressions should appear one on each line. A typical example:
349 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
350 C<&maniread>, and C<&manicopy> are exportable.
352 =head1 GLOBAL VARIABLES
354 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
355 results in both a different C<MANIFEST> and a different
356 C<MANIFEST.SKIP> file. This is useful if you want to maintain
357 different distributions for different audiences (say a user version
358 and a developer version including RCS).
360 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
361 all functions act silently.
365 All diagnostic output is sent to C<STDERR>.
369 =item C<Not in MANIFEST:> I<file>
371 is reported if a file is found, that is missing in the C<MANIFEST>
372 file which is excluded by a regular expression in the file
375 =item C<No such file:> I<file>
377 is reported if a file mentioned in a C<MANIFEST> file does not
380 =item C<MANIFEST:> I<$!>
382 is reported if C<MANIFEST> could not be opened.
384 =item C<Added to MANIFEST:> I<file>
386 is reported by mkmanifest() if $Verbose is set and a file is added
387 to MANIFEST. $Verbose is set to 1 by default.
393 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
397 Andreas Koenig E<lt>F<koenig@franz.ww.TU-Berlin.DE>E<gt>