osbuild-mpp: Allow use of mpp-* operations for stages
This mergest the handling of process_stages() and process_format() into
just one process_format(), which incrementally tracks the call stack
of the formating, which allows it to detect when it is hitting a stage
and can call _process_stage().
This means it is possible to mix things like mpp-if and mpp-join with
stages.
For example, you can do complex combinations like:
pipelines:
- name: rootfs
stages:
mpp-join:
- - type: org.ostree.foo
- mpp-if: use_bar
then:
type: org.osbuild.bar
- mpp-if: use_extra_stages
then:
mpp-eval: extra_stages
This is particularly useful if you included something and you want
to mpp-join something that was set in a variable.
This commit is contained in:
parent
ed99aa4bfa
commit
fc2697927a
1 changed files with 37 additions and 26 deletions
|
|
@ -959,6 +959,7 @@ class ManifestFile:
|
|||
self.version = version
|
||||
self.sources = element_enter(self.root, "sources", {})
|
||||
self.source_urls = {}
|
||||
self.format_stack = []
|
||||
self.solver_factory = None
|
||||
|
||||
self.vars = default_vars.copy()
|
||||
|
|
@ -1098,6 +1099,18 @@ class ManifestFile:
|
|||
else:
|
||||
return fakeroot[0], False
|
||||
|
||||
def _format_dict_node(self, node, stack):
|
||||
if len(stack) > 0:
|
||||
parent_node = stack[-1][0]
|
||||
parent_key = stack[-1][1]
|
||||
else:
|
||||
parent_node = None
|
||||
parent_key = None
|
||||
|
||||
if parent_key == "stages":
|
||||
pipeline_name = self.get_pipeline_name(parent_node)
|
||||
self._process_stage(node, pipeline_name)
|
||||
|
||||
def _process_format(self, node):
|
||||
def _is_format(node):
|
||||
if not isinstance(node, dict):
|
||||
|
|
@ -1162,7 +1175,11 @@ class ManifestFile:
|
|||
return res, False
|
||||
|
||||
if isinstance(node, dict):
|
||||
|
||||
self._format_dict_node(node, self.format_stack)
|
||||
|
||||
for key in list(node.keys()):
|
||||
self.format_stack.append( (node, key) )
|
||||
value = node[key]
|
||||
if _is_format(value):
|
||||
val, remove = _eval_format(value, self.get_vars())
|
||||
|
|
@ -1172,6 +1189,8 @@ class ManifestFile:
|
|||
node[key] = val
|
||||
else:
|
||||
self._process_format(value)
|
||||
self.format_stack.pop()
|
||||
|
||||
if isinstance(node, list):
|
||||
to_remove = []
|
||||
for i, value in enumerate(node):
|
||||
|
|
@ -1200,6 +1219,9 @@ class ManifestFile:
|
|||
name = desc.get("id", "image")
|
||||
self.vars[name] = Image.from_dict(desc)
|
||||
|
||||
def get_pipeline_name(self, node):
|
||||
return node.get("name", "unknown")
|
||||
|
||||
def _process_stage(self, stage, pipeline_name):
|
||||
self._process_depsolve(stage, pipeline_name)
|
||||
self._process_embed_files(stage)
|
||||
|
|
@ -1270,24 +1292,22 @@ class ManifestFileV1(ManifestFile):
|
|||
|
||||
packages += checksums
|
||||
|
||||
def process_stages(self, pipeline=None, depth=0):
|
||||
if pipeline is None:
|
||||
pipeline = self.pipeline
|
||||
def get_pipeline_name(self, node):
|
||||
if self.pipeline == node:
|
||||
return "stages"
|
||||
|
||||
if depth == 0:
|
||||
pipeline_name = "stages"
|
||||
elif depth == 1:
|
||||
pipeline_name = "build"
|
||||
else:
|
||||
pipeline_name = "build" + str(depth)
|
||||
build = self.pipeline.get("build", {}).get("pipeline")
|
||||
if build == node:
|
||||
return "build"
|
||||
|
||||
stages = element_enter(pipeline, "stages", [])
|
||||
for stage in stages:
|
||||
self._process_stage(stage, pipeline_name)
|
||||
build = pipeline.get("build")
|
||||
if build:
|
||||
if "pipeline" in build:
|
||||
self.process_stages(build["pipeline"], depth+1)
|
||||
depth = 1
|
||||
while build:
|
||||
build = build.get("build", {}).get("pipeline")
|
||||
depth = depth + 1
|
||||
if build == node:
|
||||
return "build" + str(depth)
|
||||
|
||||
return "unknown"
|
||||
|
||||
def _process_embed_files(self, stage):
|
||||
"Embedding files is not supported for v1 manifests"
|
||||
|
|
@ -1374,13 +1394,6 @@ class ManifestFileV2(ManifestFile):
|
|||
for checksum in checksums:
|
||||
refs[checksum] = {}
|
||||
|
||||
def process_stages(self):
|
||||
for pipeline in self.pipelines:
|
||||
name = pipeline.get("name", "")
|
||||
stages = element_enter(pipeline, "stages", [])
|
||||
for stage in stages:
|
||||
self._process_stage(stage, name)
|
||||
|
||||
def _process_embed_files(self, stage):
|
||||
|
||||
class Embedded(collections.namedtuple("Embedded", ["id", "checksum"])):
|
||||
|
|
@ -1547,11 +1560,9 @@ def main():
|
|||
|
||||
with tempfile.TemporaryDirectory() as persistdir:
|
||||
m.solver_factory = DepSolverFactory(args.cachedir, persistdir)
|
||||
m.process_stages()
|
||||
m.process_format()
|
||||
m.solver_factory = None
|
||||
|
||||
m.process_format()
|
||||
|
||||
with sys.stdout if args.dst == "-" else open(args.dst, "w") as f:
|
||||
m.write(f, args.sort_keys)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue