This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Also add all utilities for building from units to repo
[metaconfig.git] / bin / makedist
CommitLineData
459d3fb5
MBT
1#!/usr/bin/perl
2 eval "exec perl -S $0 $*"
3 if $running_under_some_shell;
4
5# $Id: makedist.SH 1 2006-08-24 12:32:52Z rmanfredi $
6#
7# Copyright (c) 1991-1997, 2004-2006, Raphael Manfredi
8#
9# You may redistribute only under the terms of the Artistic Licence,
10# as specified in the README file that comes with the distribution.
11# You may reuse parts of this distribution only within the terms of
12# that same Artistic Licence; a copy of which may be found at the root
13# of the source tree for dist 4.0.
14#
15# $Log: makedist.SH,v $
16# Revision 3.0.1.2 1994/01/24 13:58:20 ram
17# patch16: modified call to manifake to trap exceptions manually
18# patch16: removed final sed post-processing to allow 'make depend' target
19# patch16: added ~/.dist_profile awareness
20#
21# Revision 3.0.1.1 1993/08/19 06:42:17 ram
22# patch1: leading config.sh searching was not aborting properly
23#
24# Revision 3.0 1993/08/18 12:04:28 ram
25# Baseline for dist 3.0 netwide release.
26#
27
28$version = '3.5';
29$patchlevel = '0';
30
31&profile; # Read ~/.dist_profile
32require 'getopts.pl';
33&usage unless &Getopts('c:f:dhvqs:V');
34
35$ENV{'DIST'} = '/dev/null'; # Disable ~/.dist_profile
36
37if ($opt_V) {
38 print STDERR "makedist $version PL$patchlevel\n";
39 exit 0;
40} elsif ($opt_h) {
41 &usage;
42}
43
44$MAXKITSIZE = 50000 unless $MAXKITSIZE = $opt_s;
45$KITOVERHEAD = 1800;
46$FILEOVERHEAD = 90;
47$CHOPSIZE = $MAXKITSIZE - $KITOVERHEAD - $FILEOVERHEAD;
48
49$NEWMANI = 'MANIFEST.new' unless $NEWMANI = $opt_f;
50$MANI = 'MANIFEST' unless $opt_f;
51$PACKLIST = 'PACKLIST';
52$PACKNOTES = 'PACKNOTES';
53
54$tmpdir = "/tmp/MKst$$"; # Where to copy distribution
55$tmpdir = '.' if $opt_q; # Quick mode: no need to copy distribution
56
57&set_sig('aborted'); # Make sure we clean up in case of emergency
58
59&readpackage;
60&get_patchlevel;
61
62eval '&manifake'; # Want to trap possible die and redirect to fatal
63if ($@ ne '') {
64 chop($@);
65 &fatal($@);
66}
67
68if ($opt_c) { # Copy distribution only, no shell archive
69 &distcopy;
70 exit 0;
71}
72
73&distfake;
74&copyright'init($copyright) if -f $copyright;
75
76unlink <$package.kit? $package.kit??>;
77chop($curdir = `pwd`);
78chdir $tmpdir || die "Can't chdir to $tmpdir.\n";
79
80&maniread;
81&kitlists;
82&manimake;
83&kitbuild;
84&cleanup;
85exit 0;
86
87# Physically build the kits
88sub kitbuild {
89 $numkits = $#list;
90 if ($numkits > 9) {
91 $sp = '%02d';
92 } else {
93 $sp = '%d';
94 }
95
96 for ($kitnum = 1; $kitnum <= $numkits; $kitnum++) {
97 $list = $list[$kitnum];
98 $kit = sprintf("$package.kit" . $sp,$kitnum);
99 print "*** Making $kit ***\n";
100 open(KIT,">$curdir/$kit") || do fatal("Can't create $curdir/$kit: $!");
101
102 &kitleader;
103
104 @files = split(' ',$list);
105 reset 'X';
106 for $file (@files) {
107 $_ = $file;
108 while (s|^(.*)/.*$|$1|) {
109 push(@Xdirs,$_) unless $Xseen{$_}++;
110 }
111 }
112 print KIT "mkdir ",join(' ', sort @Xdirs)," 2>/dev/null\n";
113
114 foreach $file (@files) {
115 print "\t",$file,"\n" if $opt_v;
116 print KIT "echo Extracting $file\n";
117 print KIT "sed >$file <<'!STUFFY!FUNK!' -e 's/X//'\n";
118 open(FILE, $file);
119 &copyright'reset; # Reset copyright for new file
120 while (<FILE>) {
121 # Use Lock[e]r as a pattern in case it is applied on ourselves
122 s|Lock[e]r:.*\$|\$|; # Remove locker mark
123 print KIT &copyright'filter($_, 'X');
124 }
125 close FILE;
126 print KIT "!STUFFY!FUNK!\n";
127 -x "$file" && (print KIT "chmod +x $file\n");
128 }
129 &kittrailer;
130 chmod 0755, $kit;
131 }
132}
133
134sub kitlists {
135 for $filename (keys %comment) {
136 next if $filename =~ m|/$|; # Skip directories
137 next if -d $filename; # Better safe than sorry
138 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
139 $blksize,$blocks) = stat($filename);
140
141 # Make sure file is not larger than the CHOPSIZE limit. If it is,
142 # a split is attempted.
143 if ($size > $CHOPSIZE) {
144 print "Splitting $filename...\n" if $opt_v;
145 $file_comment = $comment{$filename};
146 open(FILE, $filename) || die "Can't open $filename: $!\n";
147 $piece = 'AA';
148 ($dir, $name) = ('.', $filename)
149 unless ($dir, $name) = ($filename =~ m|(.*)/(.*)|);
150 $chopped = $dir . '/' . substr($name, 0, 11);
151 $chopped =~ s|^\./||;
152 &fatal("There is already a split file named $chopped")
153 if defined $Chopped{$chopped};
154 $Chopped{$chopped} = $filename; # Association split <-> real file
155 $size = 0;
156 open(CURPIECE, ">$chopped:$piece") ||
157 &fatal("Can't create $chopped:$piece: $!");
158 while (<FILE>) {
159 if ($size + length($_) > $CHOPSIZE) {
160 close CURPIECE;
161 $size{"$chopped:$piece"} = $size;
162 $comment{"$chopped:$piece"} = "$file_comment (part $piece)";
163 push(@files, "$chopped:$piece");
164 print "\t$chopped:$piece ($size bytes)\n" if $opt_v;
165 $size = 0;
166 $piece++; # AA -> AB, etc...
167 open(CURPIECE, ">$chopped:$piece") ||
168 &fatal("Can't create $chopped:$piece: $!");
169 }
170 print CURPIECE $_;
171 $size += length($_);
172 }
173 close FILE;
174 close CURPIECE;
175 $size{"$chopped:$piece"} = $size;
176 $comment{"$chopped:$piece"} = "$file_comment (part $piece)";
177 push(@files, "$chopped:$piece");
178 print "\t$chopped:$piece ($size bytes)\n" if $opt_v;
179 delete $comment{$filename}; # File split, not in PACKLIST
180 } else {
181 $size += 1000000 if $filename =~ /README/;
182 $size{$filename} = $size;
183 push(@files, "$filename");
184 }
185 }
186
187 # Build a file PACKNOTES to reconstruct split files
188 if (defined %Chopped) {
189 open(PACKNOTES, ">$PACKNOTES") || &fatal("Can't create PACKNOTES: $!");
190 foreach (keys %Chopped) {
191 print PACKNOTES <<EOC;
192echo 'Building $Chopped{$_}...'
193cat $_:[A-Z][A-Z] > $Chopped{$_}
194rm -f $_:[A-Z][A-Z]
195EOC
196 }
197 close PACKNOTES;
198 push(@files, $PACKNOTES);
199 $comment{$PACKNOTES} = 'Script to reconstruct split files';
200 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
201 $blksize,$blocks) = stat($PACKNOTES);
202 $size{$PACKNOTES} = $size;
203 }
204
205 # Currently, file PACKLIST does not exist, so its size is unknown and
206 # it cannot be correctly put in one archive. Therefore, we take the
207 # size of MANIFEST.new, which will give us a good estimation.
208 push(@files, 'PACKLIST');
209
210 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
211 $blksize,$blocks) = stat($NEWMANI);
212 $size{$PACKLIST} = $size;
213
214 sub revnum { $size{$a} < $size{$b} ? 1 : $size{$a} > $size{$b} ? -1 : 0; }
215 @files = sort revnum @files;
216
217 for (@files) {
218 $size = $size{$_};
219 $size -= 1000000 if /README/;
220 $i=1;
221 while (($newtot = int($tot[$i] + $size + $size/40 + $FILEOVERHEAD)) >
222 $MAXKITSIZE-$KITOVERHEAD && $tot[$i]) {
223 $i++;
224 }
225 $tot[$i] = $newtot;
226 print "Adding $_ to kit $i giving $newtot bytes\n" if $opt_d;
227 $kit{$_} = $i;
228 $list[$i] .= " $_";
229 }
230}
231
232# Read manifest file and initialize the %comment array.
233sub maniread {
234 do fatal("You don't have a $NEWMANI file. Run manifake")
235 unless -f "$NEWMANI";
236 open(NEWMANI,$NEWMANI) || do fatal("Can't read $NEWMANI: $!");
237 while (<NEWMANI>) {
238 ($key,$val) = split(' ',$_,1) unless ($key,$val) = /^(\S+)\s+(.*)/;
239 $comment{$key} = $val;
240 }
241 close NEWMANI;
242}
243
244# MANIFEST and MANIFEST.new must say the same thing. Create the
245# PACKLIST file (thus avoiding kit numbers in MANIFEST, which causes big
246# patches when only re-ordering occurred). Note that PACKLIST should
247# not appear in MANIFEST.new (the user may remove it).
248sub manimake {
249 # Add built packlist
250 $comment{$PACKLIST} = 'Which files came with which kits';
251
252 open(PACKLIST, ">$PACKLIST") || do fatal("Can't create $PACKLIST: $!");
253 print PACKLIST
254"After all the $package kits are run you should have the following files:
255
256Filename Kit Description
257-------- --- -----------
258";
259 for (sort keys(comment)) {
260 printf PACKLIST "%-27s %2s %.47s\n", $_, $kit{$_}, $comment{$_};
261 }
262 close PACKLIST;
263}
264
265sub kitleader {
266 local($plevel);
267 $plevel = " at patchlevel $patch_level" if $patch_level ne '';
268 print KIT <<EOH;
269#! /bin/sh
270#
271# This is $package version $baserev$plevel.
272# Make a new directory for the $package sources, cd to it, and run kits 1 up
273# to $numkits through sh. When all $numkits kits have been run, read README.
274#
275echo " "
276cat <<EOM
277This is $package $baserev$plevel, kit $kitnum (of $numkits):
278If this shell archive is complete, the line "End of kit $kitnum (of $numkits)"
279will echo at the end.
280EOM
281export PATH || (echo "Please use sh to unpack this archive." ; kill \$\$)
282EOH
283}
284
285sub kittrailer {
286 $rangelist = '';
287 for ($i = 1; $i <= $numkits; $i++) {
288 $rangelist .= ' ' . $i;
289 }
290 print KIT <<EOM;
291echo \"End of kit $kitnum (of $numkits)\"
292echo \" \"
293cat /dev/null >kit${kitnum}isdone
294run=''
295config=''
296for iskit in$rangelist; do
297 if test -f kit\${iskit}isdone; then
298 run=\"\$run \$iskit\"
299 else
300 todo=\"\$todo \$iskit\"
301 fi
302done
303case \$todo in
304 '')
305 echo \"You have run all your kits.\"
306EOM
307 if (defined %Chopped) { # Some splitting occurred
308 print KIT <<EOM;
309 if test -f $PACKNOTES; then
310 sh $PACKNOTES
311 else
312 echo \"You have to rebuild split files by hand (see $PACKLIST).\"
313 fi
314EOM
315 }
316 if (-f "README" && -f "Configure") {
317 print KIT
318" echo \"Please read README and then type Configure.\"
319 chmod 755 Configure\n";
320 } elsif (-f "README") {
321 print KIT
322" echo \"Please read README first.\"\n";
323 } elsif (-f "Configure") {
324 print KIT
325" echo \"Please run Configure first.\"
326 chmod 755 Configure\n";
327 }
328 print KIT <<EOM;
329 rm -f kit*isdone
330 ;;
331 *) echo \"You have run\$run.\"
332 echo \"You still need to run\$todo.\"
333 ;;
334esac
335: Someone might mail this, so exit before signature...
336exit 0
337EOM
338}
339
340sub get_patchlevel {
341 $patch_level = '';
342 if (-f 'patchlevel.h') {
343 open(PL, 'patchlevel.h');
344 while (<PL>) {
345 /^#define\s+PATCHLEVEL\s+(\w+)/ && ($patch_level = $1);
346 }
347 close PL;
348 }
349}
350
351sub distfake {
352 return if $opt_q;
353 local($sw);
354 $sw = 's' unless $opt_v;
355 mkdir($tmpdir, 0700) || die "Can't create directory $tmpdir.\n";
356 print "Building a copy of distribution in $tmpdir...\n" if $opt_v;
357 system 'perl', '-S', 'patcol', "-a$sw", '-f', $NEWMANI, '-d', $tmpdir;
358 system 'cp', $NEWMANI, "$tmpdir/$NEWMANI"
359 unless -f "$tmpdir/$NEWMANI" && !$opt_f;
360}
361
362sub distcopy {
363 local($sw); # Switch to force patcol to copy checked out files
364 &makedir($opt_c);
365 print "Building a copy of distribution in $opt_c...\n" if $opt_v;
366 $sw = 'c' if $opt_q;
367 $sw .= 's' unless $opt_v;
368 system 'perl', '-S', 'patcol', "-aRC$sw", '-f', $NEWMANI, '-d', $opt_c;
369}
370
371sub distrm {
372 return if $opt_q;
373 print "Removing distribution in $tmpdir...\n" if $opt_v;
374 chdir "/"; # Do not stay in removed directory...
375 system '/bin/rm', '-rf', "$tmpdir";
376}
377
378sub splitrm {
379 foreach $base (keys %Chopped) {
380 print "Removing split files for $base:\n" if $opt_v;
381 $piece = 'AA';
382 while (-f "$base:$piece") {
383 print "\t$base:$piece\n" if $opt_v;
384 unlink "$base:$piece";
385 $piece++; # AA -> AB, etc...
386 }
387 }
388}
389
390sub cleanup {
391 &distrm if -d $tmpdir;
392 if ($opt_q) {
393 &splitrm; # Remove in-place split files
394 unlink $PACKLIST, $PACKNOTES;
395 }
396}
397
398sub fatal {
399 local($reason) = shift(@_);
400 &cleanup;
401 die "$reason\n";
402}
403
404sub set_sig {
405 local($handler) = @_;
406 $SIG{'HUP'} = $handler;
407 $SIG{'INT'} = $handler;
408 $SIG{'QUIT'} = $handler;
409 $SIG{'TERM'} = $handler;
410}
411
412sub aborted {
413 &set_sig('IGNORE');
414 $opt_v = 1; # Force verbose message in distrm
415 &cleanup;
416 print "Aborted.\n";
417 exit 1;
418}
419
420sub usage {
421 print STDERR <<EOM;
422Usage: makedist [-dhqvV] [-c dir] [-s size] [-f manifest]
423 -c : copy files in dir, do not build any shell archive.
424 -d : debug mode.
425 -f : use this file as manifest.
426 -h : print this help message and exits.
427 -q : quick mode: use checked-out files.
428 -s : set maximum pack size.
429 -v : verbose mode.
430 -V : print version number and exits.
431EOM
432 exit 1;
433}
434
435sub readpackage {
436 if (! -f '.package') {
437 if (
438 -f '../.package' ||
439 -f '../../.package' ||
440 -f '../../../.package' ||
441 -f '../../../../.package'
442 ) {
443 die "Run in top level directory only.\n";
444 } else {
445 die "No .package file! Run packinit.\n";
446 }
447 }
448 open(PACKAGE,'.package');
449 while (<PACKAGE>) {
450 next if /^:/;
451 next if /^#/;
452 if (($var,$val) = /^\s*(\w+)=(.*)/) {
453 $val = "\"$val\"" unless $val =~ /^['"]/;
454 eval "\$$var = $val;";
455 }
456 }
457 close PACKAGE;
458}
459
460sub manifake {
461 # make MANIFEST and MANIFEST.new say the same thing
462 if (! -f $NEWMANI) {
463 if (-f $MANI) {
464 open(IN,$MANI) || die "Can't open $MANI";
465 open(OUT,">$NEWMANI") || die "Can't create $NEWMANI";
466 while (<IN>) {
467 if (/---/) {
468 # Everything until now was a header...
469 close OUT;
470 open(OUT,">$NEWMANI") ||
471 die "Can't recreate $NEWMANI";
472 next;
473 }
474 s/^\s*(\S+\s+)[0-9]*\s*(.*)/$1$2/;
475 print OUT;
476 print OUT "\n" unless /\n$/; # If no description
477 }
478 close IN;
479 close OUT;
480 }
481 else {
482die "You need to make a $NEWMANI file, with names and descriptions.\n";
483 }
484 }
485}
486
487package copyright;
488
489# Read in copyright file
490sub init {
491 local($file) = @_; # Copyright file
492 undef @copyright;
493 open(COPYRIGHT, $file) || die "Can't open $file: $!\n";
494 chop(@copyright = <COPYRIGHT>);
495 close COPYRIGHT;
496}
497
498# Reset the automaton for a new file.
499sub reset {
500 $copyright_seen = @copyright ? 0 : 1;
501 $marker_seen = 0;
502}
503
504# Filter file, line by line, and expand the copyright string. The @COPYRIGHT@
505# symbol may be preceded by some random comment. A leader can be defined and
506# will be pre-pended to all the input lines.
507sub filter {
508 local($line, $leader) = @_; # Leader is optional
509 return $leader . $line if $copyright_seen || $marker_seen;
510 $marker_seen = 1 if $line =~ /\$Log[:\$]/;
511 $copyright_seen = 1 if $line =~ /\@COPYRIGHT\@/;
512 return $leader . $line unless $copyright_seen;
513 local($comment, $trailer) = $line =~ /^(.*)\@COPYRIGHT\@\s*(.*)/;
514 $comment = $leader . $comment;
515 $comment . join("\n$comment", @copyright) . "\n";
516}
517
518# Filter output of $cmd redirected into $file by expanding copyright, if any.
519sub expand {
520 local($cmd, $file) = @_;
521 if (@copyright) {
522 open(CMD,"$cmd|") || die "Can't start '$cmd': $!\n";
523 open(OUT, ">$file") || die "Can't create $file: $!\n";
524 &reset;
525 local($_);
526 while (<CMD>) {
527 print OUT &filter($_);
528 }
529 close OUT;
530 close CMD;
531 } else {
532 system "$cmd > $file";
533 die "Command '$cmd' failed!" if $?;
534 }
535}
536
537package main;
538
539# Make directories for files
540# E.g, for /usr/lib/perl/foo, it will check for all the
541# directories /usr, /usr/lib, /usr/lib/perl and make
542# them if they do not exist.
543sub makedir {
544 local($_) = shift;
545 local($dir) = $_;
546 if (!-d && $_ ne '') {
547 # Make dirname first
548 do makedir($_) if s|(.*)/.*|\1|;
549 mkdir($dir, 0700) if ! -d $dir;
550 }
551}
552
553# Perform ~name expansion ala ksh...
554# (banish csh from your vocabulary ;-)
555sub tilda_expand {
556 local($path) = @_;
557 return $path unless $path =~ /^~/;
558 $path =~ s:^~([^/]+):(getpwnam($1))[$[+7]:e; # ~name
559 $path =~ s:^~:$ENV{'HOME'} || (getpwuid($<))[$[+7]:e; # ~
560 $path;
561}
562
563# Set up profile components into %Profile, add any profile-supplied options
564# into @ARGV and return the command invocation name.
565sub profile {
566 local($profile) = &tilda_expand($ENV{'DIST'} || '~/.dist_profile');
567 local($me) = $0; # Command name
568 $me =~ s|.*/(.*)|$1|; # Keep only base name
569 return $me unless -s $profile;
570 local(*PROFILE); # Local file descriptor
571 local($options) = ''; # Options we get back from profile
572 unless (open(PROFILE, $profile)) {
573 warn "$me: cannot open $profile: $!\n";
574 return;
575 }
576 local($_);
577 local($component);
578 while (<PROFILE>) {
579 next if /^\s*#/; # Skip comments
580 next unless /^$me/o;
581 if (s/^$me://o) { # progname: options
582 chop;
583 $options .= $_; # Merge options if more than one line
584 }
585 elsif (s/^$me-([^:]+)://o) { # progname-component: value
586 $component = $1;
587 chop;
588 s/^\s+//; # Trim leading and trailing spaces
589 s/\s+$//;
590 $Profile{$component} = $_;
591 }
592 }
593 close PROFILE;
594 return unless $options;
595 require 'shellwords.pl';
596 local(@opts);
597 eval '@opts = &shellwords($options)'; # Protect against mismatched quotes
598 unshift(@ARGV, @opts);
599 return $me; # Return our invocation name
600}
601