Changeset View
Changeset View
Standalone View
Standalone View
swh/fuse/fs/mountpoint.py
# Copyright (C) 2020 The Software Heritage developers | # Copyright (C) 2020 The Software Heritage developers | ||||
# See the AUTHORS file at the top-level directory of this distribution | # See the AUTHORS file at the top-level directory of this distribution | ||||
# License: GNU General Public License version 3, or any later version | # License: GNU General Public License version 3, or any later version | ||||
# See top-level LICENSE file for more information | # See top-level LICENSE file for more information | ||||
from dataclasses import dataclass, field | from dataclasses import dataclass, field | ||||
import json | import json | ||||
from typing import AsyncIterator | from typing import AsyncIterator | ||||
from swh.fuse.fs.artifact import OBJTYPE_GETTERS | from swh.fuse.fs.artifact import OBJTYPE_GETTERS | ||||
from swh.fuse.fs.entry import EntryMode, FuseEntry | from swh.fuse.fs.entry import EntryMode, FuseDirEntry, FuseEntry, FuseFileEntry | ||||
from swh.model.exceptions import ValidationError | from swh.model.exceptions import ValidationError | ||||
from swh.model.identifiers import CONTENT, SWHID, parse_swhid | from swh.model.identifiers import CONTENT, SWHID, parse_swhid | ||||
@dataclass | @dataclass | ||||
class Root(FuseEntry): | class Root(FuseDirEntry): | ||||
""" The FUSE mountpoint, consisting of the archive/ and meta/ directories """ | """ The FUSE mountpoint, consisting of the archive/ and meta/ directories """ | ||||
name: str = field(init=False, default=None) | name: str = field(init=False, default=None) | ||||
mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) | mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) | ||||
depth: int = field(init=False, default=1) | depth: int = field(init=False, default=1) | ||||
async def __aiter__(self) -> AsyncIterator[FuseEntry]: | async def __aiter__(self) -> AsyncIterator[FuseEntry]: | ||||
yield self.create_child(ArchiveDir) | yield self.create_child(ArchiveDir) | ||||
yield self.create_child(MetaDir) | yield self.create_child(MetaDir) | ||||
@dataclass | @dataclass | ||||
class ArchiveDir(FuseEntry): | class ArchiveDir(FuseDirEntry): | ||||
""" The archive/ directory is lazily populated with one entry per accessed | """ The archive/ directory is lazily populated with one entry per accessed | ||||
SWHID, having actual SWHIDs as names """ | SWHID, having actual SWHIDs as names """ | ||||
name: str = field(init=False, default="archive") | name: str = field(init=False, default="archive") | ||||
mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) | mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) | ||||
def create_child(self, swhid: SWHID) -> FuseEntry: | def create_child(self, swhid: SWHID) -> FuseEntry: | ||||
if swhid.object_type == CONTENT: | if swhid.object_type == CONTENT: | ||||
Show All 21 Lines | async def lookup(self, name: str) -> FuseEntry: | ||||
swhid = parse_swhid(name) | swhid = parse_swhid(name) | ||||
await self.fuse.get_metadata(swhid) | await self.fuse.get_metadata(swhid) | ||||
return self.create_child(swhid) | return self.create_child(swhid) | ||||
except ValidationError: | except ValidationError: | ||||
return None | return None | ||||
@dataclass | @dataclass | ||||
class MetaDir(FuseEntry): | class MetaDir(FuseDirEntry): | ||||
""" The meta/ directory contains one SWHID.json file for each SWHID entry | """ The meta/ directory contains one SWHID.json file for each SWHID entry | ||||
under archive/. The JSON file contain all available meta information about | under archive/. The JSON file contain all available meta information about | ||||
the given SWHID, as returned by the Software Heritage Web API for that | the given SWHID, as returned by the Software Heritage Web API for that | ||||
object. Note that, in case of pagination (e.g., snapshot objects with many | object. Note that, in case of pagination (e.g., snapshot objects with many | ||||
branches) the JSON file will contain a complete version with all pages | branches) the JSON file will contain a complete version with all pages | ||||
merged together. """ | merged together. """ | ||||
name: str = field(init=False, default="meta") | name: str = field(init=False, default="meta") | ||||
mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) | mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) | ||||
async def __aiter__(self) -> AsyncIterator[FuseEntry]: | async def __aiter__(self) -> AsyncIterator[FuseEntry]: | ||||
async for swhid in self.fuse.cache.get_cached_swhids(): | async for swhid in self.fuse.cache.get_cached_swhids(): | ||||
yield self.create_child( | yield self.create_child( | ||||
MetaEntry, | MetaEntry, | ||||
name=f"{swhid}.json", | name=f"{swhid}.json", | ||||
mode=int(EntryMode.RDONLY_FILE), | mode=int(EntryMode.RDONLY_FILE), | ||||
swhid=swhid, | swhid=swhid, | ||||
) | ) | ||||
@dataclass | @dataclass | ||||
class MetaEntry(FuseEntry): | class MetaEntry(FuseFileEntry): | ||||
""" An entry from the meta/ directory, containing for each accessed SWHID a | """ An entry from the meta/ directory, containing for each accessed SWHID a | ||||
corresponding SWHID.json file with all the metadata from the Software | corresponding SWHID.json file with all the metadata from the Software | ||||
Heritage archive. """ | Heritage archive. """ | ||||
swhid: SWHID | swhid: SWHID | ||||
async def get_content(self) -> bytes: | async def get_content(self) -> bytes: | ||||
# Get raw JSON metadata from API (un-typified) | # Get raw JSON metadata from API (un-typified) | ||||
metadata = await self.fuse.cache.metadata.get(self.swhid, typify=False) | metadata = await self.fuse.cache.metadata.get(self.swhid, typify=False) | ||||
return json.dumps(metadata).encode() | return json.dumps(metadata).encode() | ||||
async def size(self) -> int: | async def size(self) -> int: | ||||
return len(await self.get_content()) | return len(await self.get_content()) |