diff --git a/swh/fuse/fs/entry.py b/swh/fuse/fs/entry.py --- a/swh/fuse/fs/entry.py +++ b/swh/fuse/fs/entry.py @@ -63,6 +63,14 @@ yield None + async def lookup(self, name: str) -> FuseEntry: + """ Look up a FUSE entry by name """ + + async for entry in self: + if entry.name == name: + return entry + return None + def get_target(self) -> Union[str, bytes, Path]: """ Return the path target of a symlink entry """ diff --git a/swh/fuse/fs/mountpoint.py b/swh/fuse/fs/mountpoint.py --- a/swh/fuse/fs/mountpoint.py +++ b/swh/fuse/fs/mountpoint.py @@ -9,7 +9,8 @@ from swh.fuse.fs.artifact import OBJTYPE_GETTERS from swh.fuse.fs.entry import EntryMode, FuseEntry -from swh.model.identifiers import CONTENT, SWHID +from swh.model.exceptions import ValidationError +from swh.model.identifiers import CONTENT, SWHID, parse_swhid @dataclass @@ -33,18 +34,34 @@ name: str = field(init=False, default="archive") mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) + def create_child(self, swhid: SWHID) -> FuseEntry: + if swhid.object_type == CONTENT: + mode = EntryMode.RDONLY_FILE + else: + mode = EntryMode.RDONLY_DIR + return super().create_child( + OBJTYPE_GETTERS[swhid.object_type], + name=str(swhid), + mode=int(mode), + swhid=swhid, + ) + async def __aiter__(self) -> AsyncIterator[FuseEntry]: async for swhid in self.fuse.cache.get_cached_swhids(): - if swhid.object_type == CONTENT: - mode = EntryMode.RDONLY_FILE - else: - mode = EntryMode.RDONLY_DIR - yield self.create_child( - OBJTYPE_GETTERS[swhid.object_type], - name=str(swhid), - mode=int(mode), - swhid=swhid, - ) + yield self.create_child(swhid) + + async def lookup(self, name: str) -> FuseEntry: + entry = await super().lookup(name) + if entry: + return entry + + # On the fly mounting of a new artifact + try: + swhid = parse_swhid(name) + await self.fuse.get_metadata(swhid) + return self.create_child(swhid) + except ValidationError: + return None @dataclass diff --git a/swh/fuse/fuse.py b/swh/fuse/fuse.py --- a/swh/fuse/fuse.py +++ b/swh/fuse/fuse.py @@ -184,14 +184,12 @@ name = os.fsdecode(name) parent_entry = self.inode2entry(parent_inode) - - async for entry in parent_entry: - if name == entry.name: - attr = await self.get_attrs(entry) - return attr - - logging.error(f"Unknown name during lookup: '{name}'") - raise pyfuse3.FUSEError(errno.ENOENT) + lookup_entry = await parent_entry.lookup(name) + if lookup_entry: + return await self.get_attrs(lookup_entry) + else: + logging.error(f"Unknown name during lookup: '{name}'") + raise pyfuse3.FUSEError(errno.ENOENT) async def readlink(self, inode: int, _ctx: pyfuse3.RequestContext) -> bytes: entry = self.inode2entry(inode)