feat: add safe calendar import and export
Add explicit noninteractive CLI transfer modes with full event validation, idempotent duplicate handling, collision refusal, atomic import backups, and no-overwrite export creation. Cover pure merge semantics and end-to-end rollback paths for unsupported content, invalid identities, conflicts, option combinations, and existing destinations.
This commit is contained in:
@@ -82,6 +82,25 @@ does not consume the backup. The TUI mutates a copyable in-memory model and
|
||||
rolls it back if persistence fails. Its bounded undo/redo history contains only
|
||||
mutations that crossed the persistence boundary successfully.
|
||||
|
||||
Explicit CLI import and export reuse the storage parser, safety classification,
|
||||
validation, and atomic persistence boundary; these workflows do not depend on
|
||||
the TUI and perform no network access. Import loads and validates both source
|
||||
and target before staging a target replacement. UIDs in both files must be
|
||||
non-empty and unique, every interval must be valid, and every component in both
|
||||
files must be safe to round-trip. Matching UID plus identical fields is an
|
||||
idempotent duplicate; matching UID with different fields is a collision that
|
||||
aborts the whole operation. A committed merge writes the exact old target to
|
||||
`.bak` before atomic replacement. If every source event is already present
|
||||
exactly, import performs no write and does not alter the backup.
|
||||
|
||||
Export accepts only a valid, safely round-trippable source, serializes a
|
||||
canonical calendar through private staging, and atomically creates a destination
|
||||
that must not already exist. Destination refusal is part of the
|
||||
commit boundary, so export never replaces an existing path. Import, export,
|
||||
demo, non-interactive frame printing, and backup restoration are distinct
|
||||
top-level application modes; import and export cannot be selected together or
|
||||
combined with any of the other modes.
|
||||
|
||||
The current writer deliberately refuses to mutate an existing file when the
|
||||
loader encounters information it cannot round-trip, including recurrence
|
||||
overrides, `RDATE`, custom `VTIMEZONE` definitions, alarms, attendees, unknown
|
||||
|
||||
Reference in New Issue
Block a user