| 1 | #!./perl -w | 
|---|
| 2 | BEGIN { @INC = qw(lib) } | 
|---|
| 3 | use strict; | 
|---|
| 4 | use Config; | 
|---|
| 5 | use Getopt::Long; | 
|---|
| 6 | use File::Find; | 
|---|
| 7 | use File::Copy; | 
|---|
| 8 | use File::Path qw(mkpath); | 
|---|
| 9 | use ExtUtils::Packlist; | 
|---|
| 10 | use Pod::Man; | 
|---|
| 11 | use subs qw(unlink chmod rename link); | 
|---|
| 12 | use vars qw($packlist); | 
|---|
| 13 |  | 
|---|
| 14 | if ($Config{d_umask}) { | 
|---|
| 15 | umask(022); # umasks like 077 aren't that useful for installations | 
|---|
| 16 | } | 
|---|
| 17 |  | 
|---|
| 18 | $ENV{SHELL} = 'sh' if $^O eq 'os2'; | 
|---|
| 19 |  | 
|---|
| 20 | my $ver = $Config{version};     # Not used presently. | 
|---|
| 21 | my $release = substr($],0,3);   # Not used presently. | 
|---|
| 22 | my $patchlevel = substr($],3,2); | 
|---|
| 23 | die "Patchlevel of perl ($patchlevel)", | 
|---|
| 24 | "and patchlevel of config.sh ($Config{'PERL_VERSION'}) don't match\n" | 
|---|
| 25 | if $patchlevel != $Config{'PERL_VERSION'}; | 
|---|
| 26 |  | 
|---|
| 27 | my $usage = | 
|---|
| 28 | "Usage:  installman --man1dir=/usr/wherever --man1ext=1 | 
|---|
| 29 | --man3dir=/usr/wherever --man3ext=3 | 
|---|
| 30 | --batchlimit=40 | 
|---|
| 31 | --notify --verbose --silent --help | 
|---|
| 32 | Defaults are: | 
|---|
| 33 | man1dir = $Config{'installman1dir'}; | 
|---|
| 34 | man1ext = $Config{'man1ext'}; | 
|---|
| 35 | man3dir = $Config{'installman3dir'}; | 
|---|
| 36 | man3ext = $Config{'man3ext'}; | 
|---|
| 37 | --notify  (or -n) just lists commands that would be executed. | 
|---|
| 38 | --verbose (or -V) report all progress. | 
|---|
| 39 | --silent  (or -S) be silent. Only report errors.\n"; | 
|---|
| 40 |  | 
|---|
| 41 | my %opts; | 
|---|
| 42 | GetOptions( \%opts, | 
|---|
| 43 | qw( man1dir=s man1ext=s man3dir=s man3ext=s batchlimit=i | 
|---|
| 44 | destdir:s notify n help silent S verbose V)) | 
|---|
| 45 | || die $usage; | 
|---|
| 46 | die $usage if $opts{help}; | 
|---|
| 47 |  | 
|---|
| 48 | my %MyConfig; | 
|---|
| 49 | $MyConfig{'installbin'}      = $Config{'installbin'}; | 
|---|
| 50 | $MyConfig{'installscript'}   = $Config{'installscript'}; | 
|---|
| 51 | $MyConfig{'installarchlib'}  = $Config{'installarchlib'}; | 
|---|
| 52 | $MyConfig{'installsitelib'}  = $Config{'installsitelib'}; | 
|---|
| 53 | $MyConfig{'installsitearch'} = $Config{'installsitearch'}; | 
|---|
| 54 | $MyConfig{'installprivlib'}  = $Config{'installprivlib'}; | 
|---|
| 55 | $MyConfig{'installman1dir'}  = $Config{'installman1dir'}; | 
|---|
| 56 | $MyConfig{'installman3dir'}  = $Config{'installman3dir'}; | 
|---|
| 57 | if ($^O eq 'os2' && "$opts{destdir}" ne '') { | 
|---|
| 58 | # Drop the /@unixroot bit if not installing to the unixroot. | 
|---|
| 59 | my $unixroot = '/@unixroot'; | 
|---|
| 60 | $MyConfig{'installbin'}      =~ s/^$unixroot//; | 
|---|
| 61 | $MyConfig{'installscript'}   =~ s/^$unixroot//; | 
|---|
| 62 | $MyConfig{'installarchlib'}  =~ s/^$unixroot//; | 
|---|
| 63 | $MyConfig{'installsitelib'}  =~ s/^$unixroot//; | 
|---|
| 64 | $MyConfig{'installsitearch'} =~ s/^$unixroot//; | 
|---|
| 65 | $MyConfig{'installprivlib'}  =~ s/^$unixroot//; | 
|---|
| 66 | $MyConfig{'installman1dir'}  =~ s/^$unixroot//; | 
|---|
| 67 | $MyConfig{'installman3dir'}  =~ s/^$unixroot//; | 
|---|
| 68 | #$Config{'archlibexp'}      =~ s/^$unixroot//; | 
|---|
| 69 | #$Config{'privlibexp'}      =~ s/^$unixroot//; | 
|---|
| 70 | #$Config{'scriptdir'}       =~ s/^$unixroot//; | 
|---|
| 71 | #$Config{'sitearchexp'}     =~ s/^$unixroot//; | 
|---|
| 72 | #$Config{'sitelibexp'}      =~ s/^$unixroot//; | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 | $opts{man1dir} = "$opts{destdir}$MyConfig{'installman1dir'}" | 
|---|
| 76 | unless defined($opts{man1dir}); | 
|---|
| 77 | $opts{man1ext} = $Config{'man1ext'} | 
|---|
| 78 | unless defined($opts{man1ext}); | 
|---|
| 79 | $opts{man3dir} = "$opts{destdir}$MyConfig{'installman3dir'}" | 
|---|
| 80 | unless defined($opts{man3dir}); | 
|---|
| 81 | $opts{man3ext} = $Config{'man3ext'} | 
|---|
| 82 | unless defined($opts{man3ext}); | 
|---|
| 83 | $opts{silent} ||= $opts{S}; | 
|---|
| 84 | $opts{notify} ||= $opts{n}; | 
|---|
| 85 | $opts{verbose} ||= $opts{V} || $opts{notify}; | 
|---|
| 86 |  | 
|---|
| 87 | #Sanity checks | 
|---|
| 88 |  | 
|---|
| 89 | -x  "./perl$Config{exe_ext}" | 
|---|
| 90 | or warn "./perl$Config{exe_ext} not found!  Have you run make?\n"; | 
|---|
| 91 | -d  "$opts{destdir}$MyConfig{'installprivlib'}" | 
|---|
| 92 | || warn "Perl library directory $MyConfig{'installprivlib'} not found. | 
|---|
| 93 | Have you run make install?.  (Installing anyway.)\n"; | 
|---|
| 94 | -x "t/perl$Config{exe_ext}"             || warn "WARNING: You've never run 'make test'!!!", | 
|---|
| 95 | "  (Installing anyway.)\n"; | 
|---|
| 96 |  | 
|---|
| 97 | $packlist = ExtUtils::Packlist->new("$opts{destdir}$MyConfig{installarchlib}/.packlist"); | 
|---|
| 98 |  | 
|---|
| 99 |  | 
|---|
| 100 | # Install the main pod pages. | 
|---|
| 101 | pod2man('pod', $opts{man1dir}, $opts{man1ext}); | 
|---|
| 102 |  | 
|---|
| 103 | # Install the pods for library modules. | 
|---|
| 104 | pod2man('lib', $opts{man3dir}, $opts{man3ext}); | 
|---|
| 105 |  | 
|---|
| 106 | # Install the pods embedded in the installed scripts | 
|---|
| 107 | my $has_man1dir = $opts{man1dir} ne '' && -d $opts{man1dir}; | 
|---|
| 108 | open UTILS, "utils.lst" or die "Can't open 'utils.lst': $!"; | 
|---|
| 109 | while (<UTILS>) { | 
|---|
| 110 | next if /^#/; | 
|---|
| 111 | chomp; | 
|---|
| 112 | $_ = $1 if /#.*pod\s*=\s*(\S+)/; | 
|---|
| 113 | my ($where, $what) = m|^(\S*)/(\S+)|; | 
|---|
| 114 | pod2man($where, $opts{man1dir}, $opts{man1ext}, $what); | 
|---|
| 115 | if ($has_man1dir) { | 
|---|
| 116 | if (my ($where2, $what2) = m|#.*link\s*=\s*(\S+)/(\S+)|) { | 
|---|
| 117 | my $old = "$opts{man1dir}/$what.$opts{man1ext}"; | 
|---|
| 118 | my $new = "$opts{man1dir}/$what2.$opts{man1ext}"; | 
|---|
| 119 | unlink($new); | 
|---|
| 120 | link($old, $new); | 
|---|
| 121 | my $xold = $old; | 
|---|
| 122 | $xold =~ s/^\Q$opts{'destdir'}\E// if $opts{'destdir'}; | 
|---|
| 123 | my $xnew = $new; | 
|---|
| 124 | $xnew =~ s/^\Q$opts{'destdir'}\E// if $opts{'destdir'}; | 
|---|
| 125 | $packlist->{$xnew} = { from => $xold, type => 'link' }; | 
|---|
| 126 | } | 
|---|
| 127 | } | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | sub pod2man { | 
|---|
| 131 | # @script is scripts names if we are installing manpages embedded | 
|---|
| 132 | # in scripts, () otherwise | 
|---|
| 133 | my($poddir, $mandir, $manext, @script) = @_; | 
|---|
| 134 | if ($mandir eq ' ' or $mandir eq '') { | 
|---|
| 135 | if (@script) { | 
|---|
| 136 | warn "Skipping installation of $poddir/$_ man page.\n" | 
|---|
| 137 | foreach @script; | 
|---|
| 138 | } else { | 
|---|
| 139 | warn "Skipping installation of $poddir man pages.\n"; | 
|---|
| 140 | } | 
|---|
| 141 | return; | 
|---|
| 142 | } | 
|---|
| 143 |  | 
|---|
| 144 | print "installing from $poddir\n" if $opts{verbose}; | 
|---|
| 145 |  | 
|---|
| 146 | mkpath($mandir, $opts{verbose}, 0777) unless $opts{notify};  # In File::Path | 
|---|
| 147 | # Make a list of all the .pm and .pod files in the directory.  We avoid | 
|---|
| 148 | # chdir because we are running with @INC = '../lib', and modules may wish | 
|---|
| 149 | # to dynamically require Carp::Heavy or other diagnostics warnings. | 
|---|
| 150 | # Hash the names of files we find, keys are names relative to perl build | 
|---|
| 151 | # dir ('.'), values are names relative to $poddir. | 
|---|
| 152 | my %modpods; | 
|---|
| 153 | if (@script) { | 
|---|
| 154 | %modpods = (map {+"$poddir/$_", $_} @script); | 
|---|
| 155 | } | 
|---|
| 156 | else { | 
|---|
| 157 | File::Find::find({no_chdir=>1, | 
|---|
| 158 | wanted => sub { | 
|---|
| 159 | # $_ is $File::Find::name when using no_chdir | 
|---|
| 160 | if (-f $_ and /\.p(?:m|od)$/) { | 
|---|
| 161 | my $fullname = $_; | 
|---|
| 162 | s!^\Q$poddir\E/!!; | 
|---|
| 163 | $modpods{$fullname} = $_; | 
|---|
| 164 | } | 
|---|
| 165 | }}, | 
|---|
| 166 | $poddir); | 
|---|
| 167 | } | 
|---|
| 168 | my @to_process; | 
|---|
| 169 | foreach my $mod (sort keys %modpods) { | 
|---|
| 170 | my $manpage = $modpods{$mod}; | 
|---|
| 171 | my $tmp; | 
|---|
| 172 | # Skip .pm files that have corresponding .pod files, and Functions.pm. | 
|---|
| 173 | next if (($tmp = $mod) =~ s/\.pm$/.pod/ && -f $tmp); | 
|---|
| 174 | next if $mod =~ m:/t/:; # no pods from test directories | 
|---|
| 175 | next if ($manpage eq 'Pod/Functions.pm'); #### Used only by pod itself | 
|---|
| 176 |  | 
|---|
| 177 | # Skip files without pod docs | 
|---|
| 178 | my $has_pod; | 
|---|
| 179 | if (open T, $mod) | 
|---|
| 180 | { | 
|---|
| 181 | local $_; | 
|---|
| 182 | while (<T>) | 
|---|
| 183 | { | 
|---|
| 184 | ++$has_pod and last if /^=(?:head\d+|item|pod)\b/; | 
|---|
| 185 | } | 
|---|
| 186 |  | 
|---|
| 187 | close T; | 
|---|
| 188 | } | 
|---|
| 189 |  | 
|---|
| 190 | unless ($has_pod) | 
|---|
| 191 | { | 
|---|
| 192 | warn "no documentation in $mod\n"; | 
|---|
| 193 | next; | 
|---|
| 194 | } | 
|---|
| 195 |  | 
|---|
| 196 | # Convert name from  File/Basename.pm to File::Basename.3 format, | 
|---|
| 197 | # if necessary. | 
|---|
| 198 | $manpage =~ s#\.p(m|od)$##; | 
|---|
| 199 | if ($^O eq 'os2' || $^O eq 'amigaos' || $^O eq 'uwin' || $^O eq 'cygwin') { | 
|---|
| 200 | $manpage =~ s#/#.#g; | 
|---|
| 201 | } | 
|---|
| 202 | else { | 
|---|
| 203 | $manpage =~ s#/#::#g; | 
|---|
| 204 | } | 
|---|
| 205 | $tmp = "${mandir}/${manpage}.tmp"; | 
|---|
| 206 | $manpage = "${mandir}/${manpage}.${manext}"; | 
|---|
| 207 | push @to_process, [$mod, $tmp, $manpage]; | 
|---|
| 208 | } | 
|---|
| 209 |  | 
|---|
| 210 | my $parser = Pod::Man->new( section => $manext, | 
|---|
| 211 | official=> 1, | 
|---|
| 212 | center  => 'Perl Programmers Reference Guide' | 
|---|
| 213 | ); | 
|---|
| 214 | foreach my $page (@to_process) { | 
|---|
| 215 | my($pod, $tmp, $manpage) = @$page; | 
|---|
| 216 |  | 
|---|
| 217 | my $xmanpage = $manpage; | 
|---|
| 218 | $xmanpage =~ s/^\Q$opts{'destdir'}\E// if $opts{'destdir'}; | 
|---|
| 219 | print "  $xmanpage\n"; | 
|---|
| 220 | if (!$opts{notify} && $parser->parse_from_file($pod, $tmp)) { | 
|---|
| 221 | if (-s $tmp) { | 
|---|
| 222 | if (rename($tmp, $manpage)) { | 
|---|
| 223 | $packlist->{$xmanpage} = { type => 'file' }; | 
|---|
| 224 | next; | 
|---|
| 225 | } | 
|---|
| 226 | } | 
|---|
| 227 | unlink($tmp); | 
|---|
| 228 | } | 
|---|
| 229 | } | 
|---|
| 230 | } | 
|---|
| 231 |  | 
|---|
| 232 | $packlist->write() unless $opts{notify}; | 
|---|
| 233 | print "  Installation complete\n" if $opts{verbose}; | 
|---|
| 234 |  | 
|---|
| 235 | exit 0; | 
|---|
| 236 |  | 
|---|
| 237 |  | 
|---|
| 238 | ############################################################################### | 
|---|
| 239 | # Utility subroutines from installperl | 
|---|
| 240 |  | 
|---|
| 241 | sub unlink { | 
|---|
| 242 | my(@names) = @_; | 
|---|
| 243 | my $cnt = 0; | 
|---|
| 244 |  | 
|---|
| 245 | foreach my $name (@names) { | 
|---|
| 246 | next unless -e $name; | 
|---|
| 247 | chmod 0777, $name if $^O eq 'os2'; | 
|---|
| 248 | print "  unlink $name\n" if $opts{verbose}; | 
|---|
| 249 | ( CORE::unlink($name) and ++$cnt | 
|---|
| 250 | or warn "Couldn't unlink $name: $!\n" ) unless $opts{notify}; | 
|---|
| 251 | } | 
|---|
| 252 | return $cnt; | 
|---|
| 253 | } | 
|---|
| 254 |  | 
|---|
| 255 | sub link { | 
|---|
| 256 | my($from,$to) = @_; | 
|---|
| 257 | my($success) = 0; | 
|---|
| 258 |  | 
|---|
| 259 | print "  ln $from $to\n" if $opts{verbose}; | 
|---|
| 260 | eval { | 
|---|
| 261 | CORE::link($from, $to) | 
|---|
| 262 | ? $success++ | 
|---|
| 263 | : ($from =~ m#^/afs/# || $to =~ m#^/afs/#) | 
|---|
| 264 | ? die "AFS"  # okay inside eval {} | 
|---|
| 265 | : warn "Couldn't link $from to $to: $!\n" | 
|---|
| 266 | unless $opts{notify}; | 
|---|
| 267 | }; | 
|---|
| 268 | if ($@) { | 
|---|
| 269 | File::Copy::copy($from, $to) | 
|---|
| 270 | ? $success++ | 
|---|
| 271 | : warn "Couldn't copy $from to $to: $!\n" | 
|---|
| 272 | unless $opts{notify}; | 
|---|
| 273 | } | 
|---|
| 274 | $success; | 
|---|
| 275 | } | 
|---|
| 276 |  | 
|---|
| 277 | sub rename { | 
|---|
| 278 | my($from,$to) = @_; | 
|---|
| 279 | if (-f $to and not unlink($to)) { | 
|---|
| 280 | my($i); | 
|---|
| 281 | for ($i = 1; $i < 50; $i++) { | 
|---|
| 282 | last if CORE::rename($to, "$to.$i"); | 
|---|
| 283 | } | 
|---|
| 284 | warn("Cannot rename to `$to.$i': $!"), return 0 | 
|---|
| 285 | if $i >= 50;        # Give up! | 
|---|
| 286 | } | 
|---|
| 287 | link($from,$to) || return 0; | 
|---|
| 288 | unlink($from); | 
|---|
| 289 | } | 
|---|
| 290 |  | 
|---|
| 291 | sub chmod { | 
|---|
| 292 | my($mode,$name) = @_; | 
|---|
| 293 |  | 
|---|
| 294 | printf "  chmod %o %s\n", $mode, $name if $opts{verbose}; | 
|---|
| 295 | CORE::chmod($mode,$name) || warn sprintf("Couldn't chmod %o %s: $!\n",$mode,$name) | 
|---|
| 296 | unless $opts{notify}; | 
|---|
| 297 | } | 
|---|
| 298 |  | 
|---|
| 299 | sub samepath { | 
|---|
| 300 | my($p1, $p2) = @_; | 
|---|
| 301 | my($dev1, $ino1, $dev2, $ino2); | 
|---|
| 302 |  | 
|---|
| 303 | if ($p1 ne $p2) { | 
|---|
| 304 | ($dev1, $ino1) = stat($p1); | 
|---|
| 305 | ($dev2, $ino2) = stat($p2); | 
|---|
| 306 | ($dev1 == $dev2 && $ino1 == $ino2); | 
|---|
| 307 | } | 
|---|
| 308 | else { | 
|---|
| 309 | 1; | 
|---|
| 310 | } | 
|---|
| 311 | } | 
|---|