objectstore: sub-tree support for read_at
Add the ability to only read a sub-tree of a tree via `Object.read_at`.
Expose the functionality via the `Store{Server,Client}.read_tree_at`.
Extend the tests to check this new functionality.
This commit is contained in:
parent
659c139ed1
commit
496d21de54
2 changed files with 38 additions and 5 deletions
|
|
@ -126,11 +126,18 @@ class Object:
|
|||
yield path
|
||||
|
||||
@contextlib.contextmanager
|
||||
def read_at(self, target: PathLike) -> str:
|
||||
def read_at(self, target: PathLike, path: str = "/") -> str:
|
||||
"""Read the object or a part of it at given location
|
||||
|
||||
Map the tree or a part of it specified via `path` at the
|
||||
specified path `target`.
|
||||
"""
|
||||
self._check_writable()
|
||||
self._check_writer()
|
||||
|
||||
mount(self._path, target)
|
||||
path = os.path.join(self._path, path.lstrip("/"))
|
||||
|
||||
mount(path, target)
|
||||
try:
|
||||
self._readers += 1
|
||||
yield target
|
||||
|
|
@ -410,6 +417,7 @@ class StoreServer(api.BaseAPI):
|
|||
def _read_tree_at(self, msg, sock):
|
||||
object_id = msg["object-id"]
|
||||
target = msg["target"]
|
||||
subtree = msg["subtree"]
|
||||
|
||||
obj = self.store.get(object_id)
|
||||
if not obj:
|
||||
|
|
@ -417,7 +425,7 @@ class StoreServer(api.BaseAPI):
|
|||
return
|
||||
|
||||
try:
|
||||
reader = obj.read_at(target)
|
||||
reader = obj.read_at(target, subtree)
|
||||
path = self._stack.enter_context(reader)
|
||||
# pylint: disable=broad-except
|
||||
except Exception as e:
|
||||
|
|
@ -486,11 +494,12 @@ class StoreClient:
|
|||
|
||||
return msg["path"]
|
||||
|
||||
def read_tree_at(self, object_id: str, target: str):
|
||||
def read_tree_at(self, object_id: str, target: str, path="/"):
|
||||
msg = {
|
||||
"method": "read-tree-at",
|
||||
"object-id": object_id,
|
||||
"target": os.fspath(target)
|
||||
"target": os.fspath(target),
|
||||
"subtree": os.fspath(path)
|
||||
}
|
||||
|
||||
self.client.send(msg)
|
||||
|
|
|
|||
|
|
@ -337,10 +337,34 @@ class TestObjectStore(unittest.TestCase):
|
|||
txt = filepath.read_text()
|
||||
assert txt == "osbuild"
|
||||
|
||||
# check we can mount subtrees via `read_tree_at`
|
||||
|
||||
filemount = Path(tmpdir, "file")
|
||||
filemount.touch()
|
||||
|
||||
path = client.read_tree_at("42", filemount, "/file.txt")
|
||||
filepath = Path(path)
|
||||
assert filepath.is_file()
|
||||
txt = filepath.read_text()
|
||||
assert txt == "osbuild"
|
||||
|
||||
dirmount = Path(tmpdir, "dir")
|
||||
dirmount.mkdir()
|
||||
|
||||
path = client.read_tree_at("42", dirmount, "/directory")
|
||||
dirpath = Path(path)
|
||||
assert dirpath.is_dir()
|
||||
|
||||
# check proper exceptions are raised for non existent
|
||||
# mount points and sub-trees
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
nonexistent = os.path.join(tmpdir, "nonexistent")
|
||||
_ = client.read_tree_at("42", nonexistent)
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
_ = client.read_tree_at("42", tmpdir, "/nonexistent")
|
||||
|
||||
# The tree is being read via the client, should
|
||||
# not be able to write to it
|
||||
with self.assertRaises(ValueError):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue