[FUSE]: Generalizing path parsing
All checks were successful
Test Python / Test (push) Successful in 26s
All checks were successful
Test Python / Test (push) Successful in 26s
This commit is contained in:
parent
471704d9fe
commit
17ab429ed3
|
@ -11,52 +11,20 @@ from .favro_client import FavroClient
|
|||
from .favro_data_model import Card, SeqId, CustomFieldInfo, CustomFieldItemId, CustomField
|
||||
from .favro_markdown import CardContents, CardFileFormatter
|
||||
|
||||
################################################################################
|
||||
# Constants
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
fuse.fuse_python_api = (0, 2)
|
||||
|
||||
|
||||
class FavroStat(fuse.Stat):
|
||||
def __init__(self):
|
||||
self.st_mode = 0
|
||||
self.st_ino = 0
|
||||
self.st_dev = 0
|
||||
self.st_nlink = 0
|
||||
self.st_uid = 0
|
||||
self.st_gid = 0
|
||||
self.st_size = 0
|
||||
self.st_atime = 0
|
||||
self.st_mtime = 0
|
||||
self.st_ctime = 0
|
||||
|
||||
|
||||
OFFICIAL_URL = 'https://favro.com/organization/{org_id}?card=par-{seq_id}'
|
||||
CARD_IDENTIFIER_FORMAT = 'PAR-{seq_id}'
|
||||
CARD_FILENAME_FORMAT = CARD_IDENTIFIER_FORMAT + '.md'
|
||||
CARD_FILENAME_REGEX = r'^\/PAR\-(\d+)\.md$'
|
||||
|
||||
OFFICIAL_URL = 'https://favro.com/organization/{org_id}?card=par-{seq_id}'
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class FileSystemItem:
|
||||
@staticmethod
|
||||
def from_path(path_str: str) -> 'FileSystemItem | None':
|
||||
if path_str == '/':
|
||||
return RootFileSystemItem()
|
||||
if m := re.match(CARD_FILENAME_REGEX, path_str):
|
||||
return CardFileSystemItem(SeqId(int(m.group(1))))
|
||||
return None
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class RootFileSystemItem(FileSystemItem):
|
||||
pass
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class CardFileSystemItem(FileSystemItem):
|
||||
seq_id: SeqId
|
||||
CARD_FILENAME_REGEX = r'^PAR\-(\d+)\.md$'
|
||||
|
||||
################################################################################
|
||||
# Formatting
|
||||
|
||||
def to_custom_field_value(custom_field: CustomField, field_def: CustomFieldInfo) -> str:
|
||||
value: CustomFieldItemId | list[CustomFieldItemId] = custom_field.value
|
||||
|
@ -107,6 +75,61 @@ def to_card_contents(card: Card, favro_client: FavroClient) -> str:
|
|||
)
|
||||
|
||||
|
||||
################################################################################
|
||||
# FUSE
|
||||
|
||||
class FavroStat(fuse.Stat):
|
||||
def __init__(self):
|
||||
self.st_mode = 0
|
||||
self.st_ino = 0
|
||||
self.st_dev = 0
|
||||
self.st_nlink = 0
|
||||
self.st_uid = 0
|
||||
self.st_gid = 0
|
||||
self.st_size = 0
|
||||
self.st_atime = 0
|
||||
self.st_mtime = 0
|
||||
self.st_ctime = 0
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class FileSystemItem:
|
||||
pass
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class RootFileSystemItem(FileSystemItem):
|
||||
|
||||
@staticmethod
|
||||
def from_path_segment(segment: str) -> 'RootFileSystemItem':
|
||||
return RootFileSystemItem()
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class OrganizationFileSystemItem(FileSystemItem):
|
||||
name: str
|
||||
|
||||
@staticmethod
|
||||
def from_path_segment(segment: str) -> 'OrganizationFileSystemItem':
|
||||
return OrganizationFileSystemItem(segment)
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class CardFileSystemItem(FileSystemItem):
|
||||
seq_id: SeqId
|
||||
|
||||
@staticmethod
|
||||
def from_path_segment(segment: str) -> 'CardFileSystemItem | None':
|
||||
if m := re.match(CARD_FILENAME_REGEX, segment):
|
||||
return CardFileSystemItem(SeqId(int(m.group(1))))
|
||||
return None
|
||||
|
||||
|
||||
def path_to_file_system_item(path_str: str, path_components: list[type[FileSystemItem]]) -> FileSystemItem | None:
|
||||
path = re.findall(r'[^/]+', path_str)
|
||||
component = path_components[len(path)]
|
||||
return component.from_path_segment(path[-1] if path else None)
|
||||
|
||||
|
||||
class FavroFuse(fuse.Fuse):
|
||||
"""Favro FileSystem in Userspace."""
|
||||
|
||||
|
@ -119,17 +142,19 @@ class FavroFuse(fuse.Fuse):
|
|||
self.favro_client = favro_client
|
||||
self.formatter = formatter
|
||||
self.wiped_cards = set()
|
||||
#self.path_components = [RootFileSystemItem, OrganizationFileSystemItem, CardFileSystemItem]
|
||||
self.path_components = [RootFileSystemItem, CardFileSystemItem]
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def getattr(self, path: str) -> FavroStat | int:
|
||||
thing = FileSystemItem.from_path(path)
|
||||
file_system_item = path_to_file_system_item(path, self.path_components)
|
||||
|
||||
st = FavroStat()
|
||||
if isinstance(thing, RootFileSystemItem):
|
||||
if isinstance(file_system_item, RootFileSystemItem):
|
||||
st.st_mode = stat.S_IFDIR | 0o755
|
||||
st.st_nlink = 2
|
||||
elif isinstance(thing, CardFileSystemItem):
|
||||
card = self.favro_client.get_card(thing.seq_id)
|
||||
elif isinstance(file_system_item, CardFileSystemItem):
|
||||
card = self.favro_client.get_card(file_system_item.seq_id)
|
||||
|
||||
st.st_mode = stat.S_IFREG | 0o666
|
||||
st.st_nlink = 1
|
||||
|
@ -149,18 +174,18 @@ class FavroFuse(fuse.Fuse):
|
|||
yield fuse.Direntry(CARD_FILENAME_FORMAT.format(seq_id=card.seq_id.raw_id))
|
||||
|
||||
def open(self, path: str, flags: int) -> int | None:
|
||||
thing = FileSystemItem.from_path(path)
|
||||
if not isinstance(thing, CardFileSystemItem):
|
||||
file_system_item = path_to_file_system_item(path, self.path_components)
|
||||
if not isinstance(file_system_item, CardFileSystemItem):
|
||||
return -errno.ENOENT
|
||||
return None
|
||||
|
||||
def read(self, path: str, size: int, offset: int) -> bytes | int:
|
||||
# Check that this is a card thing.
|
||||
thing = FileSystemItem.from_path(path)
|
||||
if not isinstance(thing, CardFileSystemItem):
|
||||
# Check that this is a card file_system_item.
|
||||
file_system_item = path_to_file_system_item(path, self.path_components)
|
||||
if not isinstance(file_system_item, CardFileSystemItem):
|
||||
return -errno.ENOENT
|
||||
|
||||
card = self.favro_client.get_card(thing.seq_id)
|
||||
card = self.favro_client.get_card(file_system_item.seq_id)
|
||||
|
||||
contents_str = self._format_card_file(card)
|
||||
contents = bytes(contents_str, 'utf8')
|
||||
|
@ -175,12 +200,12 @@ class FavroFuse(fuse.Fuse):
|
|||
return buf
|
||||
|
||||
def write(self, path: str, written_buffer: bytes, offset: int) -> int:
|
||||
# Check that this is a card thing.
|
||||
thing = FileSystemItem.from_path(path)
|
||||
if not isinstance(thing, CardFileSystemItem):
|
||||
# Check that this is a card file_system_item.
|
||||
file_system_item = path_to_file_system_item(path, self.path_components)
|
||||
if not isinstance(file_system_item, CardFileSystemItem):
|
||||
return -errno.ENOENT
|
||||
|
||||
card = self.favro_client.get_card(thing.seq_id)
|
||||
card = self.favro_client.get_card(file_system_item.seq_id)
|
||||
|
||||
# Splice contents
|
||||
contents_str = self._format_card_file(card)
|
||||
|
@ -192,18 +217,18 @@ class FavroFuse(fuse.Fuse):
|
|||
card_updated = self.formatter.parse_card_contents(contents_str)
|
||||
self.favro_client.update_card_contents(card.card_id, card_updated)
|
||||
|
||||
self.wiped_cards.remove(thing.seq_id)
|
||||
self.wiped_cards.remove(file_system_item.seq_id)
|
||||
|
||||
# Return amount written
|
||||
return len(written_buffer)
|
||||
|
||||
def truncate(self, path: str, new_size: int):
|
||||
# Check that this is a card thing.
|
||||
thing = FileSystemItem.from_path(path)
|
||||
if not isinstance(thing, CardFileSystemItem):
|
||||
# Check that this is a card file_system_item.
|
||||
file_system_item = path_to_file_system_item(path, self.path_components)
|
||||
if not isinstance(file_system_item, CardFileSystemItem):
|
||||
return -errno.ENOENT
|
||||
|
||||
card = self.favro_client.get_card(thing.seq_id)
|
||||
card = self.favro_client.get_card(file_system_item.seq_id)
|
||||
|
||||
# Splice contents
|
||||
contents_str = self._format_card_file(card)
|
||||
|
@ -217,7 +242,7 @@ class FavroFuse(fuse.Fuse):
|
|||
card_updated = self.formatter.parse_card_contents(contents_str)
|
||||
self.favro_client.update_card_contents_locally(card.card_id, card_updated)
|
||||
|
||||
self.wiped_cards.add(thing.seq_id)
|
||||
self.wiped_cards.add(file_system_item.seq_id)
|
||||
|
||||
# Return amount written
|
||||
return 0
|
||||
|
|
Loading…
Reference in New Issue
Block a user