From b31c91d671495169580d80e31d58d8909cdabda8 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 4 Feb 2022 15:51:48 +0100 Subject: [PATCH] v2: Add source-epoch key in pipeline declaration and pass to buildroot If this is set it is passed down to all stages and set as SOURCE_DATE_EPOCH in the buildroot environment. This implements the spec at: https://reproducible-builds.org/docs/source-date-epoch/ --- osbuild/formats/v2.py | 3 ++- osbuild/pipeline.py | 21 +++++++++++++++------ schemas/osbuild2.json | 1 + test/mod/test_osbuild.py | 2 +- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/osbuild/formats/v2.py b/osbuild/formats/v2.py index 4b168b39..824a19f0 100644 --- a/osbuild/formats/v2.py +++ b/osbuild/formats/v2.py @@ -318,12 +318,13 @@ def load_pipeline(description: Dict, index: Index, manifest: Manifest, source_re name = description["name"] build = description.get("build") runner = description.get("runner") + source_epoch = description.get("source-epoch") if build and build.startswith("name:"): target = resolve_ref(build, manifest) build = target - pl = manifest.add_pipeline(name, runner, build) + pl = manifest.add_pipeline(name, runner, build, source_epoch) for desc in description.get("stages", []): load_stage(desc, index, pl, manifest, source_refs) diff --git a/osbuild/pipeline.py b/osbuild/pipeline.py index e54cc0da..4eeb9044 100644 --- a/osbuild/pipeline.py +++ b/osbuild/pipeline.py @@ -37,12 +37,13 @@ class BuildResult: class Stage: - def __init__(self, info, source_options, build, base, options): + def __init__(self, info, source_options, build, base, options, source_epoch): self.info = info self.sources = source_options self.build = build self.base = base self.options = options + self.source_epoch = source_epoch self.checkpoint = False self.inputs = {} self.devices = {} @@ -59,6 +60,8 @@ class Stage: m.update(json.dumps(self.build, sort_keys=True).encode()) m.update(json.dumps(self.base, sort_keys=True).encode()) m.update(json.dumps(self.options, sort_keys=True).encode()) + if self.source_epoch is not None: + m.update(json.dumps(self.source_epoch, sort_keys=True).encode()) if self.inputs: data = {n: i.id for n, i in self.inputs.items()} m.update(json.dumps(data, sort_keys=True).encode()) @@ -193,22 +196,28 @@ class Stage: rls = remoteloop.LoopServer() build_root.register_api(rls) + extra_env = {} + if self.source_epoch is not None: + extra_env["SOURCE_DATE_EPOCH"] = str(self.source_epoch) + r = build_root.run([f"/run/osbuild/bin/{self.name}"], monitor, timeout=timeout, binds=binds, - readonly_binds=ro_binds) + readonly_binds=ro_binds, + extra_env=extra_env) return BuildResult(self, r.returncode, r.output, api.metadata, api.error) class Pipeline: - def __init__(self, name: str, runner=None, build=None): + def __init__(self, name: str, runner=None, build=None, source_epoch=None): self.name = name self.build = build self.runner = runner self.stages = [] self.assembler = None + self.source_epoch = source_epoch @property def id(self): @@ -227,7 +236,7 @@ class Pipeline: def add_stage(self, info, options, sources_options=None): stage = Stage(info, sources_options, self.build, - self.id, options or {}) + self.id, options or {}, self.source_epoch) self.stages.append(stage) if self.assembler: self.assembler.base = stage.id @@ -341,8 +350,8 @@ class Manifest: self.pipelines = collections.OrderedDict() self.sources: List[Source] = [] - def add_pipeline(self, name: str, runner: str, build: str) -> Pipeline: - pipeline = Pipeline(name, runner, build) + def add_pipeline(self, name: str, runner: str, build: str, source_epoch: Optional[int] = None) -> Pipeline: + pipeline = Pipeline(name, runner, build, source_epoch) if name in self.pipelines: raise ValueError(f"Name {name} already exists") self.pipelines[name] = pipeline diff --git a/schemas/osbuild2.json b/schemas/osbuild2.json index f08996c0..d9f0d535 100644 --- a/schemas/osbuild2.json +++ b/schemas/osbuild2.json @@ -104,6 +104,7 @@ "name": { "type:": "string" }, "build": { "type": "string" }, "runner": { "type": "string" }, + "source-epoch": { "type": "integer" }, "stages": { "$ref": "#/definitions/stages" } } }, diff --git a/test/mod/test_osbuild.py b/test/mod/test_osbuild.py index 86243240..1eaa3899 100644 --- a/test/mod/test_osbuild.py +++ b/test/mod/test_osbuild.py @@ -35,7 +35,7 @@ class TestDescriptions(unittest.TestCase): def test_stage_run(self): index = osbuild.meta.Index(os.curdir) info = index.get_module_info("Stage", "org.osbuild.noop") - stage = osbuild.Stage(info, {}, None, None, {}) + stage = osbuild.Stage(info, {}, None, None, {}, None) with tempfile.TemporaryDirectory() as tmpdir: