Track /etc/gitconfig
[msysgit/mtrensch.git] / lib / perl5 / 5.8.8 / ExtUtils / Manifest.pm
blob0c96f63ca9a2ae0c9e41f5d1f882ee4e44d962c4
1 package ExtUtils::Manifest;
3 require Exporter;
4 use Config;
5 use File::Basename;
6 use File::Copy 'copy';
7 use File::Find;
8 use File::Spec;
9 use Carp;
10 use strict;
12 use vars qw($VERSION @ISA @EXPORT_OK
13 $Is_MacOS $Is_VMS
14 $Debug $Verbose $Quiet $MANIFEST $DEFAULT_MSKIP);
16 $VERSION = '1.46';
17 @ISA=('Exporter');
18 @EXPORT_OK = qw(mkmanifest
19 manicheck filecheck fullcheck skipcheck
20 manifind maniread manicopy maniadd
23 $Is_MacOS = $^O eq 'MacOS';
24 $Is_VMS = $^O eq 'VMS';
25 require VMS::Filespec if $Is_VMS;
27 $Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
28 $Verbose = defined $ENV{PERL_MM_MANIFEST_VERBOSE} ?
29 $ENV{PERL_MM_MANIFEST_VERBOSE} : 1;
30 $Quiet = 0;
31 $MANIFEST = 'MANIFEST';
33 $DEFAULT_MSKIP = File::Spec->catfile( dirname(__FILE__), "$MANIFEST.SKIP" );
36 =head1 NAME
38 ExtUtils::Manifest - utilities to write and check a MANIFEST file
40 =head1 SYNOPSIS
42 use ExtUtils::Manifest qw(...funcs to import...);
44 mkmanifest();
46 my @missing_files = manicheck;
47 my @skipped = skipcheck;
48 my @extra_files = filecheck;
49 my($missing, $extra) = fullcheck;
51 my $found = manifind();
53 my $manifest = maniread();
55 manicopy($read,$target);
57 maniadd({$file => $comment, ...});
60 =head1 DESCRIPTION
62 =head2 Functions
64 ExtUtils::Manifest exports no functions by default. The following are
65 exported on request
67 =over 4
69 =item mkmanifest
71 mkmanifest();
73 Writes all files in and below the current directory to your F<MANIFEST>.
74 It works similar to
76 find . > MANIFEST
78 All files that match any regular expression in a file F<MANIFEST.SKIP>
79 (if it exists) are ignored.
81 Any existing F<MANIFEST> file will be saved as F<MANIFEST.bak>. Lines
82 from the old F<MANIFEST> file is preserved, including any comments
83 that are found in the existing F<MANIFEST> file in the new one.
85 =cut
87 sub _sort {
88 return sort { lc $a cmp lc $b } @_;
91 sub mkmanifest {
92 my $manimiss = 0;
93 my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
94 $read = {} if $manimiss;
95 local *M;
96 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
97 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
98 my $skip = _maniskip();
99 my $found = manifind();
100 my($key,$val,$file,%all);
101 %all = (%$found, %$read);
102 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
103 if $manimiss; # add new MANIFEST to known file list
104 foreach $file (_sort keys %all) {
105 if ($skip->($file)) {
106 # Policy: only remove files if they're listed in MANIFEST.SKIP.
107 # Don't remove files just because they don't exist.
108 warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
109 next;
111 if ($Verbose){
112 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
114 my $text = $all{$file};
115 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
116 $file = _unmacify($file);
117 my $tabs = (5 - (length($file)+1)/8);
118 $tabs = 1 if $tabs < 1;
119 $tabs = 0 unless $text;
120 print M $file, "\t" x $tabs, $text, "\n";
122 close M;
125 # Geez, shouldn't this use File::Spec or File::Basename or something?
126 # Why so careful about dependencies?
127 sub clean_up_filename {
128 my $filename = shift;
129 $filename =~ s|^\./||;
130 $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
131 return $filename;
135 =item manifind
137 my $found = manifind();
139 returns a hash reference. The keys of the hash are the files found
140 below the current directory.
142 =cut
144 sub manifind {
145 my $p = shift || {};
146 my $found = {};
148 my $wanted = sub {
149 my $name = clean_up_filename($File::Find::name);
150 warn "Debug: diskfile $name\n" if $Debug;
151 return if -d $_;
153 if( $Is_VMS ) {
154 $name =~ s#(.*)\.$#\L$1#;
155 $name = uc($name) if $name =~ /^MANIFEST(\.SKIP)?$/i;
157 $found->{$name} = "";
160 # We have to use "$File::Find::dir/$_" in preprocess, because
161 # $File::Find::name is unavailable.
162 # Also, it's okay to use / here, because MANIFEST files use Unix-style
163 # paths.
164 find({wanted => $wanted},
165 $Is_MacOS ? ":" : ".");
167 return $found;
171 =item manicheck
173 my @missing_files = manicheck();
175 checks if all the files within a C<MANIFEST> in the current directory
176 really do exist. If C<MANIFEST> and the tree below the current
177 directory are in sync it silently returns an empty list.
178 Otherwise it returns a list of files which are listed in the
179 C<MANIFEST> but missing from the directory, and by default also
180 outputs these names to STDERR.
182 =cut
184 sub manicheck {
185 return _check_files();
189 =item filecheck
191 my @extra_files = filecheck();
193 finds files below the current directory that are not mentioned in the
194 C<MANIFEST> file. An optional file C<MANIFEST.SKIP> will be
195 consulted. Any file matching a regular expression in such a file will
196 not be reported as missing in the C<MANIFEST> file. The list of any
197 extraneous files found is returned, and by default also reported to
198 STDERR.
200 =cut
202 sub filecheck {
203 return _check_manifest();
207 =item fullcheck
209 my($missing, $extra) = fullcheck();
211 does both a manicheck() and a filecheck(), returning then as two array
212 refs.
214 =cut
216 sub fullcheck {
217 return [_check_files()], [_check_manifest()];
221 =item skipcheck
223 my @skipped = skipcheck();
225 lists all the files that are skipped due to your C<MANIFEST.SKIP>
226 file.
228 =cut
230 sub skipcheck {
231 my($p) = @_;
232 my $found = manifind();
233 my $matches = _maniskip();
235 my @skipped = ();
236 foreach my $file (_sort keys %$found){
237 if (&$matches($file)){
238 warn "Skipping $file\n";
239 push @skipped, $file;
240 next;
244 return @skipped;
248 sub _check_files {
249 my $p = shift;
250 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
251 my $read = maniread() || {};
252 my $found = manifind($p);
254 my(@missfile) = ();
255 foreach my $file (_sort keys %$read){
256 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
257 if ($dosnames){
258 $file = lc $file;
259 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
260 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
262 unless ( exists $found->{$file} ) {
263 warn "No such file: $file\n" unless $Quiet;
264 push @missfile, $file;
268 return @missfile;
272 sub _check_manifest {
273 my($p) = @_;
274 my $read = maniread() || {};
275 my $found = manifind($p);
276 my $skip = _maniskip();
278 my @missentry = ();
279 foreach my $file (_sort keys %$found){
280 next if $skip->($file);
281 warn "Debug: manicheck checking from disk $file\n" if $Debug;
282 unless ( exists $read->{$file} ) {
283 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
284 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
285 push @missentry, $file;
289 return @missentry;
293 =item maniread
295 my $manifest = maniread();
296 my $manifest = maniread($manifest_file);
298 reads a named C<MANIFEST> file (defaults to C<MANIFEST> in the current
299 directory) and returns a HASH reference with files being the keys and
300 comments being the values of the HASH. Blank lines and lines which
301 start with C<#> in the C<MANIFEST> file are discarded.
303 =cut
305 sub maniread {
306 my ($mfile) = @_;
307 $mfile ||= $MANIFEST;
308 my $read = {};
309 local *M;
310 unless (open M, $mfile){
311 warn "$mfile: $!";
312 return $read;
314 local $_;
315 while (<M>){
316 chomp;
317 next if /^\s*#/;
319 my($file, $comment) = /^(\S+)\s*(.*)/;
320 next unless $file;
322 if ($Is_MacOS) {
323 $file = _macify($file);
324 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
326 elsif ($Is_VMS) {
327 require File::Basename;
328 my($base,$dir) = File::Basename::fileparse($file);
329 # Resolve illegal file specifications in the same way as tar
330 $dir =~ tr/./_/;
331 my(@pieces) = split(/\./,$base);
332 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
333 my $okfile = "$dir$base";
334 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
335 $file = $okfile;
336 $file = lc($file) unless $file =~ /^MANIFEST(\.SKIP)?$/;
339 $read->{$file} = $comment;
341 close M;
342 $read;
345 # returns an anonymous sub that decides if an argument matches
346 sub _maniskip {
347 my @skip ;
348 my $mfile = "$MANIFEST.SKIP";
349 local(*M,$_);
350 open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
351 while (<M>){
352 chomp;
353 next if /^#/;
354 next if /^\s*$/;
355 push @skip, _macify($_);
357 close M;
358 my $opts = $Is_VMS ? '(?i)' : '';
360 # Make sure each entry is isolated in its own parentheses, in case
361 # any of them contain alternations
362 my $regex = join '|', map "(?:$_)", @skip;
364 return sub { $_[0] =~ qr{$opts$regex} };
367 =item manicopy
369 manicopy(\%src, $dest_dir);
370 manicopy(\%src, $dest_dir, $how);
372 Copies the files that are the keys in %src to the $dest_dir. %src is
373 typically returned by the maniread() function.
375 manicopy( maniread(), $dest_dir );
377 This function is useful for producing a directory tree identical to the
378 intended distribution tree.
380 $how can be used to specify a different methods of "copying". Valid
381 values are C<cp>, which actually copies the files, C<ln> which creates
382 hard links, and C<best> which mostly links the files but copies any
383 symbolic link to make a tree without any symbolic link. C<cp> is the
384 default.
386 =cut
388 sub manicopy {
389 my($read,$target,$how)=@_;
390 croak "manicopy() called without target argument" unless defined $target;
391 $how ||= 'cp';
392 require File::Path;
393 require File::Basename;
395 $target = VMS::Filespec::unixify($target) if $Is_VMS;
396 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
397 foreach my $file (keys %$read){
398 if ($Is_MacOS) {
399 if ($file =~ m!:!) {
400 my $dir = _maccat($target, $file);
401 $dir =~ s/[^:]+$//;
402 File::Path::mkpath($dir,1,0755);
404 cp_if_diff($file, _maccat($target, $file), $how);
405 } else {
406 $file = VMS::Filespec::unixify($file) if $Is_VMS;
407 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
408 my $dir = File::Basename::dirname($file);
409 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
410 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
412 cp_if_diff($file, "$target/$file", $how);
417 sub cp_if_diff {
418 my($from, $to, $how)=@_;
419 -f $from or carp "$0: $from not found";
420 my($diff) = 0;
421 local(*F,*T);
422 open(F,"< $from\0") or die "Can't read $from: $!\n";
423 if (open(T,"< $to\0")) {
424 local $_;
425 while (<F>) { $diff++,last if $_ ne <T>; }
426 $diff++ unless eof(T);
427 close T;
429 else { $diff++; }
430 close F;
431 if ($diff) {
432 if (-e $to) {
433 unlink($to) or confess "unlink $to: $!";
435 STRICT_SWITCH: {
436 best($from,$to), last STRICT_SWITCH if $how eq 'best';
437 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
438 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
439 croak("ExtUtils::Manifest::cp_if_diff " .
440 "called with illegal how argument [$how]. " .
441 "Legal values are 'best', 'cp', and 'ln'.");
446 sub cp {
447 my ($srcFile, $dstFile) = @_;
448 my ($access,$mod) = (stat $srcFile)[8,9];
450 copy($srcFile,$dstFile);
451 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
452 _manicopy_chmod($dstFile);
456 sub ln {
457 my ($srcFile, $dstFile) = @_;
458 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
459 link($srcFile, $dstFile);
461 unless( _manicopy_chmod($dstFile) ) {
462 unlink $dstFile;
463 return;
468 # 1) Strip off all group and world permissions.
469 # 2) Let everyone read it.
470 # 3) If the owner can execute it, everyone can.
471 sub _manicopy_chmod {
472 my($file) = shift;
474 my $perm = 0444 | (stat $file)[2] & 0700;
475 chmod( $perm | ( $perm & 0100 ? 0111 : 0 ), $file );
478 # Files that are often modified in the distdir. Don't hard link them.
479 my @Exceptions = qw(MANIFEST META.yml SIGNATURE);
480 sub best {
481 my ($srcFile, $dstFile) = @_;
483 my $is_exception = grep $srcFile =~ /$_/, @Exceptions;
484 if ($is_exception or !$Config{d_link} or -l $srcFile) {
485 cp($srcFile, $dstFile);
486 } else {
487 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
491 sub _macify {
492 my($file) = @_;
494 return $file unless $Is_MacOS;
496 $file =~ s|^\./||;
497 if ($file =~ m|/|) {
498 $file =~ s|/+|:|g;
499 $file = ":$file";
502 $file;
505 sub _maccat {
506 my($f1, $f2) = @_;
508 return "$f1/$f2" unless $Is_MacOS;
510 $f1 .= ":$f2";
511 $f1 =~ s/([^:]:):/$1/g;
512 return $f1;
515 sub _unmacify {
516 my($file) = @_;
518 return $file unless $Is_MacOS;
520 $file =~ s|^:||;
521 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
522 $file =~ y|:|/|;
524 $file;
528 =item maniadd
530 maniadd({ $file => $comment, ...});
532 Adds an entry to an existing F<MANIFEST> unless its already there.
534 $file will be normalized (ie. Unixified). B<UNIMPLEMENTED>
536 =cut
538 sub maniadd {
539 my($additions) = shift;
541 _normalize($additions);
542 _fix_manifest($MANIFEST);
544 my $manifest = maniread();
545 my @needed = grep { !exists $manifest->{$_} } keys %$additions;
546 return 1 unless @needed;
548 open(MANIFEST, ">>$MANIFEST") or
549 die "maniadd() could not open $MANIFEST: $!";
551 foreach my $file (_sort @needed) {
552 my $comment = $additions->{$file} || '';
553 printf MANIFEST "%-40s %s\n", $file, $comment;
555 close MANIFEST or die "Error closing $MANIFEST: $!";
557 return 1;
561 # Sometimes MANIFESTs are missing a trailing newline. Fix this.
562 sub _fix_manifest {
563 my $manifest_file = shift;
565 open MANIFEST, $MANIFEST or die "Could not open $MANIFEST: $!";
567 # Yes, we should be using seek(), but I'd like to avoid loading POSIX
568 # to get SEEK_*
569 my @manifest = <MANIFEST>;
570 close MANIFEST;
572 unless( $manifest[-1] =~ /\n\z/ ) {
573 open MANIFEST, ">>$MANIFEST" or die "Could not open $MANIFEST: $!";
574 print MANIFEST "\n";
575 close MANIFEST;
580 # UNIMPLEMENTED
581 sub _normalize {
582 return;
586 =back
588 =head2 MANIFEST
590 A list of files in the distribution, one file per line. The MANIFEST
591 always uses Unix filepath conventions even if you're not on Unix. This
592 means F<foo/bar> style not F<foo\bar>.
594 Anything between white space and an end of line within a C<MANIFEST>
595 file is considered to be a comment. Any line beginning with # is also
596 a comment.
598 # this a comment
599 some/file
600 some/other/file comment about some/file
603 =head2 MANIFEST.SKIP
605 The file MANIFEST.SKIP may contain regular expressions of files that
606 should be ignored by mkmanifest() and filecheck(). The regular
607 expressions should appear one on each line. Blank lines and lines
608 which start with C<#> are skipped. Use C<\#> if you need a regular
609 expression to start with a C<#>.
611 For example:
613 # Version control files and dirs.
614 \bRCS\b
615 \bCVS\b
617 \B\.svn\b
619 # Makemaker generated files and dirs.
620 ^MANIFEST\.
621 ^Makefile$
622 ^blib/
623 ^MakeMaker-\d
625 # Temp, old and emacs backup files.
627 \.old$
628 ^#.*#$
629 ^\.#
631 If no MANIFEST.SKIP file is found, a default set of skips will be
632 used, similar to the example above. If you want nothing skipped,
633 simply make an empty MANIFEST.SKIP file.
636 =head2 EXPORT_OK
638 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
639 C<&maniread>, and C<&manicopy> are exportable.
641 =head2 GLOBAL VARIABLES
643 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
644 results in both a different C<MANIFEST> and a different
645 C<MANIFEST.SKIP> file. This is useful if you want to maintain
646 different distributions for different audiences (say a user version
647 and a developer version including RCS).
649 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
650 all functions act silently.
652 C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
653 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
654 produced.
656 =head1 DIAGNOSTICS
658 All diagnostic output is sent to C<STDERR>.
660 =over 4
662 =item C<Not in MANIFEST:> I<file>
664 is reported if a file is found which is not in C<MANIFEST>.
666 =item C<Skipping> I<file>
668 is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
670 =item C<No such file:> I<file>
672 is reported if a file mentioned in a C<MANIFEST> file does not
673 exist.
675 =item C<MANIFEST:> I<$!>
677 is reported if C<MANIFEST> could not be opened.
679 =item C<Added to MANIFEST:> I<file>
681 is reported by mkmanifest() if $Verbose is set and a file is added
682 to MANIFEST. $Verbose is set to 1 by default.
684 =back
686 =head1 ENVIRONMENT
688 =over 4
690 =item B<PERL_MM_MANIFEST_DEBUG>
692 Turns on debugging
694 =back
696 =head1 SEE ALSO
698 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
700 =head1 AUTHOR
702 Andreas Koenig C<andreas.koenig@anima.de>
704 Currently maintained by Michael G Schwern C<schwern@pobox.com>
706 =cut