abtest.py: support bisection based on a response file

Also makes LINK_TEST customizable from commandline with `--test` option.
This commit is contained in:
Yuanfang Chen 2021-04-08 09:43:08 -07:00
parent f08a2fc09e
commit bcb8ef2d5a
1 changed files with 53 additions and 11 deletions

View File

@ -7,6 +7,10 @@
# list of files which should be linked together and result tested. "link_test"
# should returns with exitcode 0 if the linking and testing succeeded.
#
# If a response file is provided, only the object files that are listed in the
# file are inspected. In addition, the "link_test" is called with a temporary
# response file representing one iteration of bisection.
#
# abtest.py operates by taking all files from the "before" directory and
# in each step replacing one of them with a file from the "bad" directory.
#
@ -41,9 +45,10 @@ import filecmp
import os
import subprocess
import sys
import tempfile
LINKTEST = "./link_test"
# Specify LINKTEST via `--test`. Default value is './link_test'.
LINKTEST = ""
ESCAPE = "\033[%sm"
BOLD = ESCAPE % "1"
RED = ESCAPE % "31"
@ -234,22 +239,42 @@ def testrun(files):
return True
def prepare_files(gooddir, baddir):
files_a = find(gooddir, "*")
files_b = find(baddir, "*")
def prepare_files(gooddir, baddir, rspfile):
files_a = []
files_b = []
basenames_a = set(map(os.path.basename, files_a))
basenames_b = set(map(os.path.basename, files_b))
if rspfile is not None:
def get_basename(name):
# remove prefix
if name.startswith(gooddir):
return name[len(gooddir):]
if name.startswith(baddir):
return name[len(baddir):]
assert False, ""
with open(rspfile, "r") as rf:
for line in rf.read().splitlines():
for obj in line.split():
assert not os.path.isabs(obj), "TODO: support abs path"
files_a.append(gooddir + "/" + obj)
files_b.append(baddir + "/" + obj)
else:
get_basename = lambda name: os.path.basename(name)
files_a = find(gooddir, "*")
files_b = find(baddir, "*")
basenames_a = set(map(get_basename, files_a))
basenames_b = set(map(get_basename, files_b))
for name in files_b:
basename = os.path.basename(name)
basename = get_basename(name)
if basename not in basenames_a:
warn("There is no corresponding file to '%s' in %s" %
(name, gooddir))
choices = []
skipped = []
for name in files_a:
basename = os.path.basename(name)
basename = get_basename(name)
if basename not in basenames_b:
warn("There is no corresponding file to '%s' in %s" %
(name, baddir))
@ -271,13 +296,25 @@ def prepare_files(gooddir, baddir):
# Note that we iterate over files_a so we don't change the order
# (cannot use `picks` as it is a dictionary without order)
for x in files_a:
basename = os.path.basename(x)
basename = get_basename(x)
picked = picks.get(basename)
if picked is None:
assert basename in skipped
files.append(x)
else:
files.append(picked)
# If response file is used, create a temporary response file for the
# picked files.
if rspfile is not None:
with tempfile.NamedTemporaryFile('w', suffix='.rsp',
delete=False) as tf:
tf.write(" ".join(files))
tf.flush()
ret = testrun([tf.name])
os.remove(tf.name)
return ret
return testrun(files)
return perform_test, choices
@ -332,6 +369,8 @@ def main():
parser = argparse.ArgumentParser()
parser.add_argument('--a', dest='dir_a', default='before')
parser.add_argument('--b', dest='dir_b', default='after')
parser.add_argument('--rsp', default=None)
parser.add_argument('--test', default='./link_test')
parser.add_argument('--insane', help='Skip sanity check',
action='store_true')
parser.add_argument('--seq',
@ -342,6 +381,9 @@ def main():
gooddir = config.dir_a
baddir = config.dir_b
rspfile = config.rsp
global LINKTEST
LINKTEST = config.test
# Preparation phase: Creates a dictionary mapping names to a list of two
# choices each. The bisection algorithm will pick one choice for each name
@ -352,7 +394,7 @@ def main():
perform_test, choices = prepare_functions(config.file, gooddir,
goodfile, badfile)
else:
perform_test, choices = prepare_files(gooddir, baddir)
perform_test, choices = prepare_files(gooddir, baddir, rspfile)
info("%d bisection choices" % len(choices))