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/
This commit is contained in:
parent
e516bf7898
commit
b31c91d671
4 changed files with 19 additions and 8 deletions
|
|
@ -318,12 +318,13 @@ def load_pipeline(description: Dict, index: Index, manifest: Manifest, source_re
|
||||||
name = description["name"]
|
name = description["name"]
|
||||||
build = description.get("build")
|
build = description.get("build")
|
||||||
runner = description.get("runner")
|
runner = description.get("runner")
|
||||||
|
source_epoch = description.get("source-epoch")
|
||||||
|
|
||||||
if build and build.startswith("name:"):
|
if build and build.startswith("name:"):
|
||||||
target = resolve_ref(build, manifest)
|
target = resolve_ref(build, manifest)
|
||||||
build = target
|
build = target
|
||||||
|
|
||||||
pl = manifest.add_pipeline(name, runner, build)
|
pl = manifest.add_pipeline(name, runner, build, source_epoch)
|
||||||
|
|
||||||
for desc in description.get("stages", []):
|
for desc in description.get("stages", []):
|
||||||
load_stage(desc, index, pl, manifest, source_refs)
|
load_stage(desc, index, pl, manifest, source_refs)
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,13 @@ class BuildResult:
|
||||||
|
|
||||||
|
|
||||||
class Stage:
|
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.info = info
|
||||||
self.sources = source_options
|
self.sources = source_options
|
||||||
self.build = build
|
self.build = build
|
||||||
self.base = base
|
self.base = base
|
||||||
self.options = options
|
self.options = options
|
||||||
|
self.source_epoch = source_epoch
|
||||||
self.checkpoint = False
|
self.checkpoint = False
|
||||||
self.inputs = {}
|
self.inputs = {}
|
||||||
self.devices = {}
|
self.devices = {}
|
||||||
|
|
@ -59,6 +60,8 @@ class Stage:
|
||||||
m.update(json.dumps(self.build, sort_keys=True).encode())
|
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.base, sort_keys=True).encode())
|
||||||
m.update(json.dumps(self.options, 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:
|
if self.inputs:
|
||||||
data = {n: i.id for n, i in self.inputs.items()}
|
data = {n: i.id for n, i in self.inputs.items()}
|
||||||
m.update(json.dumps(data, sort_keys=True).encode())
|
m.update(json.dumps(data, sort_keys=True).encode())
|
||||||
|
|
@ -193,22 +196,28 @@ class Stage:
|
||||||
rls = remoteloop.LoopServer()
|
rls = remoteloop.LoopServer()
|
||||||
build_root.register_api(rls)
|
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}"],
|
r = build_root.run([f"/run/osbuild/bin/{self.name}"],
|
||||||
monitor,
|
monitor,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
binds=binds,
|
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)
|
return BuildResult(self, r.returncode, r.output, api.metadata, api.error)
|
||||||
|
|
||||||
|
|
||||||
class Pipeline:
|
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.name = name
|
||||||
self.build = build
|
self.build = build
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
self.stages = []
|
self.stages = []
|
||||||
self.assembler = None
|
self.assembler = None
|
||||||
|
self.source_epoch = source_epoch
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
|
|
@ -227,7 +236,7 @@ class Pipeline:
|
||||||
|
|
||||||
def add_stage(self, info, options, sources_options=None):
|
def add_stage(self, info, options, sources_options=None):
|
||||||
stage = Stage(info, sources_options, self.build,
|
stage = Stage(info, sources_options, self.build,
|
||||||
self.id, options or {})
|
self.id, options or {}, self.source_epoch)
|
||||||
self.stages.append(stage)
|
self.stages.append(stage)
|
||||||
if self.assembler:
|
if self.assembler:
|
||||||
self.assembler.base = stage.id
|
self.assembler.base = stage.id
|
||||||
|
|
@ -341,8 +350,8 @@ class Manifest:
|
||||||
self.pipelines = collections.OrderedDict()
|
self.pipelines = collections.OrderedDict()
|
||||||
self.sources: List[Source] = []
|
self.sources: List[Source] = []
|
||||||
|
|
||||||
def add_pipeline(self, name: str, runner: str, build: str) -> Pipeline:
|
def add_pipeline(self, name: str, runner: str, build: str, source_epoch: Optional[int] = None) -> Pipeline:
|
||||||
pipeline = Pipeline(name, runner, build)
|
pipeline = Pipeline(name, runner, build, source_epoch)
|
||||||
if name in self.pipelines:
|
if name in self.pipelines:
|
||||||
raise ValueError(f"Name {name} already exists")
|
raise ValueError(f"Name {name} already exists")
|
||||||
self.pipelines[name] = pipeline
|
self.pipelines[name] = pipeline
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@
|
||||||
"name": { "type:": "string" },
|
"name": { "type:": "string" },
|
||||||
"build": { "type": "string" },
|
"build": { "type": "string" },
|
||||||
"runner": { "type": "string" },
|
"runner": { "type": "string" },
|
||||||
|
"source-epoch": { "type": "integer" },
|
||||||
"stages": { "$ref": "#/definitions/stages" }
|
"stages": { "$ref": "#/definitions/stages" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class TestDescriptions(unittest.TestCase):
|
||||||
def test_stage_run(self):
|
def test_stage_run(self):
|
||||||
index = osbuild.meta.Index(os.curdir)
|
index = osbuild.meta.Index(os.curdir)
|
||||||
info = index.get_module_info("Stage", "org.osbuild.noop")
|
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:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue