#! /usr/bin/env perl use Getopt::Long qw(:config bundling no_ignore_case); use POSIX; use strict; use warnings; my $help = 0; GetOptions ("h|help" => \$help); usage () if $help; die "$0: exactly one or two nonoption arguments are required\n" if @ARGV != 1 && @ARGV != 2; my $builder = `hostname`; chomp $builder; # Select build number. my $build_number = POSIX::strftime("%Y%m%d%H%M%S", localtime); # Create build directory. my $builddir = "builds/$build_number"; mkdir "builds" or die "builds: mkdir: $!\n" if ! -d "builds"; mkdir $builddir or die "$builddir: mkdir: $!\n"; our $resultsdir = "$builddir/results"; mkdir $resultsdir or die "$resultsdir: mkdir: $!\n"; mkdir "$resultsdir/vars" or die "$resultsdir/vars: mkdir: $!\n"; my $logfile = "$resultsdir/LOG"; open (LOG, '>', $logfile) or die "creating $logfile failed: $!\n"; set_var ("builder", $builder); set_var ("build_number", $build_number); sub start_step { my ($msg) = @_; print LOG " \n$msg\n"; print "$msg\n"; } sub set_var { my ($var, $value) = @_; open (VAR, '>', "$resultsdir/vars/$var") or die "creating $resultsdir/$var failed: $!\n"; print VAR "$value\n"; close VAR; print LOG "$var=$value\n"; print "\t$var=$value\n"; } my $tarball; if (@ARGV == 2) { my ($repo, $branch) = @ARGV; # Fetch branch start_step ("Fetch $repo, branch $branch"); run ("git fetch $repo +$branch:buildtmp/$$/pspp"); # Get revision number. my $revision = `git rev-parse buildtmp/$$/pspp`; chomp $revision; set_var ("pspp_commit", $revision); my $abbrev_commit = substr ($revision, 0, 6); # Extract source. start_step ("Extract branch into $builddir/pspp$build_number"); run ("git archive --format=tar --prefix=pspp$build_number/ buildtmp/$$/pspp | (cd $builddir && tar xf -)"); # Extract version number. start_step ("Extract version number"); my $trace = `cd $builddir/pspp$build_number && autoconf -t AC_INIT`; chomp $trace; my ($file, $line, $macro, $package, $version, @rest) = split (':', $trace); set_var ("pspp_version", $version); # Append -g012345 to AC_INIT version number. start_step ("Adding -g$abbrev_commit to version number"); my $fullname = "$builddir/pspp$build_number/$file"; open (OLDFILE, '<', $fullname) or die "opening $fullname failed: $!\n"; open (NEWFILE, '>', "$fullname.new") or die "creating $fullname.new failed: $!\n"; while () { if ($. != $line) { print NEWFILE $_; } else { print NEWFILE "AC_INIT([$package], [$version-g$abbrev_commit]"; print NEWFILE ", [$_]" foreach @rest; print NEWFILE ")\n"; } } close (NEWFILE); close (OLDFILE); rename ("$fullname.new", $fullname) or die "rename $fullname.new to $fullname failed: $!\n"; # Add note to beginning of NEWS (otherwise "make dist" fails). start_step ("Updating NEWS"); $fullname = "$builddir/pspp$build_number/NEWS"; open (OLDFILE, '<', $fullname) or die "opening $fullname failed: $!\n"; open (NEWFILE, '>', "$fullname.new") or die "creating $fullname.new failed: $!\n"; my $found_changes = 0; while () { if (!$found_changes && /^Changes/) { $found_changes = 1; print NEWFILE <) { ($gnulib_commit) = /^\s+commit ([0-9a-fA-F]{8,})/ and last; } die "$fullname does not specify a Git commit number\n" if !defined ($gnulib_commit); set_var ("gnulib_commit", $gnulib_commit); # If we don't already have that Gnulib commit, update Gnulib. `git rev-parse $gnulib_commit`; if ($? != 0) { start_step ("Updating Gnulib to obtain commit"); run ("git fetch gnulib"); } # Extract gnulib source. start_step ("Extract Gnulib source"); run ("git archive --format=tar --prefix=gnulib/ $gnulib_commit | (cd $builddir && tar xf -)"); # Bootstrap. start_step ("Bootstrap (make -f Smake)"); run ("cd $builddir/pspp$build_number && make -f Smake"); # Configure. start_step ("Configure source"); run ("cd $builddir/pspp$build_number && mkdir _build && cd _build && ../configure"); # Distribute. start_step ("Make dist tarball"); run ("cd $builddir/pspp$build_number/_build && make dist"); $tarball = "$builddir/pspp$build_number/_build/pspp-$version-g$abbrev_commit.tar.gz"; } else { $tarball = $ARGV[0]; } start_step ("Determining $tarball target directory"); my $sample_filename = `zcat $tarball | tar tf - | head -1`; my ($tarball_dir) = $sample_filename =~ m%^(?:[./])*([^/]+)/%; set_var ("dist_dir", $tarball_dir); start_step ("Extracting $tarball into $builddir/$tarball_dir"); run ("zcat $tarball | (cd $builddir && tar xf -)"); start_step ("Extracting tar version"); my ($version) = `cd $builddir/$tarball_dir && ./configure --version | head -1` =~ /configure (\S+)$/; set_var ("dist_version", $version); my ($binary_version) = "$version-$builder-build$build_number"; set_var ("binary_version", $binary_version); start_step ("Configuring"); run ("chmod -R a-w $builddir/$tarball_dir"); run ("chmod u+w $builddir/$tarball_dir"); run ("mkdir $builddir/$tarball_dir/_build"); run ("chmod a-w $builddir/$tarball_dir"); run ("cd $builddir/$tarball_dir/_build && ../configure --enable-relocatable --prefix=''"); start_step ("Build"); run ("cd $builddir/$tarball_dir/_build && make"); start_step ("Install"); run ("cd $builddir/$tarball_dir/_build && make install DESTDIR=\$PWD/pspp-$binary_version"); start_step ("Make binary distribution"); run ("cd $builddir/$tarball_dir/_build && tar cfz pspp-$binary_version.tar.gz pspp-$binary_version"); start_step ("Check"); run ("cd $builddir/$tarball_dir/_build && make check"); start_step ("Uninstall"); run ("cd $builddir/$tarball_dir/_build && make uninstall DESTDIR=\$PWD/pspp-$binary_version"); start_step ("Check uninstall"); run ("cd $builddir/$tarball_dir/_build && make distuninstallcheck distuninstallcheck_dir=\$PWD/pspp-$binary_version"); # distcleancheck start_step ("Success"); sub usage { print <) { print LOG $_; print "\r", $i++; } close (COMMAND); print "\r \r"; if ($? == 0) { return; } elsif ($? & 127) { printf "%s: child died with signal %d, %s coredump\n", $command, ($? & 127), ($? & 128) ? 'with' : 'without'; } else { printf "%s: child exited with value %d\n", $command, $? >> 8; } exit 1; } # Clone source # Add build number # Tag build # Clone gnulib at correct commit number # Run gnulib-tool. # Run configure # Make dist # Unpack dist # Run configure # Check # Install # Make binary dist # Build mingw32 installer # Other distcheck stuff? # Distribute manual in various formats