[reprotest] 02/03: Fix the time variation to actually make the time constant
Ximin Luo
infinity0 at debian.org
Mon Nov 27 12:03:43 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 acff508a633305a3f36f6d187d3a48ce38b4e578
Author: Ximin Luo <infinity0 at debian.org>
Date: Mon Nov 27 13:01:42 2017 +0100
Fix the time variation to actually make the time constant
---
README.rst | 15 ++++++------
debian/changelog | 2 ++
reprotest/__init__.py | 10 +++++---
reprotest/build.py | 68 +++++++++++++++++++++++++--------------------------
4 files changed, 49 insertions(+), 46 deletions(-)
diff --git a/README.rst b/README.rst
index 2bdac3b..d428814 100644
--- a/README.rst
+++ b/README.rst
@@ -247,14 +247,13 @@ user_group.available
a $user, with no $group variation.
time.faketimes
A semicolon-separated ordered set, specifying possible ``faketime(1)`` time
- descriptors to use. Default is empty.
-time.auto_faketimes
- A semicolon-separated ordered set, specifying a list of "magic" values
- which will be resolved into additional values for time.faketimes. Default
- is "SOURCE_DATE_EPOCH", possible values are:
-
- SOURCE_DATE_EPOCH
- Use the latest file modification time found in the source_root.
+ descriptors to use. Default is empty, in which case we randomly choose a
+ time: either now (if the latest file-modtime in ``source_root`` is older
+ than about half-a-year) or more than half-a-year in the future.
+
+ Note that the clock continues to run during the build. It is possible for
+ ``faketime(1)`` to freeze it, but we don't yet support that yet; it has a
+ higher chance of causing your build to fail or misbehave.
The difference between --vary and --variations is that the former appends onto
previous values but the latter resets them. Furthermore, the last value set for
diff --git a/debian/changelog b/debian/changelog
index 962139e..408603e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -4,6 +4,8 @@ reprotest (0.7.4) UNRELEASED; urgency=medium
* Add aslr, domain_host, and num_cpu variations.
* Add a --print-sudoers feature.
* Properly drop privs when running the build. (Closes: #877813)
+ * Fix the time variation to actually make the time constant. This drops the
+ time.auto_faketimes variation-spec option.
-- Ximin Luo <infinity0 at debian.org> Fri, 20 Oct 2017 12:33:21 +0200
diff --git a/reprotest/__init__.py b/reprotest/__init__.py
index 0065e18..f88ce8d 100644
--- a/reprotest/__init__.py
+++ b/reprotest/__init__.py
@@ -314,7 +314,6 @@ class TestArgs(collections.namedtuple('_Test',
raise ValueError("already built '%s'" % name)
names_seen.add(name)
- var = var.replace.spec.apply_dynamic_defaults(source_root)
bctx = BuildContext(testbed.scratch, result_dir, source_root, name, var)
build = bctx.make_build_commands(build_command, os.environ)
@@ -772,7 +771,12 @@ def run(argv, dry_run=None):
if parsed_args.min_cpus is None:
logger.warn("The control build runs on 1 CPU by default, give --min-cpus to increase this.")
min_cpus = parsed_args.min_cpus or 1
- build_variations = Variations.of(*specs, verbosity=verbosity, min_cpus=min_cpus)
+ build_variations = Variations.of(
+ *specs,
+ verbosity=verbosity,
+ min_cpus=min_cpus,
+ # TODO: make this configurable via command line
+ base_faketime='@%d' % build.auto_source_date_epoch(source_root))
# Warn about missing programs
if virtual_server_args[0] == "null" and not dry_run:
@@ -819,6 +823,6 @@ def main():
r = run(sys.argv[1:])
if not isinstance(r, int):
import pprint
- pprint.pprint(r, width=40, compact=True)
+ pprint.pprint(r, width=80, compact=True)
else:
return r
diff --git a/reprotest/build.py b/reprotest/build.py
index e260af1..30af6d9 100644
--- a/reprotest/build.py
+++ b/reprotest/build.py
@@ -356,20 +356,27 @@ def timezone(ctx, build, vary):
@tool_required("faketime")
def faketime(ctx, build, vary):
if not vary:
- # FIXME: this does not actually fix the time, it just lets the system clock run normally
- return build
- lastmt = random.choice(ctx.spec.time.faketimes)
- now = time.time()
- # FIXME: better way of choosing which faketime to use
- if lastmt.startswith("@") and int(lastmt[1:]) < now - 32253180:
- # if lastmt is far in the past, use that, it's a bit safer
- faket = lastmt
+ # fix the time at base_faketime
+ faket = ctx.base_faketime
+ elif ctx.spec.time.faketimes:
+ faket = random.choice(ctx.spec.time.faketimes)
else:
- # otherwise use a date far in the future
- faket = '+373days+7hours+13minutes'
+ now = time.time()
+ base = int(ctx.base_faketime[1:]) if ctx.base_faketime.startswith("@") else now
+ # 15552000 = 180 days
+ if base < now - 15552000 and not random.randint(0, 1):
+ # if ctx.base_faketime is far in the past, with 1/2 probability
+ # reuse the current time and don't fake it
+ return build
+ else:
+ # otherwise use a date far in the future
+ faket = '+%sdays+%shours+%sminutes' % (
+ random.randint(180, 540), random.randint(0, 23), random.randint(0, 59))
+
# faketime's manpages are stupidly misleading; it also modifies file timestamps.
# this is only mentioned in the README. we do not want this, it really really
# messes with GNU make and other buildsystems that look at timestamps.
+ # set NO_FAKE_STAT=1 avoids this.
return build.add_env('NO_FAKE_STAT', '1').prepend_to_build_command('faketime', faket)
def umask(ctx, build, vary):
@@ -459,6 +466,7 @@ VARIATIONS = collections.OrderedDict([
# but also as close to the build command as possible, (i.e. earlier in this list)
# otherwise other variations below can affect the address layout
('num_cpus', num_cpus),
+ ('time', faketime), # needs to go before sudo (user_group), closer to the build command
('user_group', user_group),
('fileordering', fileordering),
('domain_host', domain_host), # needs to run after all other mounts have been set
@@ -467,12 +475,22 @@ VARIATIONS = collections.OrderedDict([
# ('namespace', namespace),
('exec_path', exec_path),
# ('shell', shell),
- ('time', faketime),
('timezone', timezone),
('umask', umask),
])
+def auto_source_date_epoch(source_root):
+ # Get the latest modification date of all the files in the source root.
+ # This tries hard to avoid bad interactions with faketime and make(1) etc.
+ # However if you're building this too soon after changing one of the source
+ # files then the effect of this variation is not very great.
+ filemtimes = (os.lstat(os.path.join(root, f)).st_mtime
+ for root, dirs, files in os.walk(source_root)
+ for f in files)
+ return int(max(filemtimes, default=1))
+
+
class TimeVariation(collections.namedtuple('_TimeVariation', 'faketimes auto_faketimes')):
@classmethod
def default(cls):
@@ -482,20 +500,6 @@ class TimeVariation(collections.namedtuple('_TimeVariation', 'faketimes auto_fak
def empty(cls):
return cls(mdiffconf.strlist_set(";"), mdiffconf.strlist_set(";"))
- def apply_dynamic_defaults(self, source_root):
- new_faketimes = []
- for a in self.auto_faketimes:
- if a == "SOURCE_DATE_EPOCH":
- # Get the latest modification date of all the files in the source root.
- # This tries hard to avoid bad interactions with faketime and make(1) etc.
- # However if you're building this too soon after changing one of the source
- # files then the effect of this variation is not very great.
- filemtimes = (os.lstat(os.path.join(root, f)).st_mtime for root, dirs, files in os.walk(source_root) for f in files)
- new_faketimes.append("@%d" % int(max(filemtimes, default=0)))
- else:
- raise ValueError("unrecognized auto_faketime: %s" % a)
- return self.empty()._replace(faketimes=self.faketimes + new_faketimes)
-
class EnvironmentVariation(collections.namedtuple("_EnvironmentVariation", "variables")):
@classmethod
@@ -559,17 +563,11 @@ class VariationSpec(mdiffconf.ImmutableNamespace):
def actions(self):
return [(k, k in self.__dict__, v) for k, v in VARIATIONS.items()]
- def apply_dynamic_defaults(self, source_root):
- return self.__class__(**{
- k: v.apply_dynamic_defaults(source_root) if hasattr(v, "apply_dynamic_defaults") else v
- for k, v in self.__dict__.items()
- })
-
-class Variations(collections.namedtuple('_Variations', 'spec verbosity min_cpus')):
+class Variations(collections.namedtuple('_Variations', 'spec verbosity min_cpus base_faketime')):
@classmethod
- def of(cls, *specs, zero=VariationSpec.empty(), verbosity=0, min_cpus=1):
- return [cls(spec, verbosity, min_cpus) for spec in [zero] + list(specs)]
+ def of(cls, *specs, zero=VariationSpec.empty(), verbosity=0, min_cpus=1, base_faketime="@0"):
+ return [cls(spec, verbosity, min_cpus, base_faketime) for spec in [zero] + list(specs)]
@property
def replace(self):
@@ -635,4 +633,4 @@ if __name__ == "__main__":
d = d.extend([s])
print(s)
print(">>>", d)
- print("result", d.apply_dynamic_defaults("."))
+ print("result", d)
--
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