+def print_usage():
+ print("""\
+%s, for building and testing PSPP
+usage: %s [OPTIONS] [TARBALL | REPO REFSPEC]
+where TARBALL is the name of a tarball produced by "make dist"
+ or REPO and REFSPEC are a Git repo and refspec (e.g. branch) to clone.
+
+Options:
+ --help Print this usage message and exit
+ --ssw=TARBALL Get ssw from TARBALL instead of from Git.
+ --no-binary Build source tarballs but no binaries.
+ --batch Do not print progress to stdout.
+ --no-perl Do not build Perl module."""
+ % (sys.argv[0], sys.argv[0]))
+ sys.exit(0)
+
+
+def run(command, id=None):
+ if not try_run(command, id):
+ fail()
+
+
+def try_run(command, id=None):
+ LOG.write("%s\n" % command)
+
+ p = subprocess.Popen(command, shell=True, text=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ start = datetime.now()
+ est_time = 0 if id is None else read_timing(id)
+
+ lines = 0
+ for s in p.stdout:
+ LOG.write(s)
+
+ elapsed = (datetime.now() - start).seconds
+ progress = "%d lines logged, %d s elapsed" % (lines, elapsed)
+ lines += 1
+ if est_time > 0:
+ left = est_time - elapsed
+ if left > 0:
+ progress += ", ETA %d s" % left
+ if not batch:
+ sys.stdout.write("\r%s%s\r"
+ % (progress, " " * (79 - len(progress))))
+ if not batch:
+ sys.stdout.write("\r%s\r" % (' ' * 79))
+
+ if id is not None:
+ write_timing(id, (datetime.now() - start).seconds)
+
+ rc = p.wait()
+ if rc == 0:
+ return True
+
+ if rc < 0:
+ sys.stderr.write("%s: child died with signal %d\n" % (command, -rc))
+ else:
+ sys.stderr.write("%s: child exited with value %d\n" % (command, rc))
+ return False
+
+
+def read_timing(id):
+ try:
+ for s in open("%s/timings" % topdir):
+ m = re.match('([^=]+)=(.*)', s.rstrip())
+ if m:
+ key, value = m.groups()
+ if key == id:
+ try:
+ return int(value)
+ except ValueError:
+ return 0
+ return 0
+ except FileNotFoundError:
+ return 0
+
+
+def write_timing(id, time):
+ tmpname = "%s/timings.tmp%d" % (topdir, os.getpid())
+ NEWTIMINGS = open(tmpname, 'w')
+ try:
+ OLDTIMINGS = open("%s/timings" % topdir, "r")
+ for s in OLDTIMINGS:
+ m = re.match('([^=]+)=(.*)', s.rstrip())
+ if m:
+ key, value = m.groups()
+ if key == id:
+ continue
+ NEWTIMINGS.write(s)
+ except FileNotFoundError:
+ pass
+ NEWTIMINGS.write("%s=%s\n" % (id, time))
+ NEWTIMINGS.close()
+ os.rename(tmpname, "%s/timings" % topdir)
+
+
+def fail():
+ set_var("result", "failure")
+ sys.stderr.write("Build failed, refer to:\n\t%s\nfor details.\n" % logfile)
+ sys.exit(1)
+
+
+def start_step(msg):
+ LOG.write("\f\n%s\n" % msg)
+ if not batch:
+ print(msg)
+
+
+def set_var(var, value):
+ VARS.write("%s=%s\n" % (var, value))
+ if not batch:
+ print("\t%s=%s" % (var, value))
+
+ VAR = open("%s/vars/%s" % (resultsdir, var), "wt")
+ VAR.write("%s\n" % value)
+ VAR.close()
+
+
+def saved_result(name, product):
+ start_step("Saving %s: %s" % (name, product))
+
+
+def save_result(name, src, rm_src=False):
+ basename = os.path.basename(src)
+ dst = "%s/%s" % (resultsdir, basename)
+
+ saved_result(name, basename)
+ run("cp -R %s %s" % (src, dst))
+
+ if rm_src:
+ run("rm %s" % src)
+
+ return dst
+
+
+def save_result_if_exists(name, src, rm_src=False):
+ if Path(src).exists():
+ save_result(name, src, rm_src)
+ else:
+ start_step("%s does not exist, cannot save" % src)
+
+
+def ref_to_commit(ref, repo='.'):
+ return backquotes("cd %s && %s rev-parse %s" % (repo, GIT, ref))
+
+
+def add_commit_to_version(name, commit, dir, extra_news = None):
+ abbrev_commit = commit[:6]
+
+ # Extract version number.
+ start_step("Extract %s repository version number" % name)
+ fields = backquotes("cd %s && autoconf -t AC_INIT" % dir).split(':')
+ file, line, macro, package, repo_version = fields[:5]
+ rest = fields[5:]
+ set_var("%s_repo_version" % name, repo_version)
+
+ # Is this a "gnits" mode tree?
+ start_step("Checking %s Automake mode" % name)
+
+ am_mode = "gnu"
+ for s in open("%s/Makefile.am" % dir):
+ if "gnits" in s:
+ am_mode = "gnits"
+ break
+ LOG.write("%s Automake mode is %s\n" % (name, am_mode))
+
+ # Generate version number for build.
+ # We want to append -g012345, but if we're in Gnits mode and the
+ # version number already has a hyphen, we have to omit it.
+ start_step("Generate %s build version number" % name)
+ version = repo_version
+ if '-' not in version:
+ version += '-'
+ version += 'g' + abbrev_commit
+ set_var("%s_version" % name, version)
+
+ # Append -g012345 to configure.ac version number.
+ start_step("Updating %s version number in %s" % (name, file))
+ fullname = "%s/%s" % (dir, file)
+ NEWFILE = open("%s.new" % fullname, "w")
+ ln = 1
+ for s in open(fullname):
+ if ln != int(line):
+ NEWFILE.write(s)
+ else:
+ NEWFILE.write("AC_INIT([%s], [%s]" % (package, version))
+ for field in rest:
+ NEWFILE.write(", [%s]" % field)
+ NEWFILE.write(")\n")
+ ln += 1
+ NEWFILE.close()
+ os.rename("%s.new" % fullname, fullname)
+
+ # Add note to beginning of NEWS (otherwise "make dist" fails).
+ start_step("Updating %s NEWS" % name)
+ fullname = "%s/NEWS" % name
+ NEWFILE = open("%s.new" % fullname, "w")
+ found_changes = False
+ for s in open(fullname):
+ if not found_changes and (s.startswith('Changes') or repo_version in s):
+ found_changes = True
+ NEWFILE.write("""\
+Changes from %(repo_version)s to %(version)s:
+
+ * Built from PSPP commit %(revision)s
+ in branch %(branch)s on builder %(builder)s.
+
+"""
+ % {'repo_version': repo_version,
+ 'version': version,
+ 'revision': commit,
+ 'branch': branch,
+ 'builder': builder})
+ if extra_news:
+ NEWFILE.write(extra_news)
+ NEWFILE.write('\n')
+
+ NEWFILE.write(s)
+ NEWFILE.close()
+ os.rename("%s.new" % fullname, fullname)
+
+ return version
+
+try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:], "ho:",
+ ["help",
+ "binary", "no-binary",
+ "batch", "no-batch",
+ "no-perl",
+ "output=",
+ "ssw=",
+ "builder=", "build-number="])
+except getopt.GetoptError as err:
+ # print help information and exit:
+ print(err) # will print something like "option -a not recognized"
+ sys.exit(1)
+
+build_binary = True
+batch = not os.isatty(1)
+builddir = None
+build_number = None
+builder = None
+build_perl = True
+ssw = "https://git.savannah.gnu.org/git/ssw.git master"
+for o, a in opts:
+ if o in ("-h", "--help"):
+ print_usage()
+ elif o == "--binary":
+ build_binary = True
+ elif o == "--no-binary":
+ build_binary = False
+ elif o == "--batch":
+ batch = True
+ elif o == "--no-batch":
+ batch = False
+ elif o in ("-o", "--output"):
+ builddir = a
+ elif o == "--builder":
+ builder = a
+ elif o == "--build-number":
+ build_number = a
+ elif o == "--no-perl":
+ build_perl = False
+ elif o == "--ssw":
+ ssw = a
+ else:
+ assert False, "unhandled option"
+if builder is None:
+ builder = socket.gethostname()
+
+if len(args) not in (1, 2):
+ sys.stderr.write(
+ "%s: exactly one or two nonoption arguments are required\n"
+ % sys.argv[0])
+ sys.exit(1)
+
+if len(args) == 1:
+ tarball = os.path.abspath(args[0])
+else:
+ pass # Tarball will be generated later.