Skip to content

Backup & Sync: export/import + optional git repo - #53

Open
iTerminate wants to merge 10 commits into
mainfrom
custom-keybindings-config
Open

Backup & Sync: export/import + optional git repo#53
iTerminate wants to merge 10 commits into
mainfrom
custom-keybindings-config

Conversation

@iTerminate

Copy link
Copy Markdown
Owner

Summary

  • Standard single-object JSON export/import for lists and saved graphs (x/i in their popups), matching the existing dashboard format
  • backup.py: composes those per-object payloads into a directory export (lists/dashboards/graphs + entity names/settings/keybindings), with stale-file pruning and stable diffs
  • git_sync.py: a hardened, non-interactive git CLI layer (no credential prompts, per-command timeouts, safe against a directory nested inside another repo)
  • BackupController (app.backup_ctl) wired into the app: manual export/import, pull-on-start
  • Exit-time sync: commit_on_exit/push_on_exit show a small overlay while syncing; escape/quit always skips it immediately so a stalled push can never trap the user; cli.py has a last-resort fallback for a bare SIGINT
  • New "Backup & Sync" category in Configuration: directory picker, section/git toggles, and Export/Import/Init/Pull/Push/Status buttons acting on the currently-entered fields

Test plan

  • pytest — full suite green (1496 passed, 1 skipped)
  • uv run ruff check . — clean
  • uv run pyright — 0 errors
  • New unit coverage: test_backup.py, test_git_sync.py, test_backup_controller.py, plus controller tests for the new list/graph export formats
  • New acceptance coverage: test_config_screen_backup.py, test_backup_exit_sync.py, test_backup_git.py (real git against a local bare remote), plus list/graph export-import tests
  • Manual smoke test against a real HA instance (not done — feature needs no live HA; verified via --demo and scratch configs only)

Mirrors the existing per-dashboard JSON format (x/i in each popup) so any
list, dashboard, or saved graph can be shared as a single file — the format
the upcoming Backup & Sync feature will read and write in bulk.
Composes the standard per-object formats (lists/dashboards/saved graphs)
plus whole-collection files (entity names, settings, keybindings) into a
directory, with byte-stable writes and stale-object pruning so a git diff
stays minimal. No git integration yet — that's git_sync.py next.
Non-interactive, timeout-bounded init/commit/pull/push over the export
directory, shelling out to the git binary through one chokepoint so every
invocation is hardened against credential prompts and hangs. No wiring
into the app yet — that's the BackupController next.
Merges backup prefs on boot/config-save (mirrors KeybindingController),
drives manual export/import against the running app's live collections,
and fires pull-on-start. No UI entry point or exit-time git sync yet.
action_quit shows an ExitSyncScreen overlay so commit_on_exit/push_on_exit
never freezes the message pump; _on_exit_app backstops any exit() that
skips it, and cli.py has a last-resort sync flush for a bare SIGINT. escape
always skips straight to quitting, so a stalled push can never trap the
user. Test suite gets a global git_sync._run_git stub so quitting the app
in acceptance tests never shells out for real.
Directory picker, section/git toggles, and export/import/init/pull/push/
status buttons that all act on the currently-entered (unsaved) fields,
mirroring the connection-test buttons. export_now/import_now gain optional
path/sections overrides for this; also fixes a real bug where wrapping them
in asyncio.to_thread broke persist()'s asyncio.create_task() (no running
loop in a thread-pool worker).
write_export left the manifest's exported_at/hatty_version untouched
whenever no data file actually changed, so a no-op export (e.g. at exit
with nothing edited) no longer stages a git diff — commit_on_exit/
push_on_exit stop creating a commit for just the clock moving.
ExitSyncScreen (and the SIGINT fallback in cli.py) now show
Exporting…/Committing…/Pushing… as each step runs instead of one static
"Syncing with git…" for the whole duration, so a slow exit says what it's
actually waiting on.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant