meta: introduce format information

Introdcue a `FormatInfo` class that, very much like `ModuleInfo`
can be used to obtain meta information about a format. Methods
are added to `Index` to allow the enumeration of available formats,
getting the `FormatInfo` for a format given its name and to detect
a format via the manifest description data.

Change the top-level documentation to reflect the changes. Also
remove an outdated section about validation of the schema; this
was moved to the format specific code some time ago.
This commit is contained in:
Christian Kellner 2021-02-05 18:17:53 +00:00
parent 7ffae5669c
commit 7e2c0c7000

View file

@ -12,18 +12,22 @@ information. For the former a `ModuleInfo` class is returned via
the individual stages. Schemata, obtained via `Index.get_schema`
is represented via a `Schema` class that can in turn be used
to validate the individual components.
The high level `validate` function can be used to check a given
manifest (parsed form JSON input in dictionary form) against all
available schemata. The result is a `ValidationResult` which
contains a single `ValidationError` for each error detected in
the manifest. See the individual documentation for details.
Additionally, the `Index` also provides meta information about
the different formats and version that are supported to read
manifest descriptions and write output data. Fir this a class
called `FormatInfo` together with `Index.get_format_inf` and
`Index.list_formats` is provided. A `FormatInfo` can also be
inferred for a specific manifest description via a helper
method called `detect_format_info`
"""
import ast
import contextlib
import copy
import importlib.util
import os
import pkgutil
import json
import sys
from collections import deque
from typing import Iterable, List, Optional
@ -368,18 +372,76 @@ class ModuleInfo:
return mapping.get(klass)
class FormatInfo:
"""Meta information about a format
Class the can be used to get meta information about
the the different formats in which osbuild accepts
manifest descriptions and writes results.
"""
def __init__(self, module):
self.module = module
self.version = getattr(module, "VERSION")
docs = getattr(module, "__doc__")
info, desc = docs.split("\n", 1)
self.info = info.strip()
self.desc = desc.strip()
@classmethod
def load(cls, name):
mod = sys.modules.get(name)
if not mod:
mod = importlib.import_module(name)
if not mod:
raise ValueError(f"Could not load module {name}")
return cls(mod)
class Index:
"""Index of stages and assemblers
"""Index of modules and formats
Class that can be used to get the meta information about
osbuild stages and assemblers as well as JSON schemata.
osbuild modules as well as JSON schemata.
"""
def __init__(self, path: str):
self.path = path
self._module_info = {}
self._format_info = {}
self._schemata = {}
@staticmethod
def list_formats() -> List[str]:
"""List all known formats for manifest descriptions"""
base = "osbuild.formats"
spec = importlib.util.find_spec(base)
locations = spec.submodule_search_locations
modinfo = [
mod for mod in pkgutil.walk_packages(locations)
if not mod.ispkg
]
return [base + "." + m.name for m in modinfo]
def get_format_info(self, name) -> FormatInfo:
"""Get the `FormatInfo` for the format called `name`"""
info = self._format_info.get(name)
if not info:
info = FormatInfo.load(name)
self._format_info[name] = info
return info
def detect_format_info(self, data) -> Optional[FormatInfo]:
"""Obtain a `FormatInfo` for the format that can handle `data`"""
formats = self.list_formats()
version = data.get("version", "1")
for fmt in formats:
info = self.get_format_info(fmt)
if info.version == version:
return info
return None
def list_modules_for_class(self, klass: str) -> List[str]:
"""List all available modules for the given `klass`"""
module_path = ModuleInfo.module_class_to_directory(klass)