[reprotest] 03/04: main: Add a --auto-build option to determine which variations cause unreproducibility
Ximin Luo
infinity0 at debian.org
Fri Sep 22 16:31:42 UTC 2017
This is an automated email from the git hooks/post-receive script.
infinity0 pushed a commit to branch master
in repository reprotest.
commit fd4a0532af4ead6a85313aa74ae23fae077af25b
Author: Ximin Luo <infinity0 at debian.org>
Date: Fri Sep 22 17:59:13 2017 +0200
main: Add a --auto-build option to determine which variations cause unreproducibility
---
debian/changelog | 8 ++++++
reprotest/__init__.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++++---
reprotest/build.py | 7 ++++++
setup.py | 2 +-
4 files changed, 81 insertions(+), 5 deletions(-)
diff --git a/debian/changelog b/debian/changelog
index eccf426..7735988 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+reprotest (0.7.1) UNRELEASED; urgency=medium
+
+ * Add a --auto-build option to try to determine which specific variations
+ cause unreproducibility.
+ * Fix varying both umask and user_group at the same time.
+
+ -- Ximin Luo <infinity0 at debian.org> Fri, 22 Sep 2017 17:57:31 +0200
+
reprotest (0.7) unstable; urgency=medium
[ Ximin Luo ]
diff --git a/reprotest/__init__.py b/reprotest/__init__.py
index f4bce48..d73171f 100644
--- a/reprotest/__init__.py
+++ b/reprotest/__init__.py
@@ -8,6 +8,7 @@ import contextlib
import logging
import os
import pathlib
+import random
import re
import shutil
import subprocess
@@ -297,6 +298,56 @@ def check(build_command, source_root, artifact_pattern, store_dir=None, no_clean
return retcode
+def check_auto(build_command, source_root, artifact_pattern, store_dir=None, no_clean_on_error=False,
+ virtual_server_args=[], testbed_pre=None, testbed_init=None, host_distro='debian',
+ build_variations=Variations.of(VariationSpec.default()), diffoscope_args=[]):
+ # default argument [] is safe here because we never mutate it.
+ with empty_or_temp_dir(store_dir, "store_dir") as result_dir:
+ assert store_dir == result_dir or store_dir is None
+ proc = corun_builds(
+ build_command, source_root, artifact_pattern, result_dir, no_clean_on_error,
+ virtual_server_args, testbed_pre, testbed_init, host_distro)
+
+ var_x0, var_x1 = build_variations
+ dist_x0 = proc.send(("control", var_x0))
+
+ def is_reproducible(name, var):
+ dist_test = proc.send(("experiment-%s" % name, var))
+ # TODO: handle exit codes > 1 correctly, raise a CalledProcessError
+ retcode = run_diff(dist_x0, dist_test, diffoscope_args, store_dir)
+ if retcode == 0:
+ return True
+ elif retcode == 1:
+ return False
+ else:
+ raise RuntimeError("diffoscope exited non-boolean %s, can't continue" % retcode)
+
+ if not is_reproducible("0", var_x0):
+ print("Not reproducible, even when fixing as much as reprotest knows how to. :(")
+ return 1
+
+ if is_reproducible("1", var_x1):
+ print("Reproducible, even when varying as much as reprotest knows how to! :)")
+ return 0
+
+ var_cur = var_x0
+ unreproducibles = []
+
+ varnames = VariationSpec.all_names()
+ random.shuffle(varnames)
+ for v in varnames:
+ var_test = var_cur._replace(spec=var_cur.spec._replace(**{v: var_x1.spec[v]}))
+ if is_reproducible(v, var_test):
+ # vary it for the next test as well, it's OK to vary it
+ var_cur = var_test
+ else:
+ # don't vary it for the next test, continue testing other variations
+ unreproducibles.append(v)
+ print("Observed unreproducibility when varying each of the following:")
+ print(" ".join(unreproducibles))
+ print("The build is probably reproducible when varying other things.")
+
+
def config_to_args(parser, filename):
if not filename:
return []
@@ -398,11 +449,17 @@ def cli_parser():
help='Like --variations, but appends to previous --vary values '
'instead of overwriting them. Furthermore, the last value set for '
'--variations is treated implicitly as the zeroth --vary value.')
- group1.add_argument('--extra-build', metavar='VARIATIONS', default=[], action='append',
+ group1_0 = group1.add_mutually_exclusive_group()
+ group1_0.add_argument('--extra-build', metavar='VARIATIONS', default=[], action='append',
help='Perform another build with the given VARIATIONS (which may be '
'empty) to be applied on top of what was given for --variations and '
'--vary. Each occurence of this flag specifies another build, so e.g. '
'given twice this will make reprotest perform 4 builds in total.')
+ group1_0.add_argument('--auto-build', default=False, action='store_true',
+ help='Automatically perform builds to try to determine which specific '
+ 'variations cause unreproducibility, potentially up to and including '
+ 'the ones specified by --variations and --vary. Conflicts with '
+ '--extra-build.')
# TODO: remove after reprotest 0.8
group1.add_argument('--dont-vary', default=[], action='append', help=argparse.SUPPRESS)
@@ -551,8 +608,12 @@ def run(argv, check):
variations += ["-%s" % a for x in parsed_args.dont_vary for a in x.split(",")]
spec = VariationSpec().extend(variations)
specs = [spec]
- for extra_build in parsed_args.extra_build:
- specs.append(spec.extend(extra_build))
+ if parsed_args.auto_build:
+ check_func = check_auto
+ else:
+ for extra_build in parsed_args.extra_build:
+ specs.append(spec.extend(extra_build))
+ check_func = check
build_variations = Variations.of(*specs, verbosity=verbosity)
# Remaining args
@@ -576,7 +637,7 @@ def run(argv, check):
return check_args
else:
try:
- return check(**check_args)
+ return check_func(**check_args)
except Exception:
traceback.print_exc()
return 125
diff --git a/reprotest/build.py b/reprotest/build.py
index 6571990..71e0618 100644
--- a/reprotest/build.py
+++ b/reprotest/build.py
@@ -404,11 +404,18 @@ class VariationSpec(mdiffconf.ImmutableNamespace):
def empty(cls):
return cls()
+ @classmethod
+ def all_names(cls):
+ return list(VARIATIONS.keys())
+
aliases = { ("@+-", "all"): list(VARIATIONS.keys()) }
def extend(self, actions):
one = self.default()
return mdiffconf.parse_all(self, actions, one, one, self.aliases, sep=",")
+ def __getitem__(self, k):
+ return self.__dict__[k]
+
def actions(self):
return [(k, k in self.__dict__, v) for k, v in VARIATIONS.items()]
diff --git a/setup.py b/setup.py
index 5d2ca66..9dece1e 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
from setuptools import setup, find_packages
setup(name='reprotest',
- version='0.7',
+ version='0.7.1',
description='Build packages and check them for reproducibility.',
long_description=open('README.rst', encoding='utf-8').read(),
author='Ceridwen',
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/reprotest.git
More information about the Reproducible-commits
mailing list