package ExtUtils::Install; $VERSION = substr q$Revision: 1.2 $, 10; # $Date: 1997/11/30 07:57:24 $ use Exporter; use Carp (); use Config qw(%Config); use vars qw(@ISA @EXPORT $VERSION); @ISA = ('Exporter'); @EXPORT = ('install','uninstall','pm_to_blib', 'install_default'); $Is_VMS = $^O eq 'VMS'; my $splitchar = $^O eq 'VMS' ? '|' : $^O eq 'os2' ? ';' : ':'; my @PERL_ENV_LIB = split $splitchar, defined $ENV{'PERL5LIB'} ? $ENV{'PERL5LIB'} : $ENV{'PERLLIB'} || ''; my $Inc_uninstall_warn_handler; #use vars qw( @EXPORT @ISA $Is_VMS ); #use strict; sub forceunlink { chmod 0666, $_[0]; unlink $_[0] or Carp::croak("Cannot forceunlink $_[0]: $!") } sub install { my($hash,$verbose,$nonono,$inc_uninstall) = @_; $verbose ||= 0; $nonono ||= 0; use Cwd qw(cwd); use ExtUtils::MakeMaker; # to implement a MY class use File::Basename qw(dirname); use File::Copy qw(copy); use File::Find qw(find); use File::Path qw(mkpath); use File::Compare qw(compare); my(%hash) = %$hash; my(%pack, %write, $dir, $warn_permissions); # -w doesn't work reliably on FAT dirs $warn_permissions++ if $^O eq 'MSWin32'; local(*DIR, *P); for (qw/read write/) { $pack{$_}=$hash{$_}; delete $hash{$_}; } my($source_dir_or_file); foreach $source_dir_or_file (sort keys %hash) { #Check if there are files, and if yes, look if the corresponding #target directory is writable for us opendir DIR, $source_dir_or_file or next; for (readdir DIR) { next if $_ eq "." || $_ eq ".." || $_ eq ".exists"; if (-w $hash{$source_dir_or_file} || mkpath($hash{$source_dir_or_file})) { last; } else { warn "Warning: You do not have permissions to install into $hash{$source_dir_or_file}" unless $warn_permissions++; } } closedir DIR; } if (-f $pack{"read"}) { open P, $pack{"read"} or Carp::croak("Couldn't read $pack{'read'}"); # Remember what you found while (
) { chomp; $write{$_}++; } close P; } my $cwd = cwd(); my $umask = umask 0 unless $Is_VMS; # This silly reference is just here to be able to call MY->catdir # without a warning (Waiting for a proper path/directory module, # Charles!) my $MY = {}; bless $MY, 'MY'; my($source); MOD_INSTALL: foreach $source (sort keys %hash) { #copy the tree to the target directory without altering #timestamp and permission and remember for the .packlist #file. The packlist file contains the absolute paths of the #install locations. AFS users may call this a bug. We'll have #to reconsider how to add the means to satisfy AFS users also. chdir($source) or next; find(sub { my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat; return unless -f _; return if $_ eq ".exists"; my $targetdir = $MY->catdir($hash{$source},$File::Find::dir); my $targetfile = $MY->catfile($targetdir,$_); my $diff = 0; if ( -f $targetfile && -s _ == $size) { # We have a good chance, we can skip this one $diff = compare($_,$targetfile); } else { print "$_ differs\n" if $verbose>1; $diff++; } if ($diff){ if (-f $targetfile){ forceunlink($targetfile) unless $nonono; } else { mkpath($targetdir,0,0755) unless $nonono; print "mkpath($targetdir,0,0755)\n" if $verbose>1; } copy($_,$targetfile) unless $nonono; print "Installing $targetfile\n"; utime($atime,$mtime + $Is_VMS,$targetfile) unless $nonono>1; print "utime($atime,$mtime,$targetfile)\n" if $verbose>1; $mode = 0444 | ( $mode & 0111 ? 0111 : 0 ); chmod $mode, $targetfile; print "chmod($mode, $targetfile)\n" if $verbose>1; } else { print "Skipping $targetfile (unchanged)\n" if $verbose; } if (! defined $inc_uninstall) { # it's called } elsif ($inc_uninstall == 0){ inc_uninstall($_,$File::Find::dir,$verbose,1); # nonono set to 1 } else { inc_uninstall($_,$File::Find::dir,$verbose,0); # nonono set to 0 } $write{$targetfile}++; }, "."); chdir($cwd) or Carp::croak("Couldn't chdir to $cwd: $!"); } umask $umask unless $Is_VMS; if ($pack{'write'}) { $dir = dirname($pack{'write'}); mkpath($dir,0,0755); print "Writing $pack{'write'}\n"; open P, ">$pack{'write'}" or Carp::croak("Couldn't write $pack{'write'}: $!"); for (sort keys %write) { print P "$_\n"; } close P; } } sub install_default { @_ < 2 or die "install_default should be called with 0 or 1 argument"; my $FULLEXT = @_ ? shift : $ARGV[0]; defined $FULLEXT or die "Do not know to where to write install log"; my $INST_LIB = MM->catdir(MM->curdir,"blib","lib"); my $INST_ARCHLIB = MM->catdir(MM->curdir,"blib","arch"); my $INST_BIN = MM->catdir(MM->curdir,'blib','bin'); my $INST_SCRIPT = MM->catdir(MM->curdir,'blib','script'); my $INST_MAN1DIR = MM->catdir(MM->curdir,'blib','man1'); my $INST_MAN3DIR = MM->catdir(MM->curdir,'blib','man3'); install({ read => "$Config{sitearchexp}/auto/$FULLEXT/.packlist", write => "$Config{installsitearch}/auto/$FULLEXT/.packlist", $INST_LIB => $Config{installsitelib}, $INST_ARCHLIB => $Config{installsitearch}, $INST_BIN => $Config{installbin} , $INST_SCRIPT => $Config{installscript}, $INST_MAN1DIR => $Config{installman1dir}, $INST_MAN3DIR => $Config{installman3dir}, },1,0,0); } sub uninstall { my($fil,$verbose,$nonono) = @_; die "no packlist file found: $fil" unless -f $fil; # my $my_req = $self->catfile(qw(auto ExtUtils Install forceunlink.al)); # require $my_req; # Hairy, but for the first local *P; open P, $fil or Carp::croak("uninstall: Could not read packlist file $fil: $!"); while (
) {
chomp;
print "unlink $_\n" if $verbose;
forceunlink($_) unless $nonono;
}
print "unlink $fil\n" if $verbose;
forceunlink($fil) unless $nonono;
}
sub inc_uninstall {
my($file,$libdir,$verbose,$nonono) = @_;
my($dir);
my $MY = {};
bless $MY, 'MY';
my %seen_dir = ();
foreach $dir (@INC, @PERL_ENV_LIB, @Config{qw/archlibexp privlibexp sitearchexp sitelibexp/}) {
next if $dir eq ".";
next if $seen_dir{$dir}++;
my($targetfile) = $MY->catfile($dir,$libdir,$file);
next unless -f $targetfile;
# The reason why we compare file's contents is, that we cannot
# know, which is the file we just installed (AFS). So we leave
# an identical file in place
my $diff = 0;
if ( -f $targetfile && -s _ == -s $file) {
# We have a good chance, we can skip this one
$diff = compare($file,$targetfile);
} else {
print "#$file and $targetfile differ\n" if $verbose>1;
$diff++;
}
next unless $diff;
if ($nonono) {
if ($verbose) {
$Inc_uninstall_warn_handler ||= new ExtUtils::Install::Warn;
$libdir =~ s|^\./|| ; # That's just cosmetics, no need to port. It looks prettier.
$Inc_uninstall_warn_handler->add("$libdir/$file",$targetfile);
}
# if not verbose, we just say nothing
} else {
print "Unlinking $targetfile (shadowing?)\n";
forceunlink($targetfile);
}
}
}
sub pm_to_blib {
my($fromto,$autodir) = @_;
use File::Basename qw(dirname);
use File::Copy qw(copy);
use File::Path qw(mkpath);
use File::Compare qw(compare);
use AutoSplit;
# my $my_req = $self->catfile(qw(auto ExtUtils Install forceunlink.al));
# require $my_req; # Hairy, but for the first
if (!ref($fromto) && -r $fromto)
{
# Win32 has severe command line length limitations, but
# can generate temporary files on-the-fly
# so we pass name of file here - eval it to get hash
open(FROMTO,"<$fromto") or die "Cannot open $fromto:$!";
my $str = '$fromto = {qw{'.join('',