diff --git a/osbuild/objectstore.py b/osbuild/objectstore.py index 3cdc0992..1002d6ad 100644 --- a/osbuild/objectstore.py +++ b/osbuild/objectstore.py @@ -5,7 +5,7 @@ import os import subprocess import tempfile import uuid -from typing import Optional, Set +from typing import Any, Optional, Set from osbuild.util import jsoncomm, rmrf from osbuild.util.mnt import mount, umount @@ -18,6 +18,17 @@ __all__ = [ ] +class PathAdapter: + """Expose an object attribute as `os.PathLike`""" + + def __init__(self, obj: Any, attr: str) -> None: + self.obj = obj + self.attr = attr + + def __fspath__(self): + return getattr(self.obj, self.attr) + + class Object: class Mode(enum.Enum): READ = 0 @@ -111,6 +122,12 @@ class Object: tree = os.path.join(self._path, "tree") os.makedirs(tree) + # Expose our base path as `os.PathLike` via `PathAdater` + # so any changes to it, e.g. via `store_tree`, will be + # automatically picked up by `Metadata`. + wrapped = PathAdapter(self, "_path") + self._meta = self.Metadata(wrapped, folder="meta") + @property def id(self) -> Optional[str]: return self._id @@ -128,6 +145,10 @@ class Object: def tree(self) -> str: return os.path.join(self._path, "tree") + @property + def meta(self) -> Metadata: + return self._meta + def store_tree(self): """Store the tree with a fresh name and close it diff --git a/osbuild/pipeline.py b/osbuild/pipeline.py index a0bdf923..9c568bbf 100644 --- a/osbuild/pipeline.py +++ b/osbuild/pipeline.py @@ -236,6 +236,9 @@ class Stage: readonly_binds=ro_binds, extra_env=extra_env) + if r.returncode == 0: + tree.meta.set(self.id, api.metadata) + return BuildResult(self, r.returncode, r.output, api.metadata, api.error) diff --git a/test/mod/test_objectstore.py b/test/mod/test_objectstore.py index 4ea3f4aa..e28185ec 100644 --- a/test/mod/test_objectstore.py +++ b/test/mod/test_objectstore.py @@ -254,6 +254,32 @@ class TestObjectStore(unittest.TestCase): md.set("a", data) assert md.get("a") == data + + with objectstore.ObjectStore(self.store) as store: + obj = store.new("a") + p = Path(obj, "A") + p.touch() + + obj.meta.set("md", data) + assert obj.meta.get("md") == data + + store.commit(obj, "x") + obj.meta.set("extra", extra) + assert obj.meta.get("extra") == extra + + store.commit(obj, "a") + + with objectstore.ObjectStore(self.store) as store: + obj = store.get("a") + + assert obj.meta.get("md") == data + assert obj.meta.get("extra") == extra + + ext = store.get("x") + + assert ext.meta.get("md") == data + assert ext.meta.get("extra") is None + def test_host_tree(self): with objectstore.ObjectStore(self.store) as store: host = store.host_tree