Move away from inodes as direct db reference
This commit is contained in:
parent
f80f4d12a2
commit
e16d67e2f8
4 changed files with 375 additions and 154 deletions
|
|
@ -2,8 +2,8 @@ import os
|
|||
import sqlite3
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict, List, Self
|
||||
from .trove import NODE_ROOT_ID, Note, Trove, TreeNote, BlobNote, Blob, Tree, BadNoteType
|
||||
from typing import Optional, Dict, List, Self, Iterable
|
||||
from .trove import NODE_ROOT_ID, Note, Trove, TreeNote, BlobNote, Blob, Tree, BadNoteType, TreeEntry, NoteNotFound
|
||||
|
||||
|
||||
class FSNote(Note):
|
||||
|
|
@ -27,7 +27,9 @@ class FSNote(Note):
|
|||
@property
|
||||
def _path(self) -> Path:
|
||||
if self._fs_path is not None:
|
||||
return self._fs_path
|
||||
if self._fs_path.exists():
|
||||
return self._fs_path
|
||||
self._fs_path = None
|
||||
if self._inode is None:
|
||||
raise ValueError("Note not yet saved to disk")
|
||||
self._fs_path = self._trove.get_path_by_inode(self._inode)
|
||||
|
|
@ -42,6 +44,8 @@ class FSNote(Note):
|
|||
|
||||
class FSBlobNote(FSNote, BlobNote):
|
||||
def read(self) -> bytes:
|
||||
if self._inode is None:
|
||||
return b""
|
||||
return self._path.read_bytes()
|
||||
|
||||
def write(self, data: bytes) -> None:
|
||||
|
|
@ -101,6 +105,17 @@ class FSTreeNote(FSNote, TreeNote):
|
|||
self._trove._update_cache(inode, target_path)
|
||||
return FSTreeNote(self._trove, inode=inode, path=target_path)
|
||||
|
||||
def entries(self) -> Iterable[TreeEntry]:
|
||||
try:
|
||||
for item in self._path.iterdir():
|
||||
if item.name == ".trove":
|
||||
continue
|
||||
inode = item.stat().st_ino
|
||||
self._trove._update_cache(inode, item)
|
||||
yield TreeEntry(name=item.name, object_id=inode)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def list(self) -> dict[str, int]:
|
||||
res = {}
|
||||
try:
|
||||
|
|
@ -113,9 +128,16 @@ class FSTreeNote(FSNote, TreeNote):
|
|||
pass
|
||||
return res
|
||||
|
||||
def child(self, name: str) -> Note:
|
||||
"""Retrieve a child not by name."""
|
||||
target_path = self._path / name
|
||||
return self._trove.get_raw_note_by_path(target_path)
|
||||
|
||||
|
||||
class FSTrove(Trove):
|
||||
def __init__(self, root: str | Path):
|
||||
self.root = Path(root).absolute()
|
||||
self._root_inode = self.root.stat().st_ino
|
||||
self.dot_trove = self.root / ".trove"
|
||||
self.working = self.dot_trove / ".working"
|
||||
|
||||
|
|
@ -160,7 +182,7 @@ class FSTrove(Trove):
|
|||
self.con.commit()
|
||||
|
||||
def get_path_by_inode(self, inode: int) -> Optional[Path]:
|
||||
if inode == NODE_ROOT_ID:
|
||||
if inode == self._root_inode:
|
||||
return self.root
|
||||
|
||||
row = self.con.execute("SELECT path FROM cache WHERE inode = ?", (inode,)).fetchone()
|
||||
|
|
@ -189,14 +211,21 @@ class FSTrove(Trove):
|
|||
continue
|
||||
return None
|
||||
|
||||
def get_raw_note(self, note_id: int) -> Optional[Note]:
|
||||
def get_raw_note_by_path(self, target_path: Path) -> Note:
|
||||
if not target_path.exists():
|
||||
raise NoteNotFound(target_path.relative_to(self.root))
|
||||
note_id = target_path.stat().st_ino
|
||||
if target_path.is_dir():
|
||||
return FSTreeNote(self, inode=note_id, path=target_path)
|
||||
else:
|
||||
return FSBlobNote(self, inode=note_id, path=target_path)
|
||||
|
||||
def get_raw_note(self, note_id: int) -> Note:
|
||||
p = self.get_path_by_inode(note_id)
|
||||
if not p:
|
||||
return None
|
||||
if p.is_dir():
|
||||
return FSTreeNote(self, inode=note_id, path=p)
|
||||
else:
|
||||
return FSBlobNote(self, inode=note_id, path=p)
|
||||
raise NoteNotFound(note_id)
|
||||
return self.get_raw_note_by_path(p)
|
||||
|
||||
|
||||
def create_blob(self, data: bytes | None = None) -> BlobNote:
|
||||
fd, temp_path = tempfile.mkstemp(dir=self.working)
|
||||
|
|
@ -211,7 +240,7 @@ class FSTrove(Trove):
|
|||
return FSBlobNote(self, inode=inode, path=p)
|
||||
|
||||
def get_root(self) -> TreeNote:
|
||||
return FSTreeNote(self, inode=NODE_ROOT_ID, path=self.root)
|
||||
return FSTreeNote(self, inode=self._root_inode, path=self.root)
|
||||
|
||||
def _get_metadata(self, inode: int, key: str) -> Optional[bytes]:
|
||||
row = self.con.execute("SELECT value FROM metadata WHERE inode = ? AND key = ?", (inode, key)).fetchone()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue