Changeset View
Changeset View
Standalone View
Standalone View
swh/fuse/fs/mountpoint.py
# Copyright (C) 2020 The Software Heritage developers | # Copyright (C) 2020-2021 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 pathlib import Path | from pathlib import Path | ||||
import re | import re | ||||
from typing import AsyncIterator | from typing import AsyncIterator, Optional | ||||
from swh.fuse.fs.artifact import OBJTYPE_GETTERS, SWHID_REGEXP, Origin | from swh.fuse.fs.artifact import OBJTYPE_GETTERS, SWHID_REGEXP, Origin | ||||
from swh.fuse.fs.entry import ( | from swh.fuse.fs.entry import ( | ||||
EntryMode, | EntryMode, | ||||
FuseDirEntry, | FuseDirEntry, | ||||
FuseEntry, | FuseEntry, | ||||
FuseFileEntry, | FuseFileEntry, | ||||
FuseSymlinkEntry, | FuseSymlinkEntry, | ||||
) | ) | ||||
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 | ||||
JSON_SUFFIX = ".json" | JSON_SUFFIX = ".json" | ||||
@dataclass | @dataclass | ||||
class Root(FuseDirEntry): | class Root(FuseDirEntry): | ||||
""" The FUSE mountpoint, consisting of the archive/ and origin/ directories """ | """ The FUSE mountpoint, consisting of the archive/ and origin/ directories """ | ||||
name: str = field(init=False, default=None) | name: str = field(init=False, default="") | ||||
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 compute_entries(self) -> AsyncIterator[FuseEntry]: | async def compute_entries(self) -> AsyncIterator[FuseEntry]: | ||||
yield self.create_child(ArchiveDir) | yield self.create_child(ArchiveDir) | ||||
yield self.create_child(OriginDir) | yield self.create_child(OriginDir) | ||||
yield self.create_child(CacheDir) | yield self.create_child(CacheDir) | ||||
yield self.create_child(Readme) | yield self.create_child(Readme) | ||||
Show All 12 Lines | class ArchiveDir(FuseDirEntry): | ||||
mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) | mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) | ||||
ENTRIES_REGEXP = re.compile(r"^(" + SWHID_REGEXP + ")(.json)?$") | ENTRIES_REGEXP = re.compile(r"^(" + SWHID_REGEXP + ")(.json)?$") | ||||
async def compute_entries(self) -> AsyncIterator[FuseEntry]: | async def compute_entries(self) -> AsyncIterator[FuseEntry]: | ||||
return | return | ||||
yield | yield | ||||
async def lookup(self, name: str) -> FuseEntry: | async def lookup(self, name: str) -> Optional[FuseEntry]: | ||||
# On the fly mounting of a new artifact | # On the fly mounting of a new artifact | ||||
try: | try: | ||||
if name.endswith(JSON_SUFFIX): | if name.endswith(JSON_SUFFIX): | ||||
swhid = parse_swhid(name[: -len(JSON_SUFFIX)]) | swhid = parse_swhid(name[: -len(JSON_SUFFIX)]) | ||||
return self.create_child( | return self.create_child( | ||||
MetaEntry, | MetaEntry, | ||||
name=f"{swhid}{JSON_SUFFIX}", | name=f"{swhid}{JSON_SUFFIX}", | ||||
mode=int(EntryMode.RDONLY_FILE), | mode=int(EntryMode.RDONLY_FILE), | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | class OriginDir(FuseDirEntry): | ||||
origin URL (mangled to create a valid UNIX filename). The URL encoding is | origin URL (mangled to create a valid UNIX filename). The URL encoding is | ||||
done using the percent-encoding mechanism described in RFC 3986. """ | done using the percent-encoding mechanism described in RFC 3986. """ | ||||
name: str = field(init=False, default="origin") | name: str = field(init=False, default="origin") | ||||
mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) | mode: int = field(init=False, default=int(EntryMode.RDONLY_DIR)) | ||||
ENTRIES_REGEXP = re.compile(r"^.*%3A.*$") # %3A is the encoded version of ':' | ENTRIES_REGEXP = re.compile(r"^.*%3A.*$") # %3A is the encoded version of ':' | ||||
def create_child(self, url_encoded: str) -> FuseEntry: | def create_origin_child(self, url_encoded: str) -> FuseEntry: | ||||
return super().create_child( | return super().create_child( | ||||
Origin, name=url_encoded, mode=int(EntryMode.RDONLY_DIR), | Origin, name=url_encoded, mode=int(EntryMode.RDONLY_DIR), | ||||
) | ) | ||||
async def compute_entries(self) -> AsyncIterator[FuseEntry]: | async def compute_entries(self) -> AsyncIterator[FuseEntry]: | ||||
async for url in self.fuse.cache.get_cached_visits(): | async for url in self.fuse.cache.get_cached_visits(): | ||||
yield self.create_child(url) | yield self.create_origin_child(url) | ||||
async def lookup(self, name: str) -> FuseEntry: | async def lookup(self, name: str) -> Optional[FuseEntry]: | ||||
entry = await super().lookup(name) | entry = await super().lookup(name) | ||||
if entry: | if entry: | ||||
return entry | return entry | ||||
# On the fly mounting of new origin url | # On the fly mounting of new origin url | ||||
try: | try: | ||||
url_encoded = name | url_encoded = name | ||||
await self.fuse.get_visits(url_encoded) | await self.fuse.get_visits(url_encoded) | ||||
return self.create_child(url_encoded) | return self.create_origin_child(url_encoded) | ||||
except ValueError: | except ValueError: | ||||
return None | return None | ||||
@dataclass | @dataclass | ||||
class CacheDir(FuseDirEntry): | class CacheDir(FuseDirEntry): | ||||
""" The cache/ directory is an on-disk representation of locally cached | """ The cache/ directory is an on-disk representation of locally cached | ||||
objects and metadata. Via this directory you can browse cached data and | objects and metadata. Via this directory you can browse cached data and | ||||
▲ Show 20 Lines • Show All 98 Lines • Show Last 20 Lines |