1 package ExtUtils::Manifest;
10 use vars qw($VERSION @ISA @EXPORT_OK
11 $Is_VMS $Debug $Verbose $Quiet $MANIFEST $found);
15 @EXPORT_OK = ('mkmanifest', 'manicheck', 'fullcheck', 'filecheck',
16 'skipcheck', 'maniread', 'manicopy');
18 $Is_VMS = $^O eq 'VMS';
19 if ($Is_VMS) { require File::Basename }
24 $MANIFEST = 'MANIFEST';
26 # Really cool fix from Ilya :)
27 unless (defined $Config{d_link}) {
33 my $read = maniread() or $manimiss++;
34 $read = {} if $manimiss;
36 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
37 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
38 my $matches = _maniskip();
39 my $found = manifind();
40 my($key,$val,$file,%all);
41 %all = (%$found, %$read);
42 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
43 if $manimiss; # add new MANIFEST to known file list
44 foreach $file (sort keys %all) {
45 next if &$matches($file);
47 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
49 my $text = $all{$file};
50 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
51 my $tabs = (5 - (length($file)+1)/8);
52 $tabs = 1 if $tabs < 1;
53 $tabs = 0 unless $text;
54 print M $file, "\t" x $tabs, $text, "\n";
61 find(sub {return if -d $_;
62 (my $name = $File::Find::name) =~ s|./||;
63 warn "Debug: diskfile $name\n" if $Debug;
64 $name =~ s#(.*)\.$#\L$1# if $Is_VMS;
65 $found->{$name} = "";}, ".");
74 return @{(_manicheck(1))[0]};
78 return @{(_manicheck(2))[1]};
87 my $read = maniread();
89 my(@missfile,@missentry);
91 my $found = manifind();
92 foreach $file (sort keys %$read){
93 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
94 unless ( exists $found->{$file} ) {
95 warn "No such file: $file\n" unless $Quiet;
96 push @missfile, $file;
102 my $matches = _maniskip();
103 my $found = manifind();
104 my $skipwarn = $arg & 4;
105 foreach $file (sort keys %$found){
106 if (&$matches($file)){
107 warn "Skipping $file\n" if $skipwarn;
110 warn "Debug: manicheck checking from disk $file\n" if $Debug;
111 unless ( exists $read->{$file} ) {
112 warn "Not in $MANIFEST: $file\n" unless $Quiet;
113 push @missentry, $file;
117 (\@missfile,\@missentry);
122 $mfile = $MANIFEST unless defined $mfile;
125 unless (open M, $mfile){
134 my($base,$dir) = File::Basename::fileparse($file);
135 # Resolve illegal file specifications in the same way as tar
137 my(@pieces) = split(/\./,$base);
138 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
139 my $okfile = "$dir$base";
140 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
141 $read->{"\L$okfile"}=$_;
143 else { /^(\S+)\s*(.*)/ and $read->{$1}=$2; }
149 # returns an anonymous sub that decides if an argument matches
152 my $matches = sub {0};
154 $mfile = "$MANIFEST.SKIP" unless defined $mfile;
156 return $matches unless -f $mfile;
157 open M, $mfile or return $matches;
164 my $opts = $Is_VMS ? 'oi ' : 'o ';
165 my $sub = "\$matches = "
166 . "sub { my(\$arg)=\@_; return 1 if "
167 . join (" || ", (map {s!/!\\/!g; "\$arg =~ m/$_/$opts"} @skip), 0)
170 print "Debug: $sub\n" if $Debug;
175 my($read,$target,$how)=@_;
176 croak "manicopy() called without target argument" unless defined $target;
177 $how = 'cp' unless defined $how && $how;
179 require File::Basename;
181 $target = VMS::Filespec::unixify($target) if $Is_VMS;
182 umask 0 unless $Is_VMS;
183 File::Path::mkpath([ $target ],1,$Is_VMS ? undef : 0755);
184 foreach $file (keys %$read){
185 $file = VMS::Filespec::unixify($file) if $Is_VMS;
186 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
187 my $dir = File::Basename::dirname($file);
188 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
189 File::Path::mkpath(["$target/$dir"],1,$Is_VMS ? undef : 0755);
191 cp_if_diff($file, "$target/$file", $how);
196 my($from, $to, $how)=@_;
197 -f $from || carp "$0: $from not found";
200 open(F,$from) or croak "Can't read $from: $!\n";
202 while (<F>) { $diff++,last if $_ ne <T>; }
203 $diff++ unless eof(T);
210 unlink($to) or confess "unlink $to: $!";
213 best($from,$to), last STRICT_SWITCH if $how eq 'best';
214 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
215 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
221 my ($srcFile, $dstFile) = @_;
222 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
223 copy($srcFile,$dstFile);
224 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
226 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile );
230 my ($srcFile, $dstFile) = @_;
231 return &cp if $Is_VMS;
232 link($srcFile, $dstFile);
233 local($_) = $dstFile; # chmod a+r,go-w+X (except "X" only applies to u=x)
234 my $mode= 0444 | (stat)[2] & 0700;
235 chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ );
239 my ($srcFile, $dstFile) = @_;
241 cp($srcFile, $dstFile);
243 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
253 ExtUtils::Manifest - utilities to write and check a MANIFEST file
257 C<require ExtUtils::Manifest;>
259 C<ExtUtils::Manifest::mkmanifest;>
261 C<ExtUtils::Manifest::manicheck;>
263 C<ExtUtils::Manifest::filecheck;>
265 C<ExtUtils::Manifest::fullcheck;>
267 C<ExtUtils::Manifest::skipcheck;>
269 C<ExtUtild::Manifest::manifind();>
271 C<ExtUtils::Manifest::maniread($file);>
273 C<ExtUtils::Manifest::manicopy($read,$target,$how);>
277 Mkmanifest() writes all files in and below the current directory to a
278 file named in the global variable $ExtUtils::Manifest::MANIFEST (which
279 defaults to C<MANIFEST>) in the current directory. It works similar to
283 but in doing so checks each line in an existing C<MANIFEST> file and
284 includes any comments that are found in the existing C<MANIFEST> file
285 in the new one. Anything between white space and an end of line within
286 a C<MANIFEST> file is considered to be a comment. Filenames and
287 comments are seperated by one or more TAB characters in the
288 output. All files that match any regular expression in a file
289 C<MANIFEST.SKIP> (if such a file exists) are ignored.
291 Manicheck() checks if all the files within a C<MANIFEST> in the
292 current directory really do exist. It only reports discrepancies and
293 exits silently if MANIFEST and the tree below the current directory
296 Filecheck() finds files below the current directory that are not
297 mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
298 will be consulted. Any file matching a regular expression in such a
299 file will not be reported as missing in the C<MANIFEST> file.
301 Fullcheck() does both a manicheck() and a filecheck().
303 Skipcheck() lists all the files that are skipped due to your
304 C<MANIFEST.SKIP> file.
306 Manifind() retruns a hash reference. The keys of the hash are the
307 files found below the current directory.
309 Maniread($file) reads a named C<MANIFEST> file (defaults to
310 C<MANIFEST> in the current directory) and returns a HASH reference
311 with files being the keys and comments being the values of the HASH.
313 I<Manicopy($read,$target,$how)> copies the files that are the keys in
314 the HASH I<%$read> to the named target directory. The HASH reference
315 I<$read> is typically returned by the maniread() function. This
316 function is useful for producing a directory tree identical to the
317 intended distribution tree. The third parameter $how can be used to
318 specify a different methods of "copying". Valid values are C<cp>,
319 which actually copies the files, C<ln> which creates hard links, and
320 C<best> which mostly links the files but copies any symbolic link to
321 make a tree without any symbolic link. Best is the default.
325 The file MANIFEST.SKIP may contain regular expressions of files that
326 should be ignored by mkmanifest() and filecheck(). The regular
327 expressions should appear one on each line. A typical example:
340 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
341 C<&maniread>, and C<&manicopy> are exportable.
343 =head1 GLOBAL VARIABLES
345 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
346 results in both a different C<MANIFEST> and a different
347 C<MANIFEST.SKIP> file. This is useful if you want to maintain
348 different distributions for different audiences (say a user version
349 and a developer version including RCS).
351 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
352 all functions act silently.
356 All diagnostic output is sent to C<STDERR>.
360 =item C<Not in MANIFEST:> I<file>
362 is reported if a file is found, that is missing in the C<MANIFEST>
363 file which is excluded by a regular expression in the file
366 =item C<No such file:> I<file>
368 is reported if a file mentioned in a C<MANIFEST> file does not
371 =item C<MANIFEST:> I<$!>
373 is reported if C<MANIFEST> could not be opened.
375 =item C<Added to MANIFEST:> I<file>
377 is reported by mkmanifest() if $Verbose is set and a file is added
378 to MANIFEST. $Verbose is set to 1 by default.
384 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
388 Andreas Koenig <F<koenig@franz.ww.TU-Berlin.DE>>