Harden portable Redmine CLI runtime and cache writes
This commit is contained in:
+20
-25
@@ -12,6 +12,7 @@ enough for sync + local search + show next to tickets.
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from redmine_cache_io import cache_lock, read_json, atomic_write_json
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable
|
||||
@@ -34,12 +35,7 @@ class ContactCache:
|
||||
def load_manifest(self) -> dict[str, Any]:
|
||||
if not self.manifest_path.is_file():
|
||||
return {"version": 1, "contacts": {}, "updated_at": None}
|
||||
try:
|
||||
data = json.loads(self.manifest_path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return {"version": 1, "contacts": {}, "updated_at": None}
|
||||
if not isinstance(data, dict):
|
||||
return {"version": 1, "contacts": {}, "updated_at": None}
|
||||
data = read_json(self.manifest_path)
|
||||
data.setdefault("version", 1)
|
||||
data.setdefault("contacts", {})
|
||||
return data
|
||||
@@ -48,9 +44,7 @@ class ContactCache:
|
||||
data = dict(data)
|
||||
data["version"] = 1
|
||||
data["updated_at"] = now_iso()
|
||||
tmp = self.manifest_path.with_suffix(".tmp")
|
||||
tmp.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
tmp.replace(self.manifest_path)
|
||||
atomic_write_json(self.manifest_path, data)
|
||||
|
||||
def should_fetch(self, stub: dict[str, Any]) -> bool:
|
||||
cid = stub.get("id")
|
||||
@@ -64,22 +58,23 @@ class ContactCache:
|
||||
return str(entry.get("updated_on") or "") != str(stub.get("updated_on") or "")
|
||||
|
||||
def write_contact(self, contact: dict[str, Any]) -> Path:
|
||||
cid = contact.get("id")
|
||||
if cid is None:
|
||||
raise ValueError("contact missing id")
|
||||
path = self.contact_path(int(cid))
|
||||
path.write_text(json.dumps(contact, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
manifest = self.load_manifest()
|
||||
contacts = manifest.setdefault("contacts", {})
|
||||
contacts[str(int(cid))] = {
|
||||
"id": int(cid),
|
||||
"updated_on": contact.get("updated_on"),
|
||||
"last_synced": now_iso(),
|
||||
"email": primary_email(contact),
|
||||
"name": contact_display_name(contact),
|
||||
}
|
||||
self.save_manifest(manifest)
|
||||
return path
|
||||
with cache_lock(self.manifest_path):
|
||||
cid = contact.get("id")
|
||||
if cid is None:
|
||||
raise ValueError("contact missing id")
|
||||
path = self.contact_path(int(cid))
|
||||
atomic_write_json(path, contact)
|
||||
manifest = self.load_manifest()
|
||||
contacts = manifest.setdefault("contacts", {})
|
||||
contacts[str(int(cid))] = {
|
||||
"id": int(cid),
|
||||
"updated_on": contact.get("updated_on"),
|
||||
"last_synced": now_iso(),
|
||||
"email": primary_email(contact),
|
||||
"name": contact_display_name(contact),
|
||||
}
|
||||
self.save_manifest(manifest)
|
||||
return path
|
||||
|
||||
def load_contact(self, contact_id: int) -> dict[str, Any]:
|
||||
path = self.contact_path(contact_id)
|
||||
|
||||
Reference in New Issue
Block a user