Blob is no more. Notes now always have content.
This commit is contained in:
parent
5df3c81417
commit
ffefe4dd21
4 changed files with 28 additions and 48 deletions
|
|
@ -4,7 +4,9 @@ import tempfile
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Dict, List, Self, Iterable
|
from typing import Optional, Dict, List, Self, Iterable
|
||||||
from .trove import Note, Trove, TreeNote, BlobNote, Blob, Tree, BadNoteType, TreeEntry, NoteNotFound
|
|
||||||
|
from .trove import Note, Trove, TreeNote, BadNoteType, TreeEntry, NoteNotFound
|
||||||
|
from . import fs_util as fsu
|
||||||
|
|
||||||
|
|
||||||
class FSNote(Note):
|
class FSNote(Note):
|
||||||
|
|
@ -61,22 +63,17 @@ class FSNote(Note):
|
||||||
def set_raw_metadata(self, key: str, value: bytes) -> None:
|
def set_raw_metadata(self, key: str, value: bytes) -> None:
|
||||||
self._trove._set_metadata(self._inode, key, value)
|
self._trove._set_metadata(self._inode, key, value)
|
||||||
|
|
||||||
class FSBlobNote(FSNote, BlobNote):
|
def read_content(self) -> bytes:
|
||||||
def read(self) -> bytes:
|
"""Read the raw content of the note."""
|
||||||
if self._inode is None:
|
content_file = fsu.get_content_path(self._path)
|
||||||
|
if content_file.exists():
|
||||||
|
return content_file.read_bytes()
|
||||||
return b""
|
return b""
|
||||||
return self._path.read_bytes()
|
|
||||||
|
|
||||||
def write(self, data: bytes) -> None:
|
def write_content(self, data:bytes) -> None:
|
||||||
self._path.write_bytes(data)
|
"""Write the raw content of the note."""
|
||||||
# Update cache just in case inode changed (some editors do this)
|
content_file = fsu.get_content_path(self._path)
|
||||||
try:
|
content_file.write_bytes(data)
|
||||||
new_inode = self._path.stat().st_ino
|
|
||||||
if new_inode != self._inode:
|
|
||||||
self._trove._update_cache(new_inode, self._path)
|
|
||||||
self._inode = new_inode
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
class FSTreeNote(FSNote, TreeNote):
|
class FSTreeNote(FSNote, TreeNote):
|
||||||
@property
|
@property
|
||||||
|
|
@ -85,7 +82,7 @@ class FSTreeNote(FSNote, TreeNote):
|
||||||
return "inode/directory"
|
return "inode/directory"
|
||||||
|
|
||||||
def link(self, name: str, note: Note):
|
def link(self, name: str, note: Note):
|
||||||
if not isinstance(note, FSBlobNote):
|
if not isinstance(note, FSNote):
|
||||||
raise BadNoteType("Only blob notes can be linked")
|
raise BadNoteType("Only blob notes can be linked")
|
||||||
|
|
||||||
target_path = self._path / name
|
target_path = self._path / name
|
||||||
|
|
@ -239,7 +236,7 @@ class FSTrove(Trove):
|
||||||
if target_path.is_dir():
|
if target_path.is_dir():
|
||||||
return FSTreeNote(self, inode=note_id, path=target_path)
|
return FSTreeNote(self, inode=note_id, path=target_path)
|
||||||
else:
|
else:
|
||||||
return FSBlobNote(self, inode=note_id, path=target_path)
|
return FSNote(self, inode=note_id, path=target_path)
|
||||||
|
|
||||||
def get_raw_note(self, note_id: int) -> Note:
|
def get_raw_note(self, note_id: int) -> Note:
|
||||||
p = self.get_path_by_inode(note_id)
|
p = self.get_path_by_inode(note_id)
|
||||||
|
|
@ -248,7 +245,7 @@ class FSTrove(Trove):
|
||||||
return self.get_raw_note_by_path(p)
|
return self.get_raw_note_by_path(p)
|
||||||
|
|
||||||
|
|
||||||
def create_blob(self, data: bytes | None = None) -> BlobNote:
|
def create_blob(self, data: bytes | None = None) -> Note:
|
||||||
fd, temp_path = tempfile.mkstemp(dir=self.working)
|
fd, temp_path = tempfile.mkstemp(dir=self.working)
|
||||||
try:
|
try:
|
||||||
if data:
|
if data:
|
||||||
|
|
@ -258,7 +255,7 @@ class FSTrove(Trove):
|
||||||
p = Path(temp_path)
|
p = Path(temp_path)
|
||||||
inode = p.stat().st_ino
|
inode = p.stat().st_ino
|
||||||
self._update_cache(inode, p)
|
self._update_cache(inode, p)
|
||||||
return FSBlobNote(self, inode=inode, path=p)
|
return FSNote(self, inode=inode, path=p)
|
||||||
|
|
||||||
def get_root(self) -> TreeNote:
|
def get_root(self) -> TreeNote:
|
||||||
return FSTreeNote(self, inode=self._root_inode, path=self.root)
|
return FSTreeNote(self, inode=self._root_inode, path=self.root)
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,5 @@ class ToolBasicEditor(Tool):
|
||||||
layout.addWidget(self._text_edit)
|
layout.addWidget(self._text_edit)
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
def _refresh_blob(self, note: tr.Blob):
|
|
||||||
self._text_edit.setPlainText(note.read().decode("utf-8"))
|
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
if isinstance(self.note, tr.Blob):
|
self._text_edit.setPlainText(self.note.read_content().decode("utf-8"))
|
||||||
self._refresh_blob(cast(tr.Blob, self.note))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,14 +56,12 @@ class Note(Protocol):
|
||||||
"""Set metadata value for the given key."""
|
"""Set metadata value for the given key."""
|
||||||
...
|
...
|
||||||
|
|
||||||
@runtime_checkable
|
def read_content(self) -> bytes:
|
||||||
class Blob(Protocol):
|
|
||||||
def read(self) -> bytes:
|
|
||||||
"""Read the raw content of the note."""
|
"""Read the raw content of the note."""
|
||||||
...
|
...
|
||||||
|
|
||||||
def write(self, data: bytes) -> None:
|
def write_content(self, data:bytes) -> None:
|
||||||
"""Write new content to the note."""
|
"""Write the raw content of the note."""
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -101,10 +99,6 @@ class Tree(Protocol):
|
||||||
"""Return all entries as {name: object_id}."""
|
"""Return all entries as {name: object_id}."""
|
||||||
...
|
...
|
||||||
|
|
||||||
@runtime_checkable
|
|
||||||
class BlobNote(Note, Blob, Protocol):
|
|
||||||
"""Blob Note"""
|
|
||||||
|
|
||||||
@runtime_checkable
|
@runtime_checkable
|
||||||
class TreeNote(Note, Tree, Protocol):
|
class TreeNote(Note, Tree, Protocol):
|
||||||
"""Tree Note"""
|
"""Tree Note"""
|
||||||
|
|
@ -121,7 +115,7 @@ class Trove(Protocol):
|
||||||
"""Retrieve a note by a object id"""
|
"""Retrieve a note by a object id"""
|
||||||
...
|
...
|
||||||
|
|
||||||
def create_blob(self, data: bytes | None = None) -> BlobNote:
|
def create_blob(self, data: bytes | None = None) -> Note:
|
||||||
"""Create a new blob node at the given path with content"""
|
"""Create a new blob node at the given path with content"""
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ from .db import Sqlite3Trove, NOTE_ROOT_ID
|
||||||
|
|
||||||
from . import trove as tr
|
from . import trove as tr
|
||||||
|
|
||||||
from .trove import Note, Trove, TreeNote, BlobNote, TreeEntry, NoteNotFound, ObjectId
|
from .trove import Note, Trove, TreeNote, TreeEntry, NoteNotFound, ObjectId
|
||||||
|
|
||||||
|
|
||||||
class NoteImpl(Note):
|
class NoteImpl(Note):
|
||||||
|
|
@ -50,16 +50,11 @@ class NoteImpl(Note):
|
||||||
def set_raw_metadata(self, key: str, value: bytes) -> None:
|
def set_raw_metadata(self, key: str, value: bytes) -> None:
|
||||||
self._db.write_metadata(self._object_id, key, value)
|
self._db.write_metadata(self._object_id, key, value)
|
||||||
|
|
||||||
|
def read_content(self) -> bytes:
|
||||||
class BlobNoteImpl(NoteImpl, BlobNote):
|
|
||||||
"""Concrete BlobNote: a blob object in the store with metadata access."""
|
|
||||||
|
|
||||||
# Blob protocol
|
|
||||||
def read(self) -> bytes:
|
|
||||||
data = self._db.read_object(self._object_id)
|
data = self._db.read_object(self._object_id)
|
||||||
return data if data is not None else b""
|
return data if data is not None else b""
|
||||||
|
|
||||||
def write(self, data: bytes) -> None:
|
def write_content(self, data: bytes) -> None:
|
||||||
self._db.write_content(self._object_id, data)
|
self._db.write_content(self._object_id, data)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -147,13 +142,13 @@ class TroveImpl:
|
||||||
raise NoteNotFound(note_id)
|
raise NoteNotFound(note_id)
|
||||||
if self._db.is_tree(note_id) or info.type == "inode/directory":
|
if self._db.is_tree(note_id) or info.type == "inode/directory":
|
||||||
return TreeNoteImpl(self, note_id)
|
return TreeNoteImpl(self, note_id)
|
||||||
return BlobNoteImpl(self, note_id)
|
return NoteImpl(self, note_id)
|
||||||
|
|
||||||
def create_blob(self, data: bytes | None = None,
|
def create_blob(self, data: bytes | None = None,
|
||||||
dtype: str = "application/octet-stream") -> BlobNote:
|
dtype: str = "application/octet-stream") -> Note:
|
||||||
"""Create a new blob object and return a BlobNote for it."""
|
"""Create a new blob object and return a BlobNote for it."""
|
||||||
obj_id = self._db.write_blob(data or b"", dtype=dtype)
|
obj_id = self._db.write_blob(data or b"", dtype=dtype)
|
||||||
return BlobNoteImpl(self, obj_id)
|
return NoteImpl(self, obj_id)
|
||||||
|
|
||||||
def get_root(self) -> TreeNote:
|
def get_root(self) -> TreeNote:
|
||||||
"""Return the root TreeNote (always id=NOTE_ROOT_ID)."""
|
"""Return the root TreeNote (always id=NOTE_ROOT_ID)."""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue