Pod typos, pod2man bugs, and miscellaneous installation comments
[p5sagit/p5-mst-13.2.git] / lib / ExtUtils / Manifest.pm
CommitLineData
005c1a0e 1package ExtUtils::Manifest;
2
005c1a0e 3require Exporter;
8e07c86e 4use Config;
005c1a0e 5use File::Find;
79dd614e 6use File::Copy 'copy';
005c1a0e 7use Carp;
8a1da95f 8use strict;
9
10use vars qw(@ISA @EXPORT_OK $VERSION $Debug $Verbose $Is_VMS $Quiet $MANIFEST $found);
11
12@ISA=('Exporter');
13@EXPORT_OK = ('mkmanifest', 'manicheck', 'fullcheck', 'filecheck',
14 'skipcheck', 'maniread', 'manicopy');
005c1a0e 15
16$Debug = 0;
17$Verbose = 1;
79dd614e 18$Is_VMS = $^O eq 'VMS';
005c1a0e 19
8a1da95f 20$VERSION = substr(q$Revision: 1.27 $,10,4);
005c1a0e 21
22$Quiet = 0;
23
cb1a09d0 24$MANIFEST = 'MANIFEST';
25
4e68a208 26# Really cool fix from Ilya :)
27unless (defined $Config{d_link}) {
28 *ln = \&cp;
29}
30
005c1a0e 31sub mkmanifest {
32 my $manimiss = 0;
33 my $read = maniread() or $manimiss++;
34 $read = {} if $manimiss;
864a5fa8 35 local *M;
cb1a09d0 36 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
37 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
005c1a0e 38 my $matches = _maniskip();
39 my $found = manifind();
40 my($key,$val,$file,%all);
f1387719 41 %all = (%$found, %$read);
84876ac5 42 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
43 if $manimiss; # add new MANIFEST to known file list
005c1a0e 44 foreach $file (sort keys %all) {
45 next if &$matches($file);
46 if ($Verbose){
cb1a09d0 47 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
005c1a0e 48 }
8e07c86e 49 my $text = $all{$file};
84876ac5 50 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
005c1a0e 51 my $tabs = (5 - (length($file)+1)/8);
52 $tabs = 1 if $tabs < 1;
8e07c86e 53 $tabs = 0 unless $text;
54 print M $file, "\t" x $tabs, $text, "\n";
005c1a0e 55 }
56 close M;
57}
58
59sub manifind {
60 local $found = {};
4633a7c4 61 find(sub {return if -d $_;
005c1a0e 62 (my $name = $File::Find::name) =~ s|./||;
63 warn "Debug: diskfile $name\n" if $Debug;
8e07c86e 64 $name =~ s#(.*)\.$#\L$1# if $Is_VMS;
005c1a0e 65 $found->{$name} = "";}, ".");
66 $found;
67}
68
69sub fullcheck {
70 _manicheck(3);
71}
72
73sub manicheck {
74 return @{(_manicheck(1))[0]};
75}
76
77sub filecheck {
78 return @{(_manicheck(2))[1]};
79}
80
8e07c86e 81sub skipcheck {
82 _manicheck(6);
83}
84
005c1a0e 85sub _manicheck {
86 my($arg) = @_;
87 my $read = maniread();
88 my $file;
89 my(@missfile,@missentry);
90 if ($arg & 1){
91 my $found = manifind();
92 foreach $file (sort keys %$read){
cb1a09d0 93 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
005c1a0e 94 unless ( exists $found->{$file} ) {
8e07c86e 95 warn "No such file: $file\n" unless $Quiet;
96 push @missfile, $file;
005c1a0e 97 }
98 }
99 }
100 if ($arg & 2){
101 $read ||= {};
102 my $matches = _maniskip();
103 my $found = manifind();
8e07c86e 104 my $skipwarn = $arg & 4;
005c1a0e 105 foreach $file (sort keys %$found){
8e07c86e 106 if (&$matches($file)){
107 warn "Skipping $file\n" if $skipwarn;
108 next;
109 }
005c1a0e 110 warn "Debug: manicheck checking from disk $file\n" if $Debug;
111 unless ( exists $read->{$file} ) {
cb1a09d0 112 warn "Not in $MANIFEST: $file\n" unless $Quiet;
8e07c86e 113 push @missentry, $file;
005c1a0e 114 }
115 }
116 }
117 (\@missfile,\@missentry);
118}
119
120sub maniread {
121 my ($mfile) = @_;
cb1a09d0 122 $mfile = $MANIFEST unless defined $mfile;
005c1a0e 123 my $read = {};
124 local *M;
125 unless (open M, $mfile){
126 warn "$mfile: $!";
127 return $read;
128 }
129 while (<M>){
130 chomp;
8e07c86e 131 if ($Is_VMS) { /^(\S+)/ and $read->{"\L$1"}=$_; }
132 else { /^(\S+)\s*(.*)/ and $read->{$1}=$2; }
005c1a0e 133 }
134 close M;
135 $read;
136}
137
138# returns an anonymous sub that decides if an argument matches
139sub _maniskip {
140 my ($mfile) = @_;
141 my $matches = sub {0};
142 my @skip ;
f1387719 143 $mfile = "$MANIFEST.SKIP" unless defined $mfile;
005c1a0e 144 local *M;
145 return $matches unless -f $mfile;
146 open M, $mfile or return $matches;
147 while (<M>){
148 chomp;
149 next if /^\s*$/;
150 push @skip, $_;
151 }
152 close M;
8e07c86e 153 my $opts = $Is_VMS ? 'oi ' : 'o ';
005c1a0e 154 my $sub = "\$matches = "
155 . "sub { my(\$arg)=\@_; return 1 if "
8e07c86e 156 . join (" || ", (map {s!/!\\/!g; "\$arg =~ m/$_/$opts"} @skip), 0)
005c1a0e 157 . " }";
158 eval $sub;
159 print "Debug: $sub\n" if $Debug;
160 $matches;
161}
162
163sub manicopy {
8e07c86e 164 my($read,$target,$how)=@_;
005c1a0e 165 croak "manicopy() called without target argument" unless defined $target;
8e07c86e 166 $how = 'cp' unless defined $how && $how;
005c1a0e 167 require File::Path;
168 require File::Basename;
169 my(%dirs,$file);
8e07c86e 170 $target = VMS::Filespec::unixify($target) if $Is_VMS;
84876ac5 171 umask 0 unless $Is_VMS;
172 File::Path::mkpath([ $target ],1,$Is_VMS ? undef : 0755);
005c1a0e 173 foreach $file (keys %$read){
8e07c86e 174 $file = VMS::Filespec::unixify($file) if $Is_VMS;
84876ac5 175 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
176 my $dir = File::Basename::dirname($file);
177 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
178 File::Path::mkpath(["$target/$dir"],1,$Is_VMS ? undef : 0755);
179 }
8e07c86e 180 if ($Is_VMS) { vms_cp_if_diff($file,"$target/$file"); }
181 else { cp_if_diff($file, "$target/$file", $how); }
005c1a0e 182 }
183}
184
185sub cp_if_diff {
8a1da95f 186 my($from, $to, $how)=@_;
005c1a0e 187 -f $from || carp "$0: $from not found";
8e07c86e 188 my($diff) = 0;
189 local(*F,*T);
190 open(F,$from) or croak "Can't read $from: $!\n";
191 if (open(T,$to)) {
192 while (<F>) { $diff++,last if $_ ne <T>; }
193 $diff++ unless eof(T);
194 close T;
195 }
196 else { $diff++; }
197 close F;
198 if ($diff) {
199 if (-e $to) {
200 unlink($to) or confess "unlink $to: $!";
201 }
8a1da95f 202 STRICT_SWITCH: {
203 best($from,$to), last STRICT_SWITCH if $how eq 'best';
204 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
205 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
206 }
8e07c86e 207 }
208}
209
210# Do the comparisons here rather than spawning off another process
211sub vms_cp_if_diff {
212 my($from,$to) = @_;
213 my($diff) = 0;
214 local(*F,*T);
215 open(F,$from) or croak "Can't read $from: $!\n";
216 if (open(T,$to)) {
217 while (<F>) { $diff++,last if $_ ne <T>; }
218 $diff++ unless eof(T);
219 close T;
220 }
221 else { $diff++; }
222 close F;
223 if ($diff) {
84876ac5 224 system('copy',VMS::Filespec::vmsify($from),VMS::Filespec::vmsify($to)) & 1
8e07c86e 225 or confess "Copy failed: $!";
005c1a0e 226 }
227}
228
8e07c86e 229sub cp {
230 my ($srcFile, $dstFile) = @_;
79dd614e 231 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
232 copy($srcFile,$dstFile);
8e07c86e 233 utime $access, $mod, $dstFile;
234 # chmod a+rX-w,go-w
235 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile );
236}
237
238sub ln {
239 my ($srcFile, $dstFile) = @_;
240 link($srcFile, $dstFile);
241 local($_) = $dstFile; # chmod a+r,go-w+X (except "X" only applies to u=x)
242 my $mode= 0444 | (stat)[2] & 0700;
243 chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ );
244}
245
4633a7c4 246sub best {
247 my ($srcFile, $dstFile) = @_;
248 if (-l $srcFile) {
249 cp($srcFile, $dstFile);
250 } else {
251 ln($srcFile, $dstFile);
252 }
253}
254
005c1a0e 2551;
79dd614e 256
257__END__
258
259=head1 NAME
260
261ExtUtils::Manifest - utilities to write and check a MANIFEST file
262
263=head1 SYNOPSIS
264
265C<require ExtUtils::Manifest;>
266
267C<ExtUtils::Manifest::mkmanifest;>
268
269C<ExtUtils::Manifest::manicheck;>
270
271C<ExtUtils::Manifest::filecheck;>
272
273C<ExtUtils::Manifest::fullcheck;>
274
275C<ExtUtils::Manifest::skipcheck;>
276
277C<ExtUtild::Manifest::manifind();>
278
279C<ExtUtils::Manifest::maniread($file);>
280
281C<ExtUtils::Manifest::manicopy($read,$target,$how);>
282
283=head1 DESCRIPTION
284
285Mkmanifest() writes all files in and below the current directory to a
286file named in the global variable $ExtUtils::Manifest::MANIFEST (which
287defaults to C<MANIFEST>) in the current directory. It works similar to
288
289 find . -print
290
291but in doing so checks each line in an existing C<MANIFEST> file and
292includes any comments that are found in the existing C<MANIFEST> file
293in the new one. Anything between white space and an end of line within
294a C<MANIFEST> file is considered to be a comment. Filenames and
295comments are seperated by one or more TAB characters in the
296output. All files that match any regular expression in a file
297C<MANIFEST.SKIP> (if such a file exists) are ignored.
298
f1387719 299Manicheck() checks if all the files within a C<MANIFEST> in the
300current directory really do exist. It only reports discrepancies and
301exits silently if MANIFEST and the tree below the current directory
302are in sync.
79dd614e 303
304Filecheck() finds files below the current directory that are not
305mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
306will be consulted. Any file matching a regular expression in such a
307file will not be reported as missing in the C<MANIFEST> file.
308
309Fullcheck() does both a manicheck() and a filecheck().
310
311Skipcheck() lists all the files that are skipped due to your
312C<MANIFEST.SKIP> file.
313
314Manifind() retruns a hash reference. The keys of the hash are the
315files found below the current directory.
316
317Maniread($file) reads a named C<MANIFEST> file (defaults to
318C<MANIFEST> in the current directory) and returns a HASH reference
319with files being the keys and comments being the values of the HASH.
320
321I<Manicopy($read,$target,$how)> copies the files that are the keys in
322the HASH I<%$read> to the named target directory. The HASH reference
323I<$read> is typically returned by the maniread() function. This
324function is useful for producing a directory tree identical to the
325intended distribution tree. The third parameter $how can be used to
326specify a different methods of "copying". Valid values are C<cp>,
327which actually copies the files, C<ln> which creates hard links, and
328C<best> which mostly links the files but copies any symbolic link to
329make a tree without any symbolic link. Best is the default.
330
331=head1 MANIFEST.SKIP
332
333The file MANIFEST.SKIP may contain regular expressions of files that
334should be ignored by mkmanifest() and filecheck(). The regular
335expressions should appear one on each line. A typical example:
336
337 \bRCS\b
338 ^MANIFEST\.
339 ^Makefile$
340 ~$
341 \.html$
342 \.old$
343 ^blib/
344 ^MakeMaker-\d
345
346=head1 EXPORT_OK
347
348C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
349C<&maniread>, and C<&manicopy> are exportable.
350
351=head1 GLOBAL VARIABLES
352
353C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
354results in both a different C<MANIFEST> and a different
355C<MANIFEST.SKIP> file. This is useful if you want to maintain
356different distributions for different audiences (say a user version
357and a developer version including RCS).
358
359<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
360all functions act silently.
361
362=head1 DIAGNOSTICS
363
364All diagnostic output is sent to C<STDERR>.
365
366=over
367
368=item C<Not in MANIFEST:> I<file>
369
370is reported if a file is found, that is missing in the C<MANIFEST>
371file which is excluded by a regular expression in the file
372C<MANIFEST.SKIP>.
373
374=item C<No such file:> I<file>
375
376is reported if a file mentioned in a C<MANIFEST> file does not
377exist.
378
379=item C<MANIFEST:> I<$!>
380
381is reported if C<MANIFEST> could not be opened.
382
383=item C<Added to MANIFEST:> I<file>
384
385is reported by mkmanifest() if $Verbose is set and a file is added
386to MANIFEST. $Verbose is set to 1 by default.
387
388=back
389
390=head1 SEE ALSO
391
392L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
393
394=head1 AUTHOR
395
396Andreas Koenig F<E<lt>koenig@franz.ww.TU-Berlin.DEE<gt>>
397
398=cut