From 0874b807344d9f90250f7873343ef2aa757ed165 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Tue, 18 Feb 2020 09:34:35 +0100 Subject: [PATCH] objectstore: Object knows its base When a new Object is created it can have a `base`, i.e. another object that is already committed to the store, which is then used to initialize the tree of the new object. That is, the contents of the new Object will be based on the contents of the existing. The initialization of an Object with its base (if any) was done by the ObjectStore. Move all of that logic inside `Object`: The Object will store its base, which `Object.init` will use to initialize itself. Additionally, if `Object.path` is accessed `init` is being called as well to make sure it is properly initialized, i.e. the tree initialized with the base content. --- osbuild/objectstore.py | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/osbuild/objectstore.py b/osbuild/objectstore.py index 586a4817..34897531 100644 --- a/osbuild/objectstore.py +++ b/osbuild/objectstore.py @@ -29,19 +29,36 @@ def suppress_oserror(*errnos): class Object: def __init__(self, store: "ObjectStore"): + self._init = True + self._base_path = None self._workdir = None self._tree = None self.store = store self.reset() - def init(self, source: str) -> None: - """Initialize the object with source content""" + def init(self) -> None: + """Initialize the object with content of its base""" + if self._init: + return + + source = self._base_path subprocess.run(["cp", "--reflink=auto", "-a", - f"{source}/.", self.path], + f"{source}/.", self._tree], check=True) + self._init = True + + @property + def base_path(self) -> Optional[str]: + return self._base_path + + @base_path.setter + def base_path(self, path: Optional[str]): + self._init = not path + self._base_path = path @property def path(self) -> str: + self.init() return self._tree @property @@ -78,6 +95,7 @@ class Object: self._workdir = self.store.tempdir(suffix="object") self._tree = os.path.join(self._workdir.name, "tree") os.makedirs(self._tree, mode=0o755, exist_ok=True) + self._init = not self._base_path def cleanup(self): if self._workdir: @@ -147,10 +165,10 @@ class ObjectStore: # on success as object_id if base_id: - # the base, the working tree and the output dir are all - # on the same fs, so attempt a lightweight copy if the - # fs supports it - obj.init(self.resolve_ref(base_id)) + # if we were given a base id, resolve its path and set it + # as the base_path of the object + obj.base_path = self.resolve_ref(base_id) + obj.init() yield obj @@ -174,7 +192,8 @@ class ObjectStore: # the latter with the contents of `obj.path` and commit # it to the store with Object(self) as tmp: - tmp.init(obj.path) + tmp.base_path = obj.path + tmp.init() return self.commit(tmp, object_id) def commit(self, obj: Object, object_id: str) -> str: