do full build, install, check, etc.
[pspp] / build-pspp
1 #! /usr/bin/env perl
2
3 use Getopt::Long qw(:config bundling no_ignore_case);
4 use POSIX;
5
6 use strict;
7 use warnings;
8
9 my $help = 0;
10 GetOptions ("h|help" => \$help);
11
12 usage () if $help;
13
14 die "$0: exactly one or two nonoption arguments are required\n"
15   if @ARGV != 1 && @ARGV != 2;
16
17 my $builder = `hostname`;
18 chomp $builder;
19
20 # Select build number.
21 my $buildnumber = POSIX::strftime("%Y%m%d%H%M%S", localtime);
22 print "\tBUILDNUMBER=$buildnumber\n";
23
24 # Create build directory.
25 my $builddir = "builds/$buildnumber";
26 print "Create $builddir\n";
27 mkdir "builds" or die "builds: mkdir: $!\n" if ! -d "builds";
28 mkdir $builddir or die "$builddir: mkdir: $!\n";
29
30 $resultsdir = "$builddir/results";
31 mkdir $resultsdir or die "$resultsdir: mkdir: $!\n";
32
33 $logfile = "$resultsdir/LOG";
34 open (LOG, '>', $logfile) or die "creating $logfile failed: $!\n";
35
36 $varsfile = "$resultsdir/VARS";
37 open (VARS, '>', $varsfile) or die "creating $varsfile failed: $!\n";
38
39
40
41
42
43 my $tarball;
44 if (@ARGV == 2) {
45     my ($repo, $branch) = @ARGV;
46
47     # Fetch branch
48     print "Fetch $repo, branch $branch\n";
49     run ("git fetch $repo +$branch:buildtmp/$$/pspp");
50
51     # Get revision number.
52     my $revision = `git rev-parse buildtmp/$$/pspp`;
53     chomp $revision;
54     print "\tREVISION=$revision\n";
55     my $abbrev_revision = substr ($revision, 0, 6);
56
57     # Extract source.
58     print "Extract branch into $builddir/pspp$buildnumber\n";
59     run ("git archive --format=tar --prefix=pspp$buildnumber/ buildtmp/$$/pspp | (cd $builddir && tar xf -)");
60
61     # Extract version number.
62     print "Extract version number\n";
63     my $trace = `cd $builddir/pspp$buildnumber && autoconf -t AC_INIT`;
64     chomp $trace;
65     my ($file, $line, $macro, $package, $version, @rest) = split (':', $trace);
66     print "\tVERSION=$version\n";
67
68     # Append -g012345 to AC_INIT version number.
69     my $fullname = "$builddir/pspp$buildnumber/$file";
70     open (OLDFILE, '<', $fullname)
71       or die "opening $fullname failed: $!\n";
72     open (NEWFILE, '>', "$fullname.new")
73       or die "creating $fullname.new failed: $!\n";
74     while (<OLDFILE>) {
75         if ($. != $line) {
76             print NEWFILE $_;
77         } else {
78             print NEWFILE "AC_INIT([$package], [$version-g$abbrev_revision]";
79             print NEWFILE ", [$_]" foreach @rest;
80             print NEWFILE ")\n";
81         }
82     }
83     close (NEWFILE);
84     close (OLDFILE);
85     rename ("$fullname.new", $fullname)
86       or die "rename $fullname.new to $fullname failed: $!\n";
87
88     # Add note to beginning of NEWS (otherwise "make dist" fails).
89     $fullname = "$builddir/pspp$buildnumber/NEWS";
90     open (OLDFILE, '<', $fullname)
91       or die "opening $fullname failed: $!\n";
92     open (NEWFILE, '>', "$fullname.new")
93       or die "creating $fullname.new failed: $!\n";
94     my $found_changes = 0;
95     while (<OLDFILE>) {
96         if (!$found_changes && /^Changes/) {
97             $found_changes = 1;
98             print NEWFILE <<EOF;
99 Changes from $version to $version-g$abbrev_revision:
100
101  * Built automatically from commit $revision
102    in branch $branch by builder $builder
103
104 EOF
105         }
106         print NEWFILE $_;
107     }
108     close (NEWFILE);
109     close (OLDFILE);
110     rename ("$fullname.new", $fullname)
111       or die "rename $fullname.new to $fullname failed: $!\n";
112
113     # Get Gnulib commit number.
114     my $gnulib_commit;
115     $fullname = "$builddir/pspp$buildnumber/README.Git";
116     open (README_GIT, '<', $fullname)
117       or die "opening $fullname failed: $!\n";
118     while (<README_GIT>) {
119         ($gnulib_commit) = /^\s+commit ([0-9a-fA-F]{8,})/ and last;
120     }
121     die "$fullname does not specify a Git commit number\n"
122       if !defined ($gnulib_commit);
123     print "\tGNULIB_REVISION=$gnulib_commit\n";
124
125     # If we don't already have that Gnulib commit, update Gnulib.
126     `git rev-parse $gnulib_commit`;
127     if ($? != 0) {
128         run ("git fetch gnulib");
129     }
130
131     # Extract gnulib source.
132     run ("git archive --format=tar --prefix=gnulib/ $gnulib_commit | (cd $builddir && tar xf -)");
133
134     # Bootstrap.
135     run ("cd $builddir/pspp$buildnumber && make -f Smake");
136
137     # Configure.
138     run ("cd $builddir/pspp$buildnumber && mkdir _build && cd _build && ../configure");
139
140     # Distribute.
141     run ("cd $builddir/pspp$buildnumber/_build && make dist");
142
143     $tarball = "$builddir/pspp$buildnumber/_build/pspp-$version-g$abbrev_revision.tar.gz";
144 } else {
145     $tarball = $ARGV[0];
146 }
147
148 print "Determining $tarball target directory\n";
149 my $sample_filename = `zcat $tarball | tar tf - | head -1`;
150 my ($tarball_dir) = $sample_filename =~ m%^(?:[./])*([^/]+)/%;
151 print "\tTARBALL_DIR=$tarball_dir\n";
152
153 print "Extracting $tarball into $builddir/$tarball_dir\n";
154 run ("zcat $tarball | (cd $builddir && tar xf -)");
155
156 print "Extracting tar version\n";
157 my ($version) = `cd $builddir/$tarball_dir && ./configure --version | head -1`
158   =~ /configure (\S+)$/;
159 print "\tVERSION=$version\n";
160 my ($binary_version) = "$version-$builder-build$buildnumber";
161 print "\tBINARY_VERSION=$version\n";
162
163 print "Configuring\n";
164 run ("chmod -R a-w $builddir/$tarball_dir");
165 run ("chmod u+w $builddir/$tarball_dir");
166 run ("mkdir $builddir/$tarball_dir/_build");
167 run ("chmod a-w $builddir/$tarball_dir");
168 run ("cd $builddir/$tarball_dir/_build && ../configure --enable-relocatable --prefix=''");
169
170 print "Build\n";
171 run ("cd $builddir/$tarball_dir/_build && make");
172
173 print "Install\n";
174 run ("cd $builddir/$tarball_dir/_build && make install DESTDIR=\$PWD/pspp-$binary_version");
175
176 print "Make binary distribution\n";
177 run ("cd $builddir/$tarball_dir/_build && tar cfz pspp-$binary_version.tar.gz pspp-$binary_version");
178
179 print "Check\n";
180 run ("cd $builddir/$tarball_dir/_build && make check");
181
182 print "Uninstall\n";
183 run ("cd $builddir/$tarball_dir/_build && make uninstall DESTDIR=\$PWD/pspp-$binary_version");
184
185 print "Check uninstall\n";
186 run ("cd $builddir/$tarball_dir/_build && make distuninstallcheck distuninstallcheck_dir=\$PWD/pspp-$binary_version");
187
188 # distcleancheck
189
190 print "Success\n";
191
192 sub usage {
193     print <<EOF;
194 $0, for building and testing PSPP
195 usage: $0 [OPTIONS] [TARBALL | REPO REFSPEC]
196 where TARBALL is the name of a tarball produced by "make dist"
197    or REPO and REFSPEC are a Git repo and refspec (e.g. branch) to clone.
198
199 Options:
200   --help            Print this usage message and exit
201 EOF
202     exit(0);
203 }
204
205 sub run {
206     my ($command) = @_;
207     return if system ($command) == 0;
208     if ($? == -1) {
209         print "$command: failed to execute: $!\n";
210     } elsif ($? & 127) {
211         printf "%s: child died with signal %d, %s coredump\n",
212           $command, ($? & 127),  ($? & 128) ? 'with' : 'without';
213     } else {
214         printf "%s: child exited with value %d\n", $command, $? >> 8;
215     }
216     exit 1;
217 }
218
219 # Clone source
220 # Add build number
221 # Tag build
222 # Clone gnulib at correct commit number
223 # Run gnulib-tool.
224 # Run configure
225 # Make dist
226
227 # Unpack dist
228 # Run configure
229 # Check
230 # Install
231 # Make binary dist
232 # Build mingw32 installer
233 # Other distcheck stuff?
234
235 # Distribute manual in various formats