Fixup Embed.t for Win32/VC++
[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';
0b9c804f 7use File::Spec::Functions qw(splitpath);
005c1a0e 8use Carp;
8a1da95f 9use strict;
10
f168a5e7 11our ($VERSION,@ISA,@EXPORT_OK,
5d31cce8 12 $Is_MacOS,$Is_VMS,
13 $Debug,$Verbose,$Quiet,$MANIFEST,$found,$DEFAULT_MSKIP);
8a1da95f 14
88d01e8d 15$VERSION = substr(q$Revision: 1.35 $, 10);
8a1da95f 16@ISA=('Exporter');
17@EXPORT_OK = ('mkmanifest', 'manicheck', 'fullcheck', 'filecheck',
18 'skipcheck', 'maniread', 'manicopy');
005c1a0e 19
db5fd395 20$Is_MacOS = $^O eq 'MacOS';
79dd614e 21$Is_VMS = $^O eq 'VMS';
9607fc9c 22if ($Is_VMS) { require File::Basename }
005c1a0e 23
0b9c804f 24$Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
9607fc9c 25$Verbose = 1;
005c1a0e 26$Quiet = 0;
cb1a09d0 27$MANIFEST = 'MANIFEST';
0b9c804f 28$DEFAULT_MSKIP = (splitpath($INC{"ExtUtils/Manifest.pm"}))[1]."$MANIFEST.SKIP";
cb1a09d0 29
4e68a208 30# Really cool fix from Ilya :)
31unless (defined $Config{d_link}) {
db376a24 32 no warnings;
4e68a208 33 *ln = \&cp;
34}
35
005c1a0e 36sub mkmanifest {
37 my $manimiss = 0;
0300da75 38 my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
005c1a0e 39 $read = {} if $manimiss;
864a5fa8 40 local *M;
cb1a09d0 41 rename $MANIFEST, "$MANIFEST.bak" unless $manimiss;
42 open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
005c1a0e 43 my $matches = _maniskip();
44 my $found = manifind();
45 my($key,$val,$file,%all);
f1387719 46 %all = (%$found, %$read);
84876ac5 47 $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
48 if $manimiss; # add new MANIFEST to known file list
005c1a0e 49 foreach $file (sort keys %all) {
50 next if &$matches($file);
51 if ($Verbose){
cb1a09d0 52 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
005c1a0e 53 }
8e07c86e 54 my $text = $all{$file};
84876ac5 55 ($file,$text) = split(/\s+/,$text,2) if $Is_VMS && $text;
db5fd395 56 $file = _unmacify($file);
005c1a0e 57 my $tabs = (5 - (length($file)+1)/8);
58 $tabs = 1 if $tabs < 1;
8e07c86e 59 $tabs = 0 unless $text;
60 print M $file, "\t" x $tabs, $text, "\n";
005c1a0e 61 }
62 close M;
63}
64
65sub manifind {
66 local $found = {};
4633a7c4 67 find(sub {return if -d $_;
db5fd395 68 (my $name = $File::Find::name) =~ s|^\./||;
69 $name =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
005c1a0e 70 warn "Debug: diskfile $name\n" if $Debug;
db5fd395 71 $name =~ s#(.*)\.$#\L$1# if $Is_VMS;
349e1be1 72 $name = uc($name) if /^MANIFEST/i && $Is_VMS;
db5fd395 73 $found->{$name} = "";}, $Is_MacOS ? ":" : ".");
005c1a0e 74 $found;
75}
76
77sub fullcheck {
78 _manicheck(3);
79}
80
81sub manicheck {
82 return @{(_manicheck(1))[0]};
83}
84
85sub filecheck {
86 return @{(_manicheck(2))[1]};
87}
88
8e07c86e 89sub skipcheck {
90 _manicheck(6);
91}
92
005c1a0e 93sub _manicheck {
94 my($arg) = @_;
95 my $read = maniread();
15a074ca 96 my $found = manifind();
005c1a0e 97 my $file;
39e571d4 98 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
005c1a0e 99 my(@missfile,@missentry);
100 if ($arg & 1){
005c1a0e 101 foreach $file (sort keys %$read){
cb1a09d0 102 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
39e571d4 103 if ($dosnames){
104 $file = lc $file;
105 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
106 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
107 }
005c1a0e 108 unless ( exists $found->{$file} ) {
8e07c86e 109 warn "No such file: $file\n" unless $Quiet;
110 push @missfile, $file;
005c1a0e 111 }
112 }
113 }
114 if ($arg & 2){
115 $read ||= {};
116 my $matches = _maniskip();
8e07c86e 117 my $skipwarn = $arg & 4;
005c1a0e 118 foreach $file (sort keys %$found){
8e07c86e 119 if (&$matches($file)){
120 warn "Skipping $file\n" if $skipwarn;
121 next;
122 }
005c1a0e 123 warn "Debug: manicheck checking from disk $file\n" if $Debug;
124 unless ( exists $read->{$file} ) {
c4968b8c 125 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
db5fd395 126 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
8e07c86e 127 push @missentry, $file;
005c1a0e 128 }
129 }
130 }
131 (\@missfile,\@missentry);
132}
133
134sub maniread {
135 my ($mfile) = @_;
15a074ca 136 $mfile ||= $MANIFEST;
005c1a0e 137 my $read = {};
138 local *M;
139 unless (open M, $mfile){
140 warn "$mfile: $!";
141 return $read;
142 }
143 while (<M>){
144 chomp;
15a074ca 145 next if /^#/;
0e3309e2 146
147 my($file, $comment) = /^(\S+)\s*(.*)/;
148 next unless $file;
149
db5fd395 150 if ($Is_MacOS) {
0e3309e2 151 $file = _macify($file);
152 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
db5fd395 153 }
154 elsif ($Is_VMS) {
9607fc9c 155 my($base,$dir) = File::Basename::fileparse($file);
156 # Resolve illegal file specifications in the same way as tar
157 $dir =~ tr/./_/;
158 my(@pieces) = split(/\./,$base);
159 if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
160 my $okfile = "$dir$base";
161 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
349e1be1 162 $file = $okfile;
163 $file = lc($file) unless $file =~ /^MANIFEST/i;
9607fc9c 164 }
0e3309e2 165
166 $read->{$file} = $comment;
005c1a0e 167 }
168 close M;
169 $read;
170}
171
172# returns an anonymous sub that decides if an argument matches
173sub _maniskip {
174 my ($mfile) = @_;
175 my $matches = sub {0};
176 my @skip ;
15a074ca 177 $mfile ||= "$MANIFEST.SKIP";
005c1a0e 178 local *M;
0b9c804f 179 open M, $mfile or open M, $DEFAULT_MSKIP or return $matches;
005c1a0e 180 while (<M>){
181 chomp;
15a074ca 182 next if /^#/;
005c1a0e 183 next if /^\s*$/;
db5fd395 184 push @skip, _macify($_);
005c1a0e 185 }
186 close M;
8e07c86e 187 my $opts = $Is_VMS ? 'oi ' : 'o ';
005c1a0e 188 my $sub = "\$matches = "
189 . "sub { my(\$arg)=\@_; return 1 if "
8e07c86e 190 . join (" || ", (map {s!/!\\/!g; "\$arg =~ m/$_/$opts"} @skip), 0)
005c1a0e 191 . " }";
192 eval $sub;
193 print "Debug: $sub\n" if $Debug;
194 $matches;
195}
196
197sub manicopy {
8e07c86e 198 my($read,$target,$how)=@_;
005c1a0e 199 croak "manicopy() called without target argument" unless defined $target;
15a074ca 200 $how ||= 'cp';
005c1a0e 201 require File::Path;
202 require File::Basename;
203 my(%dirs,$file);
8e07c86e 204 $target = VMS::Filespec::unixify($target) if $Is_VMS;
553c0e07 205 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
005c1a0e 206 foreach $file (keys %$read){
db5fd395 207 if ($Is_MacOS) {
208 if ($file =~ m!:!) {
209 my $dir = _maccat($target, $file);
210 $dir =~ s/[^:]+$//;
211 File::Path::mkpath($dir,1,0755);
212 }
213 cp_if_diff($file, _maccat($target, $file), $how);
214 } else {
215 $file = VMS::Filespec::unixify($file) if $Is_VMS;
216 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
217 my $dir = File::Basename::dirname($file);
218 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
219 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
220 }
221 cp_if_diff($file, "$target/$file", $how);
84876ac5 222 }
005c1a0e 223 }
224}
225
226sub cp_if_diff {
8a1da95f 227 my($from, $to, $how)=@_;
15a074ca 228 -f $from or carp "$0: $from not found";
8e07c86e 229 my($diff) = 0;
230 local(*F,*T);
db5fd395 231 open(F,"< $from\0") or croak "Can't read $from: $!\n";
232 if (open(T,"< $to\0")) {
8e07c86e 233 while (<F>) { $diff++,last if $_ ne <T>; }
234 $diff++ unless eof(T);
235 close T;
236 }
237 else { $diff++; }
238 close F;
239 if ($diff) {
240 if (-e $to) {
241 unlink($to) or confess "unlink $to: $!";
242 }
15a074ca 243 STRICT_SWITCH: {
244 best($from,$to), last STRICT_SWITCH if $how eq 'best';
245 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
246 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
247 croak("ExtUtils::Manifest::cp_if_diff " .
248 "called with illegal how argument [$how]. " .
249 "Legal values are 'best', 'cp', and 'ln'.");
250 }
8e07c86e 251 }
252}
253
8e07c86e 254sub cp {
255 my ($srcFile, $dstFile) = @_;
79dd614e 256 my ($perm,$access,$mod) = (stat $srcFile)[2,8,9];
257 copy($srcFile,$dstFile);
9607fc9c 258 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
8e07c86e 259 # chmod a+rX-w,go-w
db5fd395 260 chmod( 0444 | ( $perm & 0111 ? 0111 : 0 ), $dstFile ) unless ($^O eq 'MacOS');
8e07c86e 261}
262
263sub ln {
264 my ($srcFile, $dstFile) = @_;
f0f13d0e 265 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
8e07c86e 266 link($srcFile, $dstFile);
267 local($_) = $dstFile; # chmod a+r,go-w+X (except "X" only applies to u=x)
268 my $mode= 0444 | (stat)[2] & 0700;
4e6ea2c3 269 if (! chmod( $mode | ( $mode & 0100 ? 0111 : 0 ), $_ )) {
270 unlink $dstFile;
271 return;
272 }
273 1;
8e07c86e 274}
275
4633a7c4 276sub best {
277 my ($srcFile, $dstFile) = @_;
278 if (-l $srcFile) {
279 cp($srcFile, $dstFile);
280 } else {
3dee4013 281 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
4633a7c4 282 }
283}
284
db5fd395 285sub _macify {
286 my($file) = @_;
287
288 return $file unless $Is_MacOS;
289
290 $file =~ s|^\./||;
291 if ($file =~ m|/|) {
292 $file =~ s|/+|:|g;
293 $file = ":$file";
294 }
295
296 $file;
297}
298
299sub _maccat {
300 my($f1, $f2) = @_;
301
302 return "$f1/$f2" unless $Is_MacOS;
303
304 $f1 .= ":$f2";
305 $f1 =~ s/([^:]:):/$1/g;
306 return $f1;
307}
308
309sub _unmacify {
310 my($file) = @_;
311
312 return $file unless $Is_MacOS;
313
314 $file =~ s|^:||;
315 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
316 $file =~ y|:|/|;
317
318 $file;
319}
320
005c1a0e 3211;
79dd614e 322
323__END__
324
325=head1 NAME
326
327ExtUtils::Manifest - utilities to write and check a MANIFEST file
328
329=head1 SYNOPSIS
330
d962e1c0 331 require ExtUtils::Manifest;
79dd614e 332
d962e1c0 333 ExtUtils::Manifest::mkmanifest;
79dd614e 334
d962e1c0 335 ExtUtils::Manifest::manicheck;
79dd614e 336
d962e1c0 337 ExtUtils::Manifest::filecheck;
79dd614e 338
d962e1c0 339 ExtUtils::Manifest::fullcheck;
79dd614e 340
d962e1c0 341 ExtUtils::Manifest::skipcheck;
79dd614e 342
d962e1c0 343 ExtUtils::Manifest::manifind();
79dd614e 344
d962e1c0 345 ExtUtils::Manifest::maniread($file);
79dd614e 346
d962e1c0 347 ExtUtils::Manifest::manicopy($read,$target,$how);
79dd614e 348
349=head1 DESCRIPTION
350
d962e1c0 351mkmanifest() writes all files in and below the current directory to a
79dd614e 352file named in the global variable $ExtUtils::Manifest::MANIFEST (which
353defaults to C<MANIFEST>) in the current directory. It works similar to
354
355 find . -print
356
357but in doing so checks each line in an existing C<MANIFEST> file and
358includes any comments that are found in the existing C<MANIFEST> file
359in the new one. Anything between white space and an end of line within
360a C<MANIFEST> file is considered to be a comment. Filenames and
de592821 361comments are separated by one or more TAB characters in the
79dd614e 362output. All files that match any regular expression in a file
363C<MANIFEST.SKIP> (if such a file exists) are ignored.
364
d962e1c0 365manicheck() checks if all the files within a C<MANIFEST> in the
f1387719 366current directory really do exist. It only reports discrepancies and
367exits silently if MANIFEST and the tree below the current directory
368are in sync.
79dd614e 369
d962e1c0 370filecheck() finds files below the current directory that are not
79dd614e 371mentioned in the C<MANIFEST> file. An optional file C<MANIFEST.SKIP>
372will be consulted. Any file matching a regular expression in such a
373file will not be reported as missing in the C<MANIFEST> file.
374
d962e1c0 375fullcheck() does both a manicheck() and a filecheck().
79dd614e 376
d962e1c0 377skipcheck() lists all the files that are skipped due to your
79dd614e 378C<MANIFEST.SKIP> file.
379
d962e1c0 380manifind() returns a hash reference. The keys of the hash are the
79dd614e 381files found below the current directory.
382
d962e1c0 383maniread($file) reads a named C<MANIFEST> file (defaults to
79dd614e 384C<MANIFEST> in the current directory) and returns a HASH reference
385with files being the keys and comments being the values of the HASH.
15a074ca 386Blank lines and lines which start with C<#> in the C<MANIFEST> file
387are discarded.
79dd614e 388
d962e1c0 389C<manicopy($read,$target,$how)> copies the files that are the keys in
79dd614e 390the HASH I<%$read> to the named target directory. The HASH reference
d962e1c0 391$read is typically returned by the maniread() function. This
79dd614e 392function is useful for producing a directory tree identical to the
393intended distribution tree. The third parameter $how can be used to
394specify a different methods of "copying". Valid values are C<cp>,
395which actually copies the files, C<ln> which creates hard links, and
396C<best> which mostly links the files but copies any symbolic link to
397make a tree without any symbolic link. Best is the default.
398
399=head1 MANIFEST.SKIP
400
401The file MANIFEST.SKIP may contain regular expressions of files that
402should be ignored by mkmanifest() and filecheck(). The regular
15a074ca 403expressions should appear one on each line. Blank lines and lines
404which start with C<#> are skipped. Use C<\#> if you need a regular
405expression to start with a sharp character. A typical example:
79dd614e 406
0b9c804f 407 # Version control files and dirs.
79dd614e 408 \bRCS\b
0b9c804f 409 \bCVS\b
410 ,v$
411
412 # Makemaker generated files and dirs.
79dd614e 413 ^MANIFEST\.
414 ^Makefile$
79dd614e 415 ^blib/
416 ^MakeMaker-\d
417
0b9c804f 418 # Temp, old and emacs backup files.
419 ~$
420 \.old$
421 ^#.*#$
cfcce72b 422 ^\.#
0b9c804f 423
424If no MANIFEST.SKIP file is found, a default set of skips will be
425used, similar to the example above. If you want nothing skipped,
426simply make an empty MANIFEST.SKIP file.
427
428
79dd614e 429=head1 EXPORT_OK
430
431C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
432C<&maniread>, and C<&manicopy> are exportable.
433
434=head1 GLOBAL VARIABLES
435
436C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
437results in both a different C<MANIFEST> and a different
438C<MANIFEST.SKIP> file. This is useful if you want to maintain
439different distributions for different audiences (say a user version
440and a developer version including RCS).
441
81ff29e3 442C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
79dd614e 443all functions act silently.
444
0b9c804f 445C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
446or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
447produced.
448
79dd614e 449=head1 DIAGNOSTICS
450
451All diagnostic output is sent to C<STDERR>.
452
bbc7dcd2 453=over 4
79dd614e 454
455=item C<Not in MANIFEST:> I<file>
456
457is reported if a file is found, that is missing in the C<MANIFEST>
458file which is excluded by a regular expression in the file
459C<MANIFEST.SKIP>.
460
461=item C<No such file:> I<file>
462
463is reported if a file mentioned in a C<MANIFEST> file does not
464exist.
465
466=item C<MANIFEST:> I<$!>
467
468is reported if C<MANIFEST> could not be opened.
469
470=item C<Added to MANIFEST:> I<file>
471
472is reported by mkmanifest() if $Verbose is set and a file is added
473to MANIFEST. $Verbose is set to 1 by default.
474
475=back
476
0b9c804f 477=head1 ENVIRONMENT
478
479=over 4
480
481=item B<PERL_MM_MANIFEST_DEBUG>
482
483Turns on debugging
484
485=back
486
79dd614e 487=head1 SEE ALSO
488
489L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
490
491=head1 AUTHOR
492
e309c560 493Andreas Koenig <F<andreas.koenig@anima.de>>
79dd614e 494
495=cut