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.
This commit is contained in:
Christian Kellner 2020-02-18 09:34:35 +01:00 committed by Tom Gundersen
parent 25b3807a5b
commit 0874b80734

View file

@ -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: