This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgrade to ExtUtils-Manifest-1.57
[perl5.git] / cpan / ExtUtils-Manifest / lib / ExtUtils / Manifest.pm
CommitLineData
005c1a0e
AD
1package ExtUtils::Manifest;
2
005c1a0e 3require Exporter;
8e07c86e 4use Config;
5dca256e 5use File::Basename;
79dd614e 6use File::Copy 'copy';
5dca256e 7use File::Find;
57b1a898 8use File::Spec;
005c1a0e 9use Carp;
8a1da95f
PP
10use strict;
11
57b1a898 12use vars qw($VERSION @ISA @EXPORT_OK
7e4d7138 13 $Is_MacOS $Is_VMS $Is_VMS_mode $Is_VMS_lc $Is_VMS_nodot
57b1a898 14 $Debug $Verbose $Quiet $MANIFEST $DEFAULT_MSKIP);
8a1da95f 15
551c793c 16$VERSION = '1.57';
8a1da95f 17@ISA=('Exporter');
479d2113
MS
18@EXPORT_OK = qw(mkmanifest
19 manicheck filecheck fullcheck skipcheck
20 manifind maniread manicopy maniadd
6dbcfe36 21 maniskip
479d2113 22 );
005c1a0e 23
db5fd395 24$Is_MacOS = $^O eq 'MacOS';
479d2113 25$Is_VMS = $^O eq 'VMS';
7e4d7138
SH
26$Is_VMS_mode = 0;
27$Is_VMS_lc = 0;
28$Is_VMS_nodot = 0; # No dots in dir names or double dots in files
29
30if ($Is_VMS) {
31 require VMS::Filespec if $Is_VMS;
32 my $vms_unix_rpt;
33 my $vms_efs;
34 my $vms_case;
35
36 $Is_VMS_mode = 1;
37 $Is_VMS_lc = 1;
38 $Is_VMS_nodot = 1;
39 if (eval { local $SIG{__DIE__}; require VMS::Feature; }) {
40 $vms_unix_rpt = VMS::Feature::current("filename_unix_report");
41 $vms_efs = VMS::Feature::current("efs_charset");
42 $vms_case = VMS::Feature::current("efs_case_preserve");
43 } else {
44 my $unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || '';
45 my $efs_charset = $ENV{'DECC$EFS_CHARSET'} || '';
46 my $efs_case = $ENV{'DECC$EFS_CASE_PRESERVE'} || '';
47 $vms_unix_rpt = $unix_rpt =~ /^[ET1]/i;
48 $vms_efs = $efs_charset =~ /^[ET1]/i;
49 $vms_case = $efs_case =~ /^[ET1]/i;
50 }
51 $Is_VMS_lc = 0 if ($vms_case);
52 $Is_VMS_mode = 0 if ($vms_unix_rpt);
53 $Is_VMS_nodot = 0 if ($vms_efs);
54}
005c1a0e 55
479d2113 56$Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
75e2e551
MS
57$Verbose = defined $ENV{PERL_MM_MANIFEST_VERBOSE} ?
58 $ENV{PERL_MM_MANIFEST_VERBOSE} : 1;
005c1a0e 59$Quiet = 0;
cb1a09d0 60$MANIFEST = 'MANIFEST';
479d2113 61
5dca256e 62$DEFAULT_MSKIP = File::Spec->catfile( dirname(__FILE__), "$MANIFEST.SKIP" );
4e68a208 63
479d2113
MS
64
65=head1 NAME
66
67ExtUtils::Manifest - utilities to write and check a MANIFEST file
68
69=head1 SYNOPSIS
70
71 use ExtUtils::Manifest qw(...funcs to import...);
72
73 mkmanifest();
74
75 my @missing_files = manicheck;
76 my @skipped = skipcheck;
77 my @extra_files = filecheck;
78 my($missing, $extra) = fullcheck;
79
80 my $found = manifind();
81
82 my $manifest = maniread();
83
84 manicopy($read,$target);
85
86 maniadd({$file => $comment, ...});
87
88
89=head1 DESCRIPTION
90
91=head2 Functions
92
93ExtUtils::Manifest exports no functions by default. The following are
94exported on request
95
96=over 4
97
98=item mkmanifest
99
100 mkmanifest();
101
102Writes all files in and below the current directory to your F<MANIFEST>.
6dbcfe36 103It works similar to the result of the Unix command
479d2113
MS
104
105 find . > MANIFEST
106
107All files that match any regular expression in a file F<MANIFEST.SKIP>
108(if it exists) are ignored.
109
6dbcfe36 110Any existing F<MANIFEST> file will be saved as F<MANIFEST.bak>.
479d2113
MS
111
112=cut
113
dedf98bc
MS
114sub _sort {
115 return sort { lc $a cmp lc $b } @_;
116}
117
005c1a0e
AD
118sub mkmanifest {
119 my $manimiss = 0;
0300da75 120 my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
005c1a0e 121 $read = {} if $manimiss;
864a5fa8 122 local *M;
a2fa79ff 123 my $bakbase = $MANIFEST;
7e4d7138 124 $bakbase =~ s/\./_/g if $Is_VMS_nodot; # avoid double dots
a2fa79ff 125 rename $MANIFEST, "$bakbase.bak" unless $manimiss;
6dbcfe36
SP
126 open M, "> $MANIFEST" or die "Could not open $MANIFEST: $!";
127 my $skip = maniskip();
005c1a0e
AD
128 my $found = manifind();
129 my($key,$val,$file,%all);
f1387719 130 %all = (%$found, %$read);
7e4d7138
SH
131 $all{$MANIFEST} = ($Is_VMS_mode ? "$MANIFEST\t\t" : '') .
132 'This list of files'
84876ac5 133 if $manimiss; # add new MANIFEST to known file list
dedf98bc 134 foreach $file (_sort keys %all) {
f6d6199c
MS
135 if ($skip->($file)) {
136 # Policy: only remove files if they're listed in MANIFEST.SKIP.
137 # Don't remove files just because they don't exist.
138 warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
139 next;
140 }
005c1a0e 141 if ($Verbose){
cb1a09d0 142 warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
005c1a0e 143 }
8e07c86e 144 my $text = $all{$file};
db5fd395 145 $file = _unmacify($file);
005c1a0e
AD
146 my $tabs = (5 - (length($file)+1)/8);
147 $tabs = 1 if $tabs < 1;
8e07c86e 148 $tabs = 0 unless $text;
6dbcfe36
SP
149 if ($file =~ /\s/) {
150 $file =~ s/([\\'])/\\$1/g;
151 $file = "'$file'";
152 }
8e07c86e 153 print M $file, "\t" x $tabs, $text, "\n";
005c1a0e
AD
154 }
155 close M;
156}
157
f6d6199c
MS
158# Geez, shouldn't this use File::Spec or File::Basename or something?
159# Why so careful about dependencies?
160sub clean_up_filename {
161 my $filename = shift;
162 $filename =~ s|^\./||;
163 $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
164 return $filename;
165}
166
479d2113
MS
167
168=item manifind
169
170 my $found = manifind();
171
172returns a hash reference. The keys of the hash are the files found
173below the current directory.
174
175=cut
176
005c1a0e 177sub manifind {
f6d6199c 178 my $p = shift || {};
f6d6199c
MS
179 my $found = {};
180
181 my $wanted = sub {
182 my $name = clean_up_filename($File::Find::name);
183 warn "Debug: diskfile $name\n" if $Debug;
57b1a898 184 return if -d $_;
7e4d7138
SH
185
186 if( $Is_VMS_lc ) {
f6d6199c
MS
187 $name =~ s#(.*)\.$#\L$1#;
188 $name = uc($name) if $name =~ /^MANIFEST(\.SKIP)?$/i;
189 }
190 $found->{$name} = "";
191 };
192
193 # We have to use "$File::Find::dir/$_" in preprocess, because
194 # $File::Find::name is unavailable.
195 # Also, it's okay to use / here, because MANIFEST files use Unix-style
196 # paths.
57b1a898 197 find({wanted => $wanted},
f6d6199c
MS
198 $Is_MacOS ? ":" : ".");
199
200 return $found;
005c1a0e
AD
201}
202
479d2113
MS
203
204=item manicheck
205
206 my @missing_files = manicheck();
207
208checks if all the files within a C<MANIFEST> in the current directory
209really do exist. If C<MANIFEST> and the tree below the current
2c91f887 210directory are in sync it silently returns an empty list.
479d2113
MS
211Otherwise it returns a list of files which are listed in the
212C<MANIFEST> but missing from the directory, and by default also
213outputs these names to STDERR.
214
215=cut
005c1a0e
AD
216
217sub manicheck {
45bc4d3a 218 return _check_files();
005c1a0e
AD
219}
220
479d2113
MS
221
222=item filecheck
223
224 my @extra_files = filecheck();
225
226finds files below the current directory that are not mentioned in the
227C<MANIFEST> file. An optional file C<MANIFEST.SKIP> will be
228consulted. Any file matching a regular expression in such a file will
229not be reported as missing in the C<MANIFEST> file. The list of any
230extraneous files found is returned, and by default also reported to
231STDERR.
232
233=cut
234
005c1a0e 235sub filecheck {
45bc4d3a 236 return _check_manifest();
005c1a0e
AD
237}
238
479d2113
MS
239
240=item fullcheck
241
242 my($missing, $extra) = fullcheck();
243
244does both a manicheck() and a filecheck(), returning then as two array
245refs.
246
247=cut
248
249sub fullcheck {
250 return [_check_files()], [_check_manifest()];
251}
252
253
254=item skipcheck
255
256 my @skipped = skipcheck();
257
258lists all the files that are skipped due to your C<MANIFEST.SKIP>
259file.
260
261=cut
262
8e07c86e 263sub skipcheck {
45bc4d3a
JH
264 my($p) = @_;
265 my $found = manifind();
6dbcfe36 266 my $matches = maniskip();
45bc4d3a
JH
267
268 my @skipped = ();
dedf98bc 269 foreach my $file (_sort keys %$found){
45bc4d3a 270 if (&$matches($file)){
551c793c 271 warn "Skipping $file\n" unless $Quiet;
45bc4d3a
JH
272 push @skipped, $file;
273 next;
274 }
275 }
276
277 return @skipped;
8e07c86e
AD
278}
279
f6d6199c 280
45bc4d3a
JH
281sub _check_files {
282 my $p = shift;
39e571d4 283 my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
45bc4d3a
JH
284 my $read = maniread() || {};
285 my $found = manifind($p);
286
287 my(@missfile) = ();
dedf98bc 288 foreach my $file (_sort keys %$read){
45bc4d3a
JH
289 warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
290 if ($dosnames){
291 $file = lc $file;
292 $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
293 $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
294 }
295 unless ( exists $found->{$file} ) {
296 warn "No such file: $file\n" unless $Quiet;
297 push @missfile, $file;
298 }
005c1a0e 299 }
45bc4d3a
JH
300
301 return @missfile;
302}
303
304
305sub _check_manifest {
306 my($p) = @_;
307 my $read = maniread() || {};
308 my $found = manifind($p);
6dbcfe36 309 my $skip = maniskip();
45bc4d3a
JH
310
311 my @missentry = ();
dedf98bc 312 foreach my $file (_sort keys %$found){
45bc4d3a
JH
313 next if $skip->($file);
314 warn "Debug: manicheck checking from disk $file\n" if $Debug;
315 unless ( exists $read->{$file} ) {
316 my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
317 warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
318 push @missentry, $file;
319 }
005c1a0e 320 }
45bc4d3a
JH
321
322 return @missentry;
005c1a0e
AD
323}
324
45bc4d3a 325
479d2113
MS
326=item maniread
327
328 my $manifest = maniread();
329 my $manifest = maniread($manifest_file);
330
331reads a named C<MANIFEST> file (defaults to C<MANIFEST> in the current
332directory) and returns a HASH reference with files being the keys and
333comments being the values of the HASH. Blank lines and lines which
334start with C<#> in the C<MANIFEST> file are discarded.
335
336=cut
337
005c1a0e
AD
338sub maniread {
339 my ($mfile) = @_;
15a074ca 340 $mfile ||= $MANIFEST;
005c1a0e
AD
341 my $read = {};
342 local *M;
6dbcfe36 343 unless (open M, "< $mfile"){
1c14aae0 344 warn "Problem opening $mfile: $!";
2530b651 345 return $read;
005c1a0e 346 }
2530b651 347 local $_;
005c1a0e 348 while (<M>){
2530b651 349 chomp;
1df8d179 350 next if /^\s*#/;
0e3309e2 351
6dbcfe36
SP
352 my($file, $comment);
353
354 # filename may contain spaces if enclosed in ''
355 # (in which case, \\ and \' are escapes)
356 if (($file, $comment) = /^'(\\[\\']|.+)+'\s*(.*)/) {
357 $file =~ s/\\([\\'])/$1/g;
358 }
359 else {
360 ($file, $comment) = /^(\S+)\s*(.*)/;
361 }
0e3309e2
MS
362 next unless $file;
363
2530b651
MS
364 if ($Is_MacOS) {
365 $file = _macify($file);
366 $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
367 }
7e4d7138 368 elsif ($Is_VMS_mode) {
2530b651
MS
369 require File::Basename;
370 my($base,$dir) = File::Basename::fileparse($file);
371 # Resolve illegal file specifications in the same way as tar
7e4d7138
SH
372 if ($Is_VMS_nodot) {
373 $dir =~ tr/./_/;
374 my(@pieces) = split(/\./,$base);
375 if (@pieces > 2)
376 { $base = shift(@pieces) . '.' . join('_',@pieces); }
377 my $okfile = "$dir$base";
378 warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
379 $file = $okfile;
380 }
381 $file = lc($file)
382 unless $Is_VMS_lc &&($file =~ /^MANIFEST(\.SKIP)?$/);
2530b651 383 }
0e3309e2
MS
384
385 $read->{$file} = $comment;
005c1a0e
AD
386 }
387 close M;
388 $read;
389}
390
6dbcfe36
SP
391=item maniskip
392
393 my $skipchk = maniskip();
394 my $skipchk = maniskip($manifest_skip_file);
395
396 if ($skipchk->($file)) { .. }
397
398reads a named C<MANIFEST.SKIP> file (defaults to C<MANIFEST.SKIP> in
399the current directory) and returns a CODE reference that tests whether
400a given filename should be skipped.
401
402=cut
403
005c1a0e 404# returns an anonymous sub that decides if an argument matches
6dbcfe36 405sub maniskip {
005c1a0e 406 my @skip ;
6dbcfe36 407 my $mfile = shift || "$MANIFEST.SKIP";
1c14aae0
RGS
408 _check_mskip_directives($mfile) if -f $mfile;
409 local(*M, $_);
6dbcfe36 410 open M, "< $mfile" or open M, "< $DEFAULT_MSKIP" or return sub {0};
005c1a0e 411 while (<M>){
551c793c
SH
412 chomp;
413 s/\r//;
414 $_ =~ qr{^\s*(?:(?:'([^\\']*(?:\\.[^\\']*)*)')|([^#\s]\S*))?(?:(?:\s*)|(?:\s+(.*?)\s*))$};
415 #my $comment = $3;
416 my $filename = $2;
417 if ( defined($1) ) {
418 $filename = $1;
419 $filename =~ s/\\(['\\])/$1/g;
420 }
421 next if (not defined($filename) or not $filename);
422 push @skip, _macify($filename);
005c1a0e
AD
423 }
424 close M;
b3217f3b
SP
425 return sub {0} unless (scalar @skip > 0);
426
7e4d7138 427 my $opts = $Is_VMS_mode ? '(?i)' : '';
f6d6199c
MS
428
429 # Make sure each entry is isolated in its own parentheses, in case
430 # any of them contain alternations
431 my $regex = join '|', map "(?:$_)", @skip;
432
45bc4d3a 433 return sub { $_[0] =~ qr{$opts$regex} };
005c1a0e
AD
434}
435
1c14aae0
RGS
436# checks for the special directives
437# #!include_default
438# #!include /path/to/some/manifest.skip
439# in a custom MANIFEST.SKIP for, for including
440# the content of, respectively, the default MANIFEST.SKIP
441# and an external manifest.skip file
442sub _check_mskip_directives {
443 my $mfile = shift;
444 local (*M, $_);
445 my @lines = ();
446 my $flag = 0;
6dbcfe36 447 unless (open M, "< $mfile") {
1c14aae0
RGS
448 warn "Problem opening $mfile: $!";
449 return;
450 }
451 while (<M>) {
452 if (/^#!include_default\s*$/) {
453 if (my @default = _include_mskip_file()) {
454 push @lines, @default;
455 warn "Debug: Including default MANIFEST.SKIP\n" if $Debug;
456 $flag++;
457 }
458 next;
459 }
460 if (/^#!include\s+(.*)\s*$/) {
461 my $external_file = $1;
462 if (my @external = _include_mskip_file($external_file)) {
463 push @lines, @external;
464 warn "Debug: Including external $external_file\n" if $Debug;
465 $flag++;
466 }
467 next;
468 }
469 push @lines, $_;
470 }
471 close M;
472 return unless $flag;
a2fa79ff 473 my $bakbase = $mfile;
7e4d7138 474 $bakbase =~ s/\./_/g if $Is_VMS_nodot; # avoid double dots
a2fa79ff
CB
475 rename $mfile, "$bakbase.bak";
476 warn "Debug: Saving original $mfile as $bakbase.bak\n" if $Debug;
6dbcfe36 477 unless (open M, "> $mfile") {
1c14aae0
RGS
478 warn "Problem opening $mfile: $!";
479 return;
480 }
481 print M $_ for (@lines);
482 close M;
483 return;
484}
485
486# returns an array containing the lines of an external
487# manifest.skip file, if given, or $DEFAULT_MSKIP
488sub _include_mskip_file {
489 my $mskip = shift || $DEFAULT_MSKIP;
490 unless (-f $mskip) {
491 warn qq{Included file "$mskip" not found - skipping};
492 return;
493 }
494 local (*M, $_);
6dbcfe36 495 unless (open M, "< $mskip") {
1c14aae0
RGS
496 warn "Problem opening $mskip: $!";
497 return;
498 }
499 my @lines = ();
500 push @lines, "\n#!start included $mskip\n";
501 push @lines, $_ while <M>;
502 close M;
503 push @lines, "#!end included $mskip\n\n";
504 return @lines;
505}
506
479d2113
MS
507=item manicopy
508
a7d1454b
RGS
509 manicopy(\%src, $dest_dir);
510 manicopy(\%src, $dest_dir, $how);
479d2113 511
a7d1454b
RGS
512Copies the files that are the keys in %src to the $dest_dir. %src is
513typically returned by the maniread() function.
514
515 manicopy( maniread(), $dest_dir );
516
517This function is useful for producing a directory tree identical to the
518intended distribution tree.
519
520$how can be used to specify a different methods of "copying". Valid
479d2113
MS
521values are C<cp>, which actually copies the files, C<ln> which creates
522hard links, and C<best> which mostly links the files but copies any
a7d1454b 523symbolic link to make a tree without any symbolic link. C<cp> is the
479d2113
MS
524default.
525
526=cut
527
005c1a0e 528sub manicopy {
8e07c86e 529 my($read,$target,$how)=@_;
005c1a0e 530 croak "manicopy() called without target argument" unless defined $target;
15a074ca 531 $how ||= 'cp';
005c1a0e
AD
532 require File::Path;
533 require File::Basename;
57b1a898 534
7e4d7138 535 $target = VMS::Filespec::unixify($target) if $Is_VMS_mode;
553c0e07 536 File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
57b1a898 537 foreach my $file (keys %$read){
db5fd395
CN
538 if ($Is_MacOS) {
539 if ($file =~ m!:!) {
540 my $dir = _maccat($target, $file);
541 $dir =~ s/[^:]+$//;
542 File::Path::mkpath($dir,1,0755);
543 }
544 cp_if_diff($file, _maccat($target, $file), $how);
545 } else {
7e4d7138 546 $file = VMS::Filespec::unixify($file) if $Is_VMS_mode;
db5fd395
CN
547 if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
548 my $dir = File::Basename::dirname($file);
7e4d7138 549 $dir = VMS::Filespec::unixify($dir) if $Is_VMS_mode;
db5fd395
CN
550 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
551 }
552 cp_if_diff($file, "$target/$file", $how);
84876ac5 553 }
005c1a0e
AD
554 }
555}
556
557sub cp_if_diff {
8a1da95f 558 my($from, $to, $how)=@_;
6dbcfe36
SP
559 if (! -f $from) {
560 carp "$from not found";
561 return;
562 }
8e07c86e
AD
563 my($diff) = 0;
564 local(*F,*T);
57b1a898 565 open(F,"< $from\0") or die "Can't read $from: $!\n";
db5fd395 566 if (open(T,"< $to\0")) {
2530b651 567 local $_;
8e07c86e
AD
568 while (<F>) { $diff++,last if $_ ne <T>; }
569 $diff++ unless eof(T);
570 close T;
571 }
572 else { $diff++; }
573 close F;
574 if ($diff) {
575 if (-e $to) {
576 unlink($to) or confess "unlink $to: $!";
577 }
7292dc67 578 STRICT_SWITCH: {
15a074ca
AK
579 best($from,$to), last STRICT_SWITCH if $how eq 'best';
580 cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
581 ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
582 croak("ExtUtils::Manifest::cp_if_diff " .
583 "called with illegal how argument [$how]. " .
584 "Legal values are 'best', 'cp', and 'ln'.");
585 }
8e07c86e
AD
586 }
587}
588
8e07c86e
AD
589sub cp {
590 my ($srcFile, $dstFile) = @_;
a7d1454b
RGS
591 my ($access,$mod) = (stat $srcFile)[8,9];
592
79dd614e 593 copy($srcFile,$dstFile);
9607fc9c 594 utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
1c14aae0 595 _manicopy_chmod($srcFile, $dstFile);
8e07c86e
AD
596}
597
a7d1454b 598
8e07c86e
AD
599sub ln {
600 my ($srcFile, $dstFile) = @_;
7e4d7138 601 # Fix-me - VMS can support links.
f0f13d0e 602 return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
8e07c86e 603 link($srcFile, $dstFile);
57b1a898 604
1c14aae0 605 unless( _manicopy_chmod($srcFile, $dstFile) ) {
57b1a898
MS
606 unlink $dstFile;
607 return;
4e6ea2c3
GS
608 }
609 1;
8e07c86e
AD
610}
611
a7d1454b
RGS
612# 1) Strip off all group and world permissions.
613# 2) Let everyone read it.
614# 3) If the owner can execute it, everyone can.
615sub _manicopy_chmod {
1c14aae0 616 my($srcFile, $dstFile) = @_;
57b1a898 617
1c14aae0
RGS
618 my $perm = 0444 | (stat $srcFile)[2] & 0700;
619 chmod( $perm | ( $perm & 0100 ? 0111 : 0 ), $dstFile );
a7d1454b 620}
57b1a898 621
7292dc67
RGS
622# Files that are often modified in the distdir. Don't hard link them.
623my @Exceptions = qw(MANIFEST META.yml SIGNATURE);
4633a7c4
LW
624sub best {
625 my ($srcFile, $dstFile) = @_;
7292dc67
RGS
626
627 my $is_exception = grep $srcFile =~ /$_/, @Exceptions;
628 if ($is_exception or !$Config{d_link} or -l $srcFile) {
4633a7c4
LW
629 cp($srcFile, $dstFile);
630 } else {
3dee4013 631 ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
4633a7c4
LW
632 }
633}
634
db5fd395
CN
635sub _macify {
636 my($file) = @_;
637
638 return $file unless $Is_MacOS;
a7d1454b 639
db5fd395
CN
640 $file =~ s|^\./||;
641 if ($file =~ m|/|) {
642 $file =~ s|/+|:|g;
643 $file = ":$file";
644 }
a7d1454b 645
db5fd395
CN
646 $file;
647}
648
649sub _maccat {
650 my($f1, $f2) = @_;
a7d1454b 651
db5fd395 652 return "$f1/$f2" unless $Is_MacOS;
a7d1454b 653
db5fd395
CN
654 $f1 .= ":$f2";
655 $f1 =~ s/([^:]:):/$1/g;
656 return $f1;
657}
658
659sub _unmacify {
660 my($file) = @_;
661
662 return $file unless $Is_MacOS;
5dca256e 663
db5fd395
CN
664 $file =~ s|^:||;
665 $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
666 $file =~ y|:|/|;
5dca256e 667
db5fd395
CN
668 $file;
669}
670
79dd614e 671
479d2113 672=item maniadd
79dd614e 673
479d2113 674 maniadd({ $file => $comment, ...});
79dd614e 675
1df8d179 676Adds an entry to an existing F<MANIFEST> unless its already there.
79dd614e 677
479d2113 678$file will be normalized (ie. Unixified). B<UNIMPLEMENTED>
79dd614e 679
479d2113 680=cut
79dd614e 681
479d2113
MS
682sub maniadd {
683 my($additions) = shift;
79dd614e 684
479d2113 685 _normalize($additions);
2530b651 686 _fix_manifest($MANIFEST);
79dd614e 687
479d2113 688 my $manifest = maniread();
30361541
JH
689 my @needed = grep { !exists $manifest->{$_} } keys %$additions;
690 return 1 unless @needed;
1df8d179 691
30361541
JH
692 open(MANIFEST, ">>$MANIFEST") or
693 die "maniadd() could not open $MANIFEST: $!";
2c91f887 694
30361541 695 foreach my $file (_sort @needed) {
dedf98bc 696 my $comment = $additions->{$file} || '';
6dbcfe36
SP
697 if ($file =~ /\s/) {
698 $file =~ s/([\\'])/\\$1/g;
699 $file = "'$file'";
700 }
30361541 701 printf MANIFEST "%-40s %s\n", $file, $comment;
479d2113 702 }
30361541
JH
703 close MANIFEST or die "Error closing $MANIFEST: $!";
704
705 return 1;
479d2113 706}
79dd614e 707
2530b651
MS
708
709# Sometimes MANIFESTs are missing a trailing newline. Fix this.
710sub _fix_manifest {
711 my $manifest_file = shift;
712
713 open MANIFEST, $MANIFEST or die "Could not open $MANIFEST: $!";
714
715 # Yes, we should be using seek(), but I'd like to avoid loading POSIX
716 # to get SEEK_*
717 my @manifest = <MANIFEST>;
718 close MANIFEST;
719
720 unless( $manifest[-1] =~ /\n\z/ ) {
721 open MANIFEST, ">>$MANIFEST" or die "Could not open $MANIFEST: $!";
722 print MANIFEST "\n";
723 close MANIFEST;
724 }
725}
5dca256e 726
2530b651 727
479d2113
MS
728# UNIMPLEMENTED
729sub _normalize {
730 return;
731}
79dd614e 732
79dd614e 733
479d2113 734=back
79dd614e 735
479d2113 736=head2 MANIFEST
79dd614e 737
5dca256e
RGS
738A list of files in the distribution, one file per line. The MANIFEST
739always uses Unix filepath conventions even if you're not on Unix. This
740means F<foo/bar> style not F<foo\bar>.
741
479d2113 742Anything between white space and an end of line within a C<MANIFEST>
5dca256e 743file is considered to be a comment. Any line beginning with # is also
6dbcfe36
SP
744a comment. Beginning with ExtUtils::Manifest 1.52, a filename may
745contain whitespace characters if it is enclosed in single quotes; single
746quotes or backslashes in that filename must be backslash-escaped.
5dca256e
RGS
747
748 # this a comment
749 some/file
750 some/other/file comment about some/file
6dbcfe36 751 'some/third file' comment
79dd614e 752
79dd614e 753
479d2113 754=head2 MANIFEST.SKIP
79dd614e
PP
755
756The file MANIFEST.SKIP may contain regular expressions of files that
757should be ignored by mkmanifest() and filecheck(). The regular
15a074ca
AK
758expressions should appear one on each line. Blank lines and lines
759which start with C<#> are skipped. Use C<\#> if you need a regular
5dca256e
RGS
760expression to start with a C<#>.
761
762For example:
79dd614e 763
0b9c804f 764 # Version control files and dirs.
79dd614e 765 \bRCS\b
0b9c804f
MS
766 \bCVS\b
767 ,v$
479d2113 768 \B\.svn\b
0b9c804f
MS
769
770 # Makemaker generated files and dirs.
79dd614e
PP
771 ^MANIFEST\.
772 ^Makefile$
79dd614e
PP
773 ^blib/
774 ^MakeMaker-\d
775
0b9c804f
MS
776 # Temp, old and emacs backup files.
777 ~$
778 \.old$
779 ^#.*#$
cfcce72b 780 ^\.#
0b9c804f
MS
781
782If no MANIFEST.SKIP file is found, a default set of skips will be
783used, similar to the example above. If you want nothing skipped,
784simply make an empty MANIFEST.SKIP file.
785
1c14aae0
RGS
786In one's own MANIFEST.SKIP file, certain directives
787can be used to include the contents of other MANIFEST.SKIP
788files. At present two such directives are recognized.
789
790=over 4
791
792=item #!include_default
793
794This inserts the contents of the default MANIFEST.SKIP file
795
796=item #!include /Path/to/another/manifest.skip
797
798This inserts the contents of the specified external file
799
800=back
801
802The included contents will be inserted into the MANIFEST.SKIP
803file in between I<#!start included /path/to/manifest.skip>
804and I<#!end included /path/to/manifest.skip> markers.
805The original MANIFEST.SKIP is saved as MANIFEST.SKIP.bak.
0b9c804f 806
479d2113 807=head2 EXPORT_OK
79dd614e
PP
808
809C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
810C<&maniread>, and C<&manicopy> are exportable.
811
479d2113 812=head2 GLOBAL VARIABLES
79dd614e
PP
813
814C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
815results in both a different C<MANIFEST> and a different
816C<MANIFEST.SKIP> file. This is useful if you want to maintain
817different distributions for different audiences (say a user version
818and a developer version including RCS).
819
81ff29e3 820C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
79dd614e
PP
821all functions act silently.
822
0b9c804f
MS
823C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value,
824or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
825produced.
826
79dd614e
PP
827=head1 DIAGNOSTICS
828
829All diagnostic output is sent to C<STDERR>.
830
bbc7dcd2 831=over 4
79dd614e
PP
832
833=item C<Not in MANIFEST:> I<file>
834
45bc4d3a
JH
835is reported if a file is found which is not in C<MANIFEST>.
836
837=item C<Skipping> I<file>
838
839is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
79dd614e
PP
840
841=item C<No such file:> I<file>
842
843is reported if a file mentioned in a C<MANIFEST> file does not
844exist.
845
846=item C<MANIFEST:> I<$!>
847
848is reported if C<MANIFEST> could not be opened.
849
850=item C<Added to MANIFEST:> I<file>
851
852is reported by mkmanifest() if $Verbose is set and a file is added
853to MANIFEST. $Verbose is set to 1 by default.
854
855=back
856
0b9c804f
MS
857=head1 ENVIRONMENT
858
859=over 4
860
861=item B<PERL_MM_MANIFEST_DEBUG>
862
863Turns on debugging
864
865=back
866
79dd614e
PP
867=head1 SEE ALSO
868
869L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
870
871=head1 AUTHOR
872
a7d1454b
RGS
873Andreas Koenig C<andreas.koenig@anima.de>
874
4c857482
SP
875Maintained by Michael G Schwern C<schwern@pobox.com> within the
876ExtUtils-MakeMaker package and, as a separate CPAN package, by
877Randy Kobes C<r.kobes@uwinnipeg.ca>.
79dd614e
PP
878
879=cut
479d2113
MS
880
8811;