[win32] reverse integrate asperl branch contents (phew!)
[p5sagit/p5-mst-13.2.git] / lib / ExtUtils / Install.pm
CommitLineData
4b6d56d3 1package ExtUtils::Install;
2
456e5c25 3$VERSION = substr q$Revision: 1.28 $, 10;
4# $Date: 1998/01/25 07:08:24 $
f1387719 5
08ad6bd5 6use Exporter;
08ad6bd5 7use Carp ();
c3648e42 8use Config qw(%Config);
f1387719 9use vars qw(@ISA @EXPORT $VERSION);
4b6d56d3 10@ISA = ('Exporter');
c3648e42 11@EXPORT = ('install','uninstall','pm_to_blib', 'install_default');
08ad6bd5 12$Is_VMS = $^O eq 'VMS';
13
39e571d4 14my $splitchar = $^O eq 'VMS' ? '|' : ($^O eq 'os2' || $^O eq 'dos') ? ';' : ':';
d6abf24b 15my @PERL_ENV_LIB = split $splitchar, defined $ENV{'PERL5LIB'} ? $ENV{'PERL5LIB'} : $ENV{'PERLLIB'} || '';
f1387719 16my $Inc_uninstall_warn_handler;
17
08ad6bd5 18#use vars qw( @EXPORT @ISA $Is_VMS );
4b6d56d3 19#use strict;
20
f1387719 21sub forceunlink {
22 chmod 0666, $_[0];
23 unlink $_[0] or Carp::croak("Cannot forceunlink $_[0]: $!")
24}
08ad6bd5 25
4b6d56d3 26sub install {
f1387719 27 my($hash,$verbose,$nonono,$inc_uninstall) = @_;
4b6d56d3 28 $verbose ||= 0;
29 $nonono ||= 0;
08ad6bd5 30
31 use Cwd qw(cwd);
32 use ExtUtils::MakeMaker; # to implement a MY class
354f3b56 33 use ExtUtils::Packlist;
08ad6bd5 34 use File::Basename qw(dirname);
35 use File::Copy qw(copy);
36 use File::Find qw(find);
37 use File::Path qw(mkpath);
fb73857a 38 use File::Compare qw(compare);
08ad6bd5 39
4b6d56d3 40 my(%hash) = %$hash;
354f3b56 41 my(%pack, $dir, $warn_permissions);
42 my($packlist) = ExtUtils::Packlist->new();
3e3baf6d 43 # -w doesn't work reliably on FAT dirs
44 $warn_permissions++ if $^O eq 'MSWin32';
354f3b56 45 local(*DIR);
4b6d56d3 46 for (qw/read write/) {
47 $pack{$_}=$hash{$_};
48 delete $hash{$_};
49 }
08ad6bd5 50 my($source_dir_or_file);
51 foreach $source_dir_or_file (sort keys %hash) {
4b6d56d3 52 #Check if there are files, and if yes, look if the corresponding
53 #target directory is writable for us
08ad6bd5 54 opendir DIR, $source_dir_or_file or next;
f1387719 55 for (readdir DIR) {
4b6d56d3 56 next if $_ eq "." || $_ eq ".." || $_ eq ".exists";
456e5c25 57 if (-w $hash{$source_dir_or_file} ||
58 mkpath($hash{$source_dir_or_file})) {
4b6d56d3 59 last;
60 } else {
456e5c25 61 warn "Warning: You do not have permissions to " .
62 "install into $hash{$source_dir_or_file}"
cee7b94a 63 unless $warn_permissions++;
4b6d56d3 64 }
65 }
66 closedir DIR;
67 }
354f3b56 68 $packlist->read($pack{"read"}) if (-f $pack{"read"});
4b6d56d3 69 my $cwd = cwd();
08ad6bd5 70 my $umask = umask 0 unless $Is_VMS;
4b6d56d3 71
4b6d56d3 72 my($source);
73 MOD_INSTALL: foreach $source (sort keys %hash) {
74 #copy the tree to the target directory without altering
75 #timestamp and permission and remember for the .packlist
76 #file. The packlist file contains the absolute paths of the
77 #install locations. AFS users may call this a bug. We'll have
78 #to reconsider how to add the means to satisfy AFS users also.
456e5c25 79
80 #October 1997: we want to install .pm files into archlib if
81 #there are any files in arch. So we depend on having ./blib/arch
82 #hardcoded here.
83 my $targetroot = $hash{$source};
6ee623d5 84 if ($source eq "blib/lib" and
85 exists $hash{"blib/arch"} and
86 directory_not_empty("blib/arch")) {
87 $targetroot = $hash{"blib/arch"};
88 print "Files found in blib/arch --> Installing files in "
89 . "blib/lib into architecture dependend library tree!\n"
90 ; #if $verbose>1;
456e5c25 91 }
4b6d56d3 92 chdir($source) or next;
93 find(sub {
94 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
95 $atime,$mtime,$ctime,$blksize,$blocks) = stat;
96 return unless -f _;
97 return if $_ eq ".exists";
456e5c25 98 my $targetdir = MY->catdir($targetroot,$File::Find::dir);
99 my $targetfile = MY->catfile($targetdir,$_);
4b6d56d3 100
f1387719 101 my $diff = 0;
4b6d56d3 102 if ( -f $targetfile && -s _ == $size) {
103 # We have a good chance, we can skip this one
fb73857a 104 $diff = compare($_,$targetfile);
4b6d56d3 105 } else {
106 print "$_ differs\n" if $verbose>1;
107 $diff++;
108 }
109
110 if ($diff){
08ad6bd5 111 if (-f $targetfile){
f1387719 112 forceunlink($targetfile) unless $nonono;
08ad6bd5 113 } else {
114 mkpath($targetdir,0,0755) unless $nonono;
115 print "mkpath($targetdir,0,0755)\n" if $verbose>1;
116 }
4b6d56d3 117 copy($_,$targetfile) unless $nonono;
f1387719 118 print "Installing $targetfile\n";
08ad6bd5 119 utime($atime,$mtime + $Is_VMS,$targetfile) unless $nonono>1;
4b6d56d3 120 print "utime($atime,$mtime,$targetfile)\n" if $verbose>1;
f1387719 121 $mode = 0444 | ( $mode & 0111 ? 0111 : 0 );
4b6d56d3 122 chmod $mode, $targetfile;
123 print "chmod($mode, $targetfile)\n" if $verbose>1;
124 } else {
f1387719 125 print "Skipping $targetfile (unchanged)\n" if $verbose;
126 }
127
128 if (! defined $inc_uninstall) { # it's called
129 } elsif ($inc_uninstall == 0){
130 inc_uninstall($_,$File::Find::dir,$verbose,1); # nonono set to 1
131 } else {
132 inc_uninstall($_,$File::Find::dir,$verbose,0); # nonono set to 0
4b6d56d3 133 }
354f3b56 134 $packlist->{$targetfile}++;
4b6d56d3 135
136 }, ".");
08ad6bd5 137 chdir($cwd) or Carp::croak("Couldn't chdir to $cwd: $!");
4b6d56d3 138 }
08ad6bd5 139 umask $umask unless $Is_VMS;
4b6d56d3 140 if ($pack{'write'}) {
141 $dir = dirname($pack{'write'});
142 mkpath($dir,0,0755);
143 print "Writing $pack{'write'}\n";
354f3b56 144 $packlist->write($pack{'write'});
4b6d56d3 145 }
146}
147
456e5c25 148sub directory_not_empty ($) {
149 my($dir) = @_;
150 my $files = 0;
151 find(sub {
152 return if $_ eq ".exists";
153 if (-f) {
154 $File::Find::prune++;
155 $files = 1;
156 }
157 }, $dir);
158 return $files;
159}
160
c3648e42 161sub install_default {
162 @_ < 2 or die "install_default should be called with 0 or 1 argument";
163 my $FULLEXT = @_ ? shift : $ARGV[0];
164 defined $FULLEXT or die "Do not know to where to write install log";
165 my $INST_LIB = MM->catdir(MM->curdir,"blib","lib");
166 my $INST_ARCHLIB = MM->catdir(MM->curdir,"blib","arch");
167 my $INST_BIN = MM->catdir(MM->curdir,'blib','bin');
168 my $INST_SCRIPT = MM->catdir(MM->curdir,'blib','script');
169 my $INST_MAN1DIR = MM->catdir(MM->curdir,'blib','man1');
170 my $INST_MAN3DIR = MM->catdir(MM->curdir,'blib','man3');
171 install({
172 read => "$Config{sitearchexp}/auto/$FULLEXT/.packlist",
173 write => "$Config{installsitearch}/auto/$FULLEXT/.packlist",
456e5c25 174 $INST_LIB => (directory_not_empty($INST_ARCHLIB)) ?
175 $Config{installsitearch} :
176 $Config{installsitelib},
c3648e42 177 $INST_ARCHLIB => $Config{installsitearch},
178 $INST_BIN => $Config{installbin} ,
179 $INST_SCRIPT => $Config{installscript},
180 $INST_MAN1DIR => $Config{installman1dir},
181 $INST_MAN3DIR => $Config{installman3dir},
182 },1,0,0);
183}
184
4b6d56d3 185sub uninstall {
354f3b56 186 use ExtUtils::Packlist;
4b6d56d3 187 my($fil,$verbose,$nonono) = @_;
188 die "no packlist file found: $fil" unless -f $fil;
f1387719 189 # my $my_req = $self->catfile(qw(auto ExtUtils Install forceunlink.al));
190 # require $my_req; # Hairy, but for the first
354f3b56 191 my ($packlist) = ExtUtils::Packlist->new($fil);
192 foreach (sort(keys(%$packlist))) {
4b6d56d3 193 chomp;
194 print "unlink $_\n" if $verbose;
f1387719 195 forceunlink($_) unless $nonono;
4b6d56d3 196 }
197 print "unlink $fil\n" if $verbose;
456e5c25 198 close P;
f1387719 199 forceunlink($fil) unless $nonono;
200}
201
202sub inc_uninstall {
203 my($file,$libdir,$verbose,$nonono) = @_;
204 my($dir);
f1387719 205 my %seen_dir = ();
456e5c25 206 foreach $dir (@INC, @PERL_ENV_LIB, @Config{qw(archlibexp
207 privlibexp
208 sitearchexp
209 sitelibexp)}) {
f1387719 210 next if $dir eq ".";
211 next if $seen_dir{$dir}++;
456e5c25 212 my($targetfile) = MY->catfile($dir,$libdir,$file);
f1387719 213 next unless -f $targetfile;
214
215 # The reason why we compare file's contents is, that we cannot
216 # know, which is the file we just installed (AFS). So we leave
217 # an identical file in place
218 my $diff = 0;
219 if ( -f $targetfile && -s _ == -s $file) {
220 # We have a good chance, we can skip this one
fb73857a 221 $diff = compare($file,$targetfile);
f1387719 222 } else {
223 print "#$file and $targetfile differ\n" if $verbose>1;
224 $diff++;
225 }
226
227 next unless $diff;
228 if ($nonono) {
229 if ($verbose) {
230 $Inc_uninstall_warn_handler ||= new ExtUtils::Install::Warn;
231 $libdir =~ s|^\./|| ; # That's just cosmetics, no need to port. It looks prettier.
232 $Inc_uninstall_warn_handler->add("$libdir/$file",$targetfile);
233 }
234 # if not verbose, we just say nothing
235 } else {
236 print "Unlinking $targetfile (shadowing?)\n";
237 forceunlink($targetfile);
238 }
239 }
08ad6bd5 240}
241
242sub pm_to_blib {
243 my($fromto,$autodir) = @_;
244
245 use File::Basename qw(dirname);
246 use File::Copy qw(copy);
247 use File::Path qw(mkpath);
fb73857a 248 use File::Compare qw(compare);
08ad6bd5 249 use AutoSplit;
f1387719 250 # my $my_req = $self->catfile(qw(auto ExtUtils Install forceunlink.al));
251 # require $my_req; # Hairy, but for the first
08ad6bd5 252
68dc0745 253 if (!ref($fromto) && -r $fromto)
254 {
255 # Win32 has severe command line length limitations, but
256 # can generate temporary files on-the-fly
257 # so we pass name of file here - eval it to get hash
258 open(FROMTO,"<$fromto") or die "Cannot open $fromto:$!";
259 my $str = '$fromto = {qw{'.join('',<FROMTO>).'}}';
260 eval $str;
261 close(FROMTO);
262 }
263
08ad6bd5 264 my $umask = umask 0022 unless $Is_VMS;
265 mkpath($autodir,0,0755);
266 foreach (keys %$fromto) {
267 next if -f $fromto->{$_} && -M $fromto->{$_} < -M $_;
fb73857a 268 unless (compare($_,$fromto->{$_})){
08ad6bd5 269 print "Skip $fromto->{$_} (unchanged)\n";
270 next;
271 }
272 if (-f $fromto->{$_}){
f1387719 273 forceunlink($fromto->{$_});
08ad6bd5 274 } else {
275 mkpath(dirname($fromto->{$_}),0,0755);
276 }
277 copy($_,$fromto->{$_});
cee7b94a 278 my($mode,$atime,$mtime) = (stat)[2,8,9];
279 utime($atime,$mtime+$Is_VMS,$fromto->{$_});
280 chmod(0444 | ( $mode & 0111 ? 0111 : 0 ),$fromto->{$_});
08ad6bd5 281 print "cp $_ $fromto->{$_}\n";
282 next unless /\.pm$/;
283 autosplit($fromto->{$_},$autodir);
284 }
285 umask $umask unless $Is_VMS;
4b6d56d3 286}
287
f1387719 288package ExtUtils::Install::Warn;
289
290sub new { bless {}, shift }
291
292sub add {
293 my($self,$file,$targetfile) = @_;
294 push @{$self->{$file}}, $targetfile;
295}
296
297sub DESTROY {
298 my $self = shift;
299 my($file,$i,$plural);
300 foreach $file (sort keys %$self) {
301 $plural = @{$self->{$file}} > 1 ? "s" : "";
302 print "## Differing version$plural of $file found. You might like to\n";
303 for (0..$#{$self->{$file}}) {
304 print "rm ", $self->{$file}[$_], "\n";
305 $i++;
306 }
307 }
308 $plural = $i>1 ? "all those files" : "this file";
309 print "## Running 'make install UNINST=1' will unlink $plural for you.\n";
310}
311
4b6d56d3 3121;
313
314__END__
315
316=head1 NAME
317
318ExtUtils::Install - install files from here to there
319
320=head1 SYNOPSIS
321
322B<use ExtUtils::Install;>
323
324B<install($hashref,$verbose,$nonono);>
325
326B<uninstall($packlistfile,$verbose,$nonono);>
327
08ad6bd5 328B<pm_to_blib($hashref);>
329
4b6d56d3 330=head1 DESCRIPTION
331
08ad6bd5 332Both install() and uninstall() are specific to the way
4b6d56d3 333ExtUtils::MakeMaker handles the installation and deinstallation of
334perl modules. They are not designed as general purpose tools.
335
336install() takes three arguments. A reference to a hash, a verbose
337switch and a don't-really-do-it switch. The hash ref contains a
338mapping of directories: each key/value pair is a combination of
339directories to be copied. Key is a directory to copy from, value is a
340directory to copy to. The whole tree below the "from" directory will
341be copied preserving timestamps and permissions.
342
343There are two keys with a special meaning in the hash: "read" and
344"write". After the copying is done, install will write the list of
1fef88e7 345target files to the file named by C<$hashref-E<gt>{write}>. If there is
346another file named by C<$hashref-E<gt>{read}>, the contents of this file will
4b6d56d3 347be merged into the written file. The read and the written file may be
348identical, but on AFS it is quite likely, people are installing to a
349different directory than the one where the files later appear.
350
c3648e42 351install_default() takes one or less arguments. If no arguments are
352specified, it takes $ARGV[0] as if it was specified as an argument.
353The argument is the value of MakeMaker's C<FULLEXT> key, like F<Tk/Canvas>.
354This function calls install() with the same arguments as the defaults
355the MakeMaker would use.
356
357The argumement-less form is convenient for install scripts like
358
359 perl -MExtUtils::Install -e install_default Tk/Canvas
360
361Assuming this command is executed in a directory with populated F<blib>
362directory, it will proceed as if the F<blib> was build by MakeMaker on
363this machine. This is useful for binary distributions.
364
4b6d56d3 365uninstall() takes as first argument a file containing filenames to be
366unlinked. The second argument is a verbose switch, the third is a
367no-don't-really-do-it-now switch.
368
08ad6bd5 369pm_to_blib() takes a hashref as the first argument and copies all keys
370of the hash to the corresponding values efficiently. Filenames with
371the extension pm are autosplit. Second argument is the autosplit
372directory.
4b6d56d3 373
08ad6bd5 374=cut