176 lines
5.5 KiB
Python
176 lines
5.5 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import Any, Dict, Optional, Sequence
|
|
import sys
|
|
|
|
from SYS.logger import log
|
|
|
|
import pipeline as ctx
|
|
from . import _shared as sh
|
|
|
|
Cmdlet = sh.Cmdlet
|
|
CmdletArg = sh.CmdletArg
|
|
SharedArgs = sh.SharedArgs
|
|
normalize_hash = sh.normalize_hash
|
|
parse_cmdlet_args = sh.parse_cmdlet_args
|
|
normalize_result_input = sh.normalize_result_input
|
|
should_show_help = sh.should_show_help
|
|
from Store import Store
|
|
from SYS.utils import sha256_file
|
|
|
|
|
|
class Get_Note(Cmdlet):
|
|
|
|
def __init__(self) -> None:
|
|
super().__init__(
|
|
name="get-note",
|
|
summary="List notes on a file in a store.",
|
|
usage='get-note -store <store> [-query "hash:<sha256>"]',
|
|
alias=["get-notes",
|
|
"get_note"],
|
|
arg=[
|
|
SharedArgs.STORE,
|
|
SharedArgs.QUERY,
|
|
],
|
|
detail=[
|
|
"- Notes are retrieved via the selected store backend.",
|
|
"- Lyrics are stored in a note named 'lyric'.",
|
|
],
|
|
exec=self.run,
|
|
)
|
|
try:
|
|
SharedArgs.STORE.choices = SharedArgs.get_store_choices(None)
|
|
except Exception:
|
|
pass
|
|
self.register()
|
|
|
|
def _resolve_hash(
|
|
self,
|
|
raw_hash: Optional[str],
|
|
raw_path: Optional[str],
|
|
override_hash: Optional[str]
|
|
) -> Optional[str]:
|
|
resolved = normalize_hash(override_hash
|
|
) if override_hash else normalize_hash(raw_hash)
|
|
if resolved:
|
|
return resolved
|
|
if raw_path:
|
|
try:
|
|
p = Path(str(raw_path))
|
|
stem = p.stem
|
|
if len(stem) == 64 and all(c in "0123456789abcdef"
|
|
for c in stem.lower()):
|
|
return stem.lower()
|
|
if p.exists() and p.is_file():
|
|
return sha256_file(p)
|
|
except Exception:
|
|
return None
|
|
return None
|
|
|
|
def run(self, result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
|
if should_show_help(args):
|
|
log(f"Cmdlet: {self.name}\nSummary: {self.summary}\nUsage: {self.usage}")
|
|
return 0
|
|
|
|
parsed = parse_cmdlet_args(args, self)
|
|
store_override = parsed.get("store")
|
|
query_hash = sh.parse_single_hash_query(parsed.get("query"))
|
|
if parsed.get("query") and not query_hash:
|
|
log(
|
|
"[get_note] Error: -query must be of the form hash:<sha256>",
|
|
file=sys.stderr
|
|
)
|
|
return 1
|
|
|
|
results = normalize_result_input(result)
|
|
if not results:
|
|
if store_override and query_hash:
|
|
results = [{
|
|
"store": str(store_override),
|
|
"hash": query_hash
|
|
}]
|
|
else:
|
|
log(
|
|
'[get_note] Error: Requires piped item(s) or -store and -query "hash:<sha256>"',
|
|
file=sys.stderr,
|
|
)
|
|
return 1
|
|
|
|
store_registry = Store(config)
|
|
any_notes = False
|
|
|
|
for res in results:
|
|
if not isinstance(res, dict):
|
|
continue
|
|
|
|
store_name = str(store_override or res.get("store") or "").strip()
|
|
raw_hash = res.get("hash")
|
|
raw_path = res.get("path")
|
|
|
|
if not store_name:
|
|
log(
|
|
"[get_note] Error: Missing -store and item has no store field",
|
|
file=sys.stderr
|
|
)
|
|
return 1
|
|
|
|
resolved_hash = self._resolve_hash(
|
|
raw_hash=str(raw_hash) if raw_hash else None,
|
|
raw_path=str(raw_path) if raw_path else None,
|
|
override_hash=str(query_hash) if query_hash else None,
|
|
)
|
|
if not resolved_hash:
|
|
continue
|
|
|
|
try:
|
|
backend = store_registry[store_name]
|
|
except Exception as exc:
|
|
log(
|
|
f"[get_note] Error: Unknown store '{store_name}': {exc}",
|
|
file=sys.stderr
|
|
)
|
|
return 1
|
|
|
|
notes = {}
|
|
try:
|
|
notes = backend.get_note(
|
|
resolved_hash,
|
|
config=config
|
|
) or {}
|
|
except Exception:
|
|
notes = {}
|
|
|
|
if not notes:
|
|
continue
|
|
|
|
any_notes = True
|
|
# Emit each note as its own row so CLI renders a proper note table
|
|
for k in sorted(notes.keys(), key=lambda x: str(x).lower()):
|
|
v = notes.get(k)
|
|
raw_text = str(v or "")
|
|
# Keep payload small for IPC/pipes.
|
|
raw_text = raw_text[:999]
|
|
preview = " ".join(raw_text.replace("\r", "").split("\n"))
|
|
ctx.emit(
|
|
{
|
|
"store": store_name,
|
|
"hash": resolved_hash,
|
|
"note_name": str(k),
|
|
"note_text": raw_text,
|
|
"columns": [
|
|
("Name",
|
|
str(k)),
|
|
("Text",
|
|
preview.strip()),
|
|
],
|
|
}
|
|
)
|
|
|
|
if not any_notes:
|
|
ctx.emit("No notes found.")
|
|
return 0
|
|
|
|
|
|
CMDLET = Get_Note()
|