Commit 348f5ca4 authored by thomie's avatar thomie

Build system: delete [skip ci]

fingerprint makes no sense anymore w/ submodules.
parent b1063b1b
#! /usr/bin/env python
# Script to create and restore a git fingerprint of the ghc repositories.
from __future__ import print_function
from datetime import datetime
from optparse import OptionParser
import os
import os.path
import re
import subprocess
from subprocess import PIPE, Popen
import sys
def main():
opts, args = parseopts(sys.argv[1:])
def create_action(opts):
"""Action called for the create commmand"""
if opts.fpfile:
fp =
fp = fingerprint(opts.source)
if len(fp) == 0:
error("Got empty fingerprint from source: "+str(opts.source))
if opts.output_file:
print("Writing fingerprint to: ", opts.output_file)
def restore_action(opts):
"""Action called for the restore commmand"""
def branch_name(filename):
return "fingerprint_" + os.path.basename(filename).replace(".", "_")
if opts.fpfile:
fp =
bn = branch_name(opts.fpfile)
except MalformedFingerPrintError:
error("Error parsing fingerprint file: "+opts.fpfile)
if len(fp) == 0:
error("No fingerprint found in fingerprint file: "+opts.fpfile)
elif opts.logfile:
fp = fingerprint(opts.source)
bn = branch_name(opts.logfile)
if len(fp) == 0:
error("No fingerprint found in build log file: "+opts.logfile)
error("Must restore from fingerprint or log file")
restore(fp, branch_name=bn if opts.branch else None)
def fingerprint(source=None):
"""Create a new fingerprint of current repositories.
The source argument is parsed to look for the expected output
from a `sync-all` command. If the source is `None` then the
`sync-all` command will be run to get the current fingerprint.
if source is None:
if sys.platform == 'win32':
# Can't rely on perl being located at `/usr/bin/perl`.
sync_all = ["perl", "./sync-all", "log", "-1", "--pretty=oneline"]
sync_all = ["./sync-all", "log", "-1", "--pretty=oneline"]
source = Popen(sync_all, stdout=PIPE).stdout
lib = ""
commits = {}
for line in source.readlines():
if line.startswith("=="):
lib = line.split()[1].rstrip(":")
lib = "." if lib == "running" else lib # hack for top ghc repo
elif re.match("[abcdef0-9]{40}", line):
commit = line[:40]
commits[lib] = commit
return FingerPrint(commits)
def restore(fp, branch_name=None):
"""Restore the ghc repos to the commits in the fingerprint
This function performs a checkout of each commit specifed in
the fingerprint. If `branch_name` is not None then a new branch
will be created for the top ghc repository. We also add an entry
to the git config that sets the remote for the new branch as `origin`
so that the `sync-all` command can be used from the branch.
checkout = ["git", "checkout"]
# run checkout in all subdirs
for (subdir, commit) in fp:
if subdir != ".":
cmd = checkout + [commit]
print("==", subdir, " ".join(cmd))
if os.path.exists(subdir):
rc =, cwd=subdir)
if rc != 0:
error("Too many errors, aborting")
sys.stderr.write("WARNING: "+
subdir+" is in fingerprint but missing in working directory\n")
# special handling for top ghc repo
# if we are creating a new branch then also add an entry to the
# git config so the sync-all command is happy
branch_args = ["-b", branch_name] if branch_name else []
rc = + branch_args + [fp["."]])
if (rc == 0) and branch_name:
branch_config = "branch."+branch_name+".remote"["git", "config", "--add", branch_config, "origin"])
actions = {"create" : create_action, "restore" : restore_action}
def parseopts(argv):
"""Parse and check the validity of the command line arguments"""
usage = "fingerprint ("+"|".join(sorted(actions.keys()))+") [options]"
parser = OptionParser(usage=usage)
parser.add_option("-d", "--dir", dest="dir",
help="write output to directory DIR", metavar="DIR")
parser.add_option("-o", "--output", dest="output",
help="write output to file FILE", metavar="FILE")
parser.add_option("-l", "--from-log", dest="logfile",
help="reconstruct fingerprint from build log", metavar="FILE")
parser.add_option("-f", "--from-fp", dest="fpfile",
help="reconstruct fingerprint from fingerprint file", metavar="FILE")
parser.add_option("-n", "--no-branch",
action="store_false", dest="branch", default=True,
help="do not create a new branch when restoring fingerprint")
parser.add_option("-g", "--ghc-dir", dest="ghcdir",
help="perform actions in GHC dir", metavar="DIR")
opts,args = parser.parse_args(argv)
return (validate(opts, args, parser), args)
def validate(opts, args, parser):
""" Validate and prepare the command line options.
It performs the following actions:
* Check that we have a valid action to perform
* Check that we have a valid output destination
* Opens the output file if needed
* Opens the input file if needed
# Determine the action
opts.action = actions[args[0]]
except (IndexError, KeyError):
error("Must specify a valid action", parser)
# Inputs
if opts.logfile and opts.fpfile:
error("Must specify only one of -l and -f")
opts.source = None
if opts.logfile:
opts.source = file(opts.logfile, "r")
elif opts.fpfile:
opts.source = file(opts.fpfile, "r")
# Outputs
if opts.dir:
fname = opts.output
if fname is None:
fname ="%Y-%m-%d_%H-%M-%S") + ".fp"
path = os.path.join(opts.dir, fname)
opts.output_file = path
opts.output = file(path, "w")
elif opts.output:
opts.output_file = opts.output
opts.output = file(opts.output_file, "w")
opts.output_file = None
opts.output = sys.stdout
# GHC Directory
# As a last step change the directory to the GHC directory specified
if opts.ghcdir:
return opts
def error(msg="fatal error", parser=None, exit=1):
"""Function that prints error message and exits"""
print("ERROR:", msg)
if parser:
class MalformedFingerPrintError(Exception):
"""Exception raised when parsing a bad fingerprint file"""
class FingerPrint:
"""Class representing a fingerprint of all ghc git repos.
A finger print is represented by a dictionary that maps a
directory to a commit. The directory "." is used for the top
level ghc repository.
def __init__(self, subcommits = {}):
self.commits = subcommits
def __eq__(self, other):
if other.__class__ != self.__class__:
raise TypeError
return self.commits == other.commits
def __neq__(self, other):
not(self == other)
def __hash__(self):
return hash(str(self))
def __len__(self):
return len(self.commits)
def __repr__(self):
return "FingerPrint(" + repr(self.commits) + ")"
def __str__(self):
s = ""
for lib in sorted(self.commits.keys()):
commit = self.commits[lib]
s += "{0}|{1}\n".format(lib, commit)
return s
def __getitem__(self, item):
return self.commits[item]
def __iter__(self):
return self.commits.iteritems()
def write(self, outh):
def read(inh):
"""Read a fingerprint from a fingerprint file"""
commits = {}
for line in inh.readlines():
splits = line.strip().split("|", 1)
if len(splits) != 2:
raise MalformedFingerPrintError(line)
lib, commit = splits
commits[lib] = commit
return FingerPrint(commits)
if __name__ == "__main__":
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment