tools/mpp: support search dirs for manifests

Add support for additional paths that are searched when trying to
load a manifest. Currently only the path of the manifest that has
the include is searched. With this changed additional directories
will be included after that, in the order they were given ton the
command line.
This commit is contained in:
Christian Kellner 2021-06-20 11:51:33 +00:00 committed by Tom Gundersen
parent 2230dfe566
commit ec68369daf

View file

@ -99,6 +99,7 @@ The parameters for this pre-processor, version "2", look like this:
import argparse import argparse
import contextlib
import json import json
import os import os
import sys import sys
@ -258,8 +259,13 @@ class ManifestFile:
@staticmethod @staticmethod
def load(path): def load(path):
with open(path) as f: with open(path) as f:
# We use OrderedDict to preserve key order (for python < 3.6) return ManifestFile.load_from_fd(f, path)
data = json.load(f, object_pairs_hook=collections.OrderedDict)
@staticmethod
def load_from_fd(f, path):
# We use OrderedDict to preserve key order (for python < 3.6)
data = json.load(f, object_pairs_hook=collections.OrderedDict)
version = int(data.get("version", "1")) version = int(data.get("version", "1"))
if version == 1: if version == 1:
return ManifestFileV1(path, data) return ManifestFileV1(path, data)
@ -275,12 +281,21 @@ class ManifestFile:
self.sources = element_enter(self.root, "sources", {}) self.sources = element_enter(self.root, "sources", {})
self.source_urls = {} self.source_urls = {}
def load_import(self, path): def load_import(self, path, search_dirs):
m = ManifestFile.load(self.basedir.joinpath(path)) m = self.find_and_load_manifest(path, search_dirs)
if m.version != self.version: if m.version != self.version:
raise ValueError(f"Incompatible manifest version {m.version}") raise ValueError(f"Incompatible manifest version {m.version}")
return m return m
def find_and_load_manifest(self, path, dirs):
for p in [self.basedir] + dirs:
with contextlib.suppress(FileNotFoundError):
fullpath = os.path.join(p, path)
with open(fullpath, "r") as f:
return ManifestFile.load_from_fd(f, path)
raise FileNotFoundError(f"Could not find manifest '{path}'")
def add_packages(self, deps): def add_packages(self, deps):
checksums = [] checksums = []
@ -314,13 +329,13 @@ class ManifestFileV1(ManifestFile):
files = element_enter(self.sources, "org.osbuild.files", {}) files = element_enter(self.sources, "org.osbuild.files", {})
self.source_urls = element_enter(files, "urls", {}) self.source_urls = element_enter(files, "urls", {})
def _process_import(self, build): def _process_import(self, build, search_dirs):
mpp = build.get("mpp-import-pipeline") mpp = build.get("mpp-import-pipeline")
if not mpp: if not mpp:
return return
path = mpp["path"] path = mpp["path"]
imp = self.load_import(path) imp = self.load_import(path, search_dirs)
# We only support importing manifests with URL sources. Other sources are # We only support importing manifests with URL sources. Other sources are
# not supported, yet. This can be extended in the future, but we should # not supported, yet. This can be extended in the future, but we should
@ -343,10 +358,10 @@ class ManifestFileV1(ManifestFile):
build["pipeline"] = imp.pipeline build["pipeline"] = imp.pipeline
del(build["mpp-import-pipeline"]) del(build["mpp-import-pipeline"])
def process_imports(self): def process_imports(self, search_dirs):
current = self.root current = self.root
while current: while current:
self._process_import(current) self._process_import(current, search_dirs)
current = current.get("pipeline", {}).get("build") current = current.get("pipeline", {}).get("build")
def _process_depsolve(self, stage): def _process_depsolve(self, stage):
@ -395,13 +410,13 @@ class ManifestFileV2(ManifestFile):
raise ValueError(f"Pipeline '{name}' not found in {self.path}") raise ValueError(f"Pipeline '{name}' not found in {self.path}")
def _process_import(self, pipeline): def _process_import(self, pipeline, search_dirs):
mpp = pipeline.get("mpp-import-pipeline") mpp = pipeline.get("mpp-import-pipeline")
if not mpp: if not mpp:
return return
path = mpp["path"] path = mpp["path"]
imp = self.load_import(path) imp = self.load_import(path, search_dirs)
for source, desc in imp.sources.items(): for source, desc in imp.sources.items():
target = self.sources.get(source) target = self.sources.get(source)
@ -421,9 +436,9 @@ class ManifestFileV2(ManifestFile):
target = imp.get_pipeline_by_name(mpp["id"]) target = imp.get_pipeline_by_name(mpp["id"])
pipeline.update(target) pipeline.update(target)
def process_imports(self): def process_imports(self, search_dirs):
for pipeline in self.pipelines: for pipeline in self.pipelines:
self._process_import(pipeline) self._process_import(pipeline, search_dirs)
def _process_depsolve(self, stage): def _process_depsolve(self, stage):
if stage.get("type", "") != "org.osbuild.rpm": if stage.get("type", "") != "org.osbuild.rpm":
@ -462,6 +477,13 @@ if __name__ == "__main__":
default=None, default=None,
help="Path to DNF cache-directory to use", help="Path to DNF cache-directory to use",
) )
parser.add_argument(
"-I,--import-dir",
dest="searchdirs",
default=[],
action="append",
help="Search for import in that directory",
)
parser.add_argument( parser.add_argument(
"--sort-keys", "--sort-keys",
dest="sort_keys", dest="sort_keys",
@ -486,7 +508,7 @@ if __name__ == "__main__":
m = ManifestFile.load(args.src) m = ManifestFile.load(args.src)
# First resolve all imports # First resolve all imports
m.process_imports() m.process_imports(args.searchdirs)
m.process_depsolves() m.process_depsolves()