Upgrade to ExtUtils::MakeMaker 6.19
[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';
57b1a898 7use File::Spec;
005c1a0e 8use Carp;
8a1da95f 9use strict;
10
57b1a898 11use vars qw($VERSION @ISA @EXPORT_OK
12 $Is_MacOS $Is_VMS
13 $Debug $Verbose $Quiet $MANIFEST $DEFAULT_MSKIP);
8a1da95f 14
a7d1454b 15$VERSION = 1.43;
8a1da95f 16@ISA=('Exporter');
479d2113 17@EXPORT_OK = qw(mkmanifest
18 manicheck filecheck fullcheck skipcheck
19 manifind maniread manicopy maniadd
20 );
005c1a0e 21
db5fd395 22$Is_MacOS = $^O eq 'MacOS';
479d2113 23$Is_VMS = $^O eq 'VMS';
f6d6199c 24require VMS::Filespec if $Is_VMS;
005c1a0e 25
479d2113 26$Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
75e2e551 27$Verbose = defined $ENV{PERL_MM_MANIFEST_VERBOSE} ?
28 $ENV{PERL_MM_MANIFEST_VERBOSE} : 1;
005c1a0e 29$Quiet = 0;
cb1a09d0 30$MANIFEST = 'MANIFEST';
479d2113 31
dedf98bc 32my $Filename = __FILE__;
33$DEFAULT_MSKIP = (File::Spec->splitpath($Filename))[1].
57b1a898 34 "$MANIFEST.SKIP";
4e68a208 35
479d2113 36
37=head1 NAME
38
39ExtUtils::Manifest - utilities to write and check a MANIFEST file
40
41=head1 SYNOPSIS
42
43 use ExtUtils::Manifest qw(...funcs to import...);
44
45 mkmanifest();
46
47 my @missing_files = manicheck;
48 my @skipped = skipcheck;
49 my @extra_files = filecheck;
50 my($missing, $extra) = fullcheck;
51
52 my $found = manifind();
53
54 my $manifest = maniread();
55
56 manicopy($read,$target);
57
58 maniadd({$file => $comment, ...});
59
60
61=head1 DESCRIPTION
62
63=head2 Functions
64
65ExtUtils::Manifest exports no functions by default. The following are
66exported on request
67
68=over 4
69
70=item mkmanifest
71
72 mkmanifest();
73
74Writes all files in and below the current directory to your F<MANIFEST>.
75It works similar to
76
77 find . > MANIFEST
78
79All files that match any regular expression in a file F<MANIFEST.SKIP>
80(if it exists) are ignored.
81
82Any existing F<MANIFEST> file will be saved as F<MANIFEST.bak>. Lines
83from the old F<MANIFEST> file is preserved, including any comments
84that are found in the existing F<MANIFEST> file in the new one.
85
86=cut
87
dedf98bc 88sub _sort {
89 return sort { lc $a cmp lc $b } @_;
90}
91
005c1a0e 92sub mkmanifest {
93 my $manimiss = 0;
0300da75 94 my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
005c1a0e 95 $read = {} if $manimiss;
864a5fa8 96 local *M;
cb1a09d0 97 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
98 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
f6d6199c 99 my $skip = _maniskip();
005c1a0e 100 my $found = manifind();
101 my($key,$val,$file,%all);
f1387719 102 %all = (%$found, %$read);
84876ac5 103 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
104 if $manimiss; # add new MANIFEST to known file list
dedf98bc 105 foreach $file (_sort keys %all) {
f6d6199c 106 if ($skip->($file)) {
107 # Policy: only remove files if they're listed in MANIFEST.SKIP.
108 # Don't remove files just because they don't exist.
109 warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
110 next;
111 }
005c1a0e 112 if ($Verbose){
cb1a09d0 113 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
005c1a0e 114 }
8e07c86e 115 my $text = $all{$file};
84876ac5 116 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
db5fd395 117 $file = _unmacify($file);
005c1a0e 118 my $tabs = (5 - (length($file)+1)/8);
119 $tabs = 1 if $tabs < 1;
8e07c86e 120 $tabs = 0 unless $text;
121 print M $file, "\t" x $tabs, $text, "\n";
005c1a0e 122 }
123 close M;
124}
125
f6d6199c 126# Geez, shouldn't this use File::Spec or File::Basename or something?
127# Why so careful about dependencies?
128sub clean_up_filename {
129 my $filename = shift;
130 $filename =~ s|^\./||;
131 $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
132 return $filename;
133}
134
479d2113 135
136=item manifind
137
138 my $found = manifind();
139
140returns a hash reference. The keys of the hash are the files found
141below the current directory.
142
143=cut
144
005c1a0e 145sub manifind {
f6d6199c 146 my $p = shift || {};
f6d6199c 147 my $found = {};
148
149 my $wanted = sub {
150 my $name = clean_up_filename($File::Find::name);
151 warn "Debug: diskfile $name\n" if $Debug;
57b1a898 152 return if -d $_;
f6d6199c 153
154 if( $Is_VMS ) {
155 $name =~ s#(.*)\.$#\L$1#;
156 $name = uc($name) if $name =~ /^MANIFEST(\.SKIP)?$/i;
157 }
158 $found->{$name} = "";
159 };
160
161 # We have to use "$File::Find::dir/$_" in preprocess, because
162 # $File::Find::name is unavailable.
163 # Also, it's okay to use / here, because MANIFEST files use Unix-style
164 # paths.
57b1a898 165 find({wanted => $wanted},
f6d6199c 166 $Is_MacOS ? ":" : ".");
167
168 return $found;
005c1a0e 169}
170
479d2113 171
172=item manicheck
173
174 my @missing_files = manicheck();
175
176checks if all the files within a C<MANIFEST> in the current directory
177really do exist. If C<MANIFEST> and the tree below the current
2c91f887 178directory are in sync it silently returns an empty list.
479d2113 179Otherwise it returns a list of files which are listed in the
180C<MANIFEST> but missing from the directory, and by default also
181outputs these names to STDERR.
182
183=cut
005c1a0e 184
185sub manicheck {
45bc4d3a 186 return _check_files();
005c1a0e 187}
188
479d2113 189
190=item filecheck
191
192 my @extra_files = filecheck();
193
194finds files below the current directory that are not mentioned in the
195C<MANIFEST> file. An optional file C<MANIFEST.SKIP> will be
196consulted. Any file matching a regular expression in such a file will
197not be reported as missing in the C<MANIFEST> file. The list of any
198extraneous files found is returned, and by default also reported to
199STDERR.
200
201=cut
202
005c1a0e 203sub filecheck {
45bc4d3a 204 return _check_manifest();
005c1a0e 205}
206
479d2113 207
208=item fullcheck
209
210 my($missing, $extra) = fullcheck();
211
212does both a manicheck() and a filecheck(), returning then as two array
213refs.
214
215=cut
216
217sub fullcheck {
218 return [_check_files()], [_check_manifest()];
219}
220
221
222=item skipcheck
223
224 my @skipped = skipcheck();
225
226lists all the files that are skipped due to your C<MANIFEST.SKIP>
227file.
228
229=cut
230
8e07c86e 231sub skipcheck {
45bc4d3a 232 my($p) = @_;
233 my $found = manifind();
234 my $matches = _maniskip();
235
236 my @skipped = ();
dedf98bc 237 foreach my $file (_sort keys %$found){
45bc4d3a 238 if (&$matches($file)){
239 warn "Skipping $file\n";
240 push @skipped, $file;
241 next;
242 }
243 }
244
245 return @skipped;
8e07c86e 246}
247
f6d6199c 248
45bc4d3a 249sub _check_files {
250 my $p = shift;
39e571d4 251 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
45bc4d3a 252 my $read = maniread() || {};
253 my $found = manifind($p);
254
255 my(@missfile) = ();
dedf98bc 256 foreach my $file (_sort keys %$read){
45bc4d3a 257 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
258 if ($dosnames){
259 $file = lc $file;
260 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
261 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
262 }
263 unless ( exists $found->{$file} ) {
264 warn "No such file: $file\n" unless $Quiet;
265 push @missfile, $file;
266 }
005c1a0e 267 }
45bc4d3a 268
269 return @missfile;
270}
271
272
273sub _check_manifest {
274 my($p) = @_;
275 my $read = maniread() || {};
276 my $found = manifind($p);
277 my $skip = _maniskip();
278
279 my @missentry = ();
dedf98bc 280 foreach my $file (_sort keys %$found){
45bc4d3a 281 next if $skip->($file);
282 warn "Debug: manicheck checking from disk $file\n" if $Debug;
283 unless ( exists $read->{$file} ) {
284 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
285 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
286 push @missentry, $file;
287 }
005c1a0e 288 }
45bc4d3a 289
290 return @missentry;
005c1a0e 291}
292
45bc4d3a 293
479d2113 294=item maniread
295
296 my $manifest = maniread();
297 my $manifest = maniread($manifest_file);
298
299reads a named C<MANIFEST> file (defaults to C<MANIFEST> in the current
300directory) and returns a HASH reference with files being the keys and
301comments being the values of the HASH. Blank lines and lines which
302start with C<#> in the C<MANIFEST> file are discarded.
303
304=cut
305
005c1a0e 306sub maniread {
307 my ($mfile) = @_;
15a074ca 308 $mfile ||= $MANIFEST;
005c1a0e 309 my $read = {};
310 local *M;
311 unless (open M, $mfile){
2530b651 312 warn "$mfile: $!";
313 return $read;
005c1a0e 314 }
2530b651 315 local $_;
005c1a0e 316 while (<M>){
2530b651 317 chomp;
1df8d179 318 next if /^\s*#/;
0e3309e2 319
320 my($file, $comment) = /^(\S+)\s*(.*)/;
321 next unless $file;
322
2530b651 323 if ($Is_MacOS) {
324 $file = _macify($file);
325 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
326 }
327 elsif ($Is_VMS) {
328 require File::Basename;
329 my($base,$dir) = File::Basename::fileparse($file);
330 # Resolve illegal file specifications in the same way as tar
331 $dir =~ tr/./_/;
332 my(@pieces) = split(/\./,$base);
333 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
334 my $okfile = "$dir$base";
335 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
349e1be1 336 $file = $okfile;
f6d6199c 337 $file = lc($file) unless $file =~ /^MANIFEST(\.SKIP)?$/;
2530b651 338 }
0e3309e2 339
340 $read->{$file} = $comment;
005c1a0e 341 }
342 close M;
343 $read;
344}
345
346# returns an anonymous sub that decides if an argument matches
347sub _maniskip {
005c1a0e 348 my @skip ;
45bc4d3a 349 my $mfile = "$MANIFEST.SKIP";
2530b651 350 local(*M,$_);
f6d6199c 351 open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
005c1a0e 352 while (<M>){
353 chomp;
15a074ca 354 next if /^#/;
005c1a0e 355 next if /^\s*$/;
db5fd395 356 push @skip, _macify($_);
005c1a0e 357 }
358 close M;
f6d6199c 359 my $opts = $Is_VMS ? '(?i)' : '';
360
361 # Make sure each entry is isolated in its own parentheses, in case
362 # any of them contain alternations
363 my $regex = join '|', map "(?:$_)", @skip;
364
45bc4d3a 365 return sub { $_[0] =~ qr{$opts$regex} };
005c1a0e 366}
367
479d2113 368=item manicopy
369
a7d1454b 370 manicopy(\%src, $dest_dir);
371 manicopy(\%src, $dest_dir, $how);
479d2113 372
a7d1454b 373Copies the files that are the keys in %src to the $dest_dir. %src is
374typically returned by the maniread() function.
375
376 manicopy( maniread(), $dest_dir );
377
378This function is useful for producing a directory tree identical to the
379intended distribution tree.
380
381$how can be used to specify a different methods of "copying". Valid
479d2113 382values are C<cp>, which actually copies the files, C<ln> which creates
383hard links, and C<best> which mostly links the files but copies any
a7d1454b 384symbolic link to make a tree without any symbolic link. C<cp> is the
479d2113 385default.
386
387=cut
388
005c1a0e 389sub manicopy {
8e07c86e 390 my($read,$target,$how)=@_;
005c1a0e 391 croak "manicopy() called without target argument" unless defined $target;
15a074ca 392 $how ||= 'cp';
005c1a0e 393 require File::Path;
394 require File::Basename;
57b1a898 395
8e07c86e 396 $target = VMS::Filespec::unixify($target) if $Is_VMS;
553c0e07 397 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
57b1a898 398 foreach my $file (keys %$read){
db5fd395 399 if ($Is_MacOS) {
400 if ($file =~ m!:!) {
401 my $dir = _maccat($target, $file);
402 $dir =~ s/[^:]+$//;
403 File::Path::mkpath($dir,1,0755);
404 }
405 cp_if_diff($file, _maccat($target, $file), $how);
406 } else {
407 $file = VMS::Filespec::unixify($file) if $Is_VMS;
408 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
409 my $dir = File::Basename::dirname($file);
410 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
411 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
412 }
413 cp_if_diff($file, "$target/$file", $how);
84876ac5 414 }
005c1a0e 415 }
416}
417
418sub cp_if_diff {
8a1da95f 419 my($from, $to, $how)=@_;
15a074ca 420 -f $from or carp "$0: $from not found";
8e07c86e 421 my($diff) = 0;
422 local(*F,*T);
57b1a898 423 open(F,"< $from\0") or die "Can't read $from: $!\n";
db5fd395 424 if (open(T,"< $to\0")) {
2530b651 425 local $_;
8e07c86e 426 while (<F>) { $diff++,last if $_ ne <T>; }
427 $diff++ unless eof(T);
428 close T;
429 }
430 else { $diff++; }
431 close F;
432 if ($diff) {
433 if (-e $to) {
434 unlink($to) or confess "unlink $to: $!";
435 }
15a074ca 436 STRICT_SWITCH: {
437 best($from,$to), last STRICT_SWITCH if $how eq 'best';
438 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
439 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
440 croak("ExtUtils::Manifest::cp_if_diff " .
441 "called with illegal how argument [$how]. " .
442 "Legal values are 'best', 'cp', and 'ln'.");
443 }
8e07c86e 444 }
445}
446
8e07c86e 447sub cp {
448 my ($srcFile, $dstFile) = @_;
a7d1454b 449 my ($access,$mod) = (stat $srcFile)[8,9];
450
79dd614e 451 copy($srcFile,$dstFile);
9607fc9c 452 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
a7d1454b 453 _manicopy_chmod($dstFile);
8e07c86e 454}
455
a7d1454b 456
8e07c86e 457sub ln {
458 my ($srcFile, $dstFile) = @_;
f0f13d0e 459 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
8e07c86e 460 link($srcFile, $dstFile);
57b1a898 461
a7d1454b 462 unless( _manicopy_chmod($dstFile) ) {
57b1a898 463 unlink $dstFile;
464 return;
4e6ea2c3 465 }
466 1;
8e07c86e 467}
468
a7d1454b 469# 1) Strip off all group and world permissions.
470# 2) Let everyone read it.
471# 3) If the owner can execute it, everyone can.
472sub _manicopy_chmod {
473 my($file) = shift;
57b1a898 474
a7d1454b 475 my $perm = 0444 | (stat $file)[2] & 0700;
476 chmod( $perm | ( $perm & 0100 ? 0111 : 0 ), $file );
477}
57b1a898 478
4633a7c4 479sub best {
480 my ($srcFile, $dstFile) = @_;
a7d1454b 481 if (!$Config{d_link} or -l $srcFile) {
4633a7c4 482 cp($srcFile, $dstFile);
483 } else {
3dee4013 484 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
4633a7c4 485 }
486}
487
db5fd395 488sub _macify {
489 my($file) = @_;
490
491 return $file unless $Is_MacOS;
a7d1454b 492
db5fd395 493 $file =~ s|^\./||;
494 if ($file =~ m|/|) {
495 $file =~ s|/+|:|g;
496 $file = ":$file";
497 }
a7d1454b 498
db5fd395 499 $file;
500}
501
502sub _maccat {
503 my($f1, $f2) = @_;
a7d1454b 504
db5fd395 505 return "$f1/$f2" unless $Is_MacOS;
a7d1454b 506
db5fd395 507 $f1 .= ":$f2";
508 $f1 =~ s/([^:]:):/$1/g;
509 return $f1;
510}
511
512sub _unmacify {
513 my($file) = @_;
514
515 return $file unless $Is_MacOS;
516
517 $file =~ s|^:||;
518 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
519 $file =~ y|:|/|;
520
521 $file;
522}
523
79dd614e 524
479d2113 525=item maniadd
79dd614e 526
479d2113 527 maniadd({ $file => $comment, ...});
79dd614e 528
1df8d179 529Adds an entry to an existing F<MANIFEST> unless its already there.
79dd614e 530
479d2113 531$file will be normalized (ie. Unixified). B<UNIMPLEMENTED>
79dd614e 532
479d2113 533=cut
79dd614e 534
479d2113 535sub maniadd {
536 my($additions) = shift;
79dd614e 537
479d2113 538 _normalize($additions);
2530b651 539 _fix_manifest($MANIFEST);
79dd614e 540
479d2113 541 my $manifest = maniread();
30361541 542 my @needed = grep { !exists $manifest->{$_} } keys %$additions;
543 return 1 unless @needed;
1df8d179 544
30361541 545 open(MANIFEST, ">>$MANIFEST") or
546 die "maniadd() could not open $MANIFEST: $!";
2c91f887 547
30361541 548 foreach my $file (_sort @needed) {
dedf98bc 549 my $comment = $additions->{$file} || '';
30361541 550 printf MANIFEST "%-40s %s\n", $file, $comment;
479d2113 551 }
30361541 552 close MANIFEST or die "Error closing $MANIFEST: $!";
553
554 return 1;
479d2113 555}
79dd614e 556
2530b651 557
558# Sometimes MANIFESTs are missing a trailing newline. Fix this.
559sub _fix_manifest {
560 my $manifest_file = shift;
561
562 open MANIFEST, $MANIFEST or die "Could not open $MANIFEST: $!";
563
564 # Yes, we should be using seek(), but I'd like to avoid loading POSIX
565 # to get SEEK_*
566 my @manifest = <MANIFEST>;
567 close MANIFEST;
568
569 unless( $manifest[-1] =~ /\n\z/ ) {
570 open MANIFEST, ">>$MANIFEST" or die "Could not open $MANIFEST: $!";
571 print MANIFEST "\n";
572 close MANIFEST;
573 }
574}
575
576
479d2113 577# UNIMPLEMENTED
578sub _normalize {
579 return;
580}
79dd614e 581
79dd614e 582
479d2113 583=back
79dd614e 584
479d2113 585=head2 MANIFEST
79dd614e 586
479d2113 587Anything between white space and an end of line within a C<MANIFEST>
588file is considered to be a comment. Filenames and comments are
589separated by one or more TAB characters in the output.
79dd614e 590
79dd614e 591
479d2113 592=head2 MANIFEST.SKIP
79dd614e 593
594The file MANIFEST.SKIP may contain regular expressions of files that
595should be ignored by mkmanifest() and filecheck(). The regular
15a074ca 596expressions should appear one on each line. Blank lines and lines
597which start with C<#> are skipped. Use C<\#> if you need a regular
598expression to start with a sharp character. A typical example:
79dd614e 599
0b9c804f 600 # Version control files and dirs.
79dd614e 601 \bRCS\b
0b9c804f 602 \bCVS\b
603 ,v$
479d2113 604 \B\.svn\b
0b9c804f 605
606 # Makemaker generated files and dirs.
79dd614e 607 ^MANIFEST\.
608 ^Makefile$
79dd614e 609 ^blib/
610 ^MakeMaker-\d
611
0b9c804f 612 # Temp, old and emacs backup files.
613 ~$
614 \.old$
615 ^#.*#$
cfcce72b 616 ^\.#
0b9c804f 617
618If no MANIFEST.SKIP file is found, a default set of skips will be
619used, similar to the example above. If you want nothing skipped,
620simply make an empty MANIFEST.SKIP file.
621
622
479d2113 623=head2 EXPORT_OK
79dd614e 624
625C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
626C<&maniread>, and C<&manicopy> are exportable.
627
479d2113 628=head2 GLOBAL VARIABLES
79dd614e 629
630C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
631results in both a different C<MANIFEST> and a different
632C<MANIFEST.SKIP> file. This is useful if you want to maintain
633different distributions for different audiences (say a user version
634and a developer version including RCS).
635
81ff29e3 636C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
79dd614e 637all functions act silently.
638
0b9c804f 639C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
640or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
641produced.
642
79dd614e 643=head1 DIAGNOSTICS
644
645All diagnostic output is sent to C<STDERR>.
646
bbc7dcd2 647=over 4
79dd614e 648
649=item C<Not in MANIFEST:> I<file>
650
45bc4d3a 651is reported if a file is found which is not in C<MANIFEST>.
652
653=item C<Skipping> I<file>
654
655is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
79dd614e 656
657=item C<No such file:> I<file>
658
659is reported if a file mentioned in a C<MANIFEST> file does not
660exist.
661
662=item C<MANIFEST:> I<$!>
663
664is reported if C<MANIFEST> could not be opened.
665
666=item C<Added to MANIFEST:> I<file>
667
668is reported by mkmanifest() if $Verbose is set and a file is added
669to MANIFEST. $Verbose is set to 1 by default.
670
671=back
672
0b9c804f 673=head1 ENVIRONMENT
674
675=over 4
676
677=item B<PERL_MM_MANIFEST_DEBUG>
678
679Turns on debugging
680
681=back
682
79dd614e 683=head1 SEE ALSO
684
685L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
686
687=head1 AUTHOR
688
a7d1454b 689Andreas Koenig C<andreas.koenig@anima.de>
690
691Currently maintained by Michael G Schwern C<schwern@pobox.com>
79dd614e 692
693=cut
479d2113 694
6951;