Backup & Sync: export/import + optional git repo - #53
Open
iTerminate wants to merge 10 commits into
Open
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
x/iin their popups), matching the existing dashboard formatbackup.py: composes those per-object payloads into a directory export (lists/dashboards/graphs + entity names/settings/keybindings), with stale-file pruning and stable diffsgit_sync.py: a hardened, non-interactivegitCLI 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-startcommit_on_exit/push_on_exitshow a small overlay while syncing; escape/quit always skips it immediately so a stalled push can never trap the user;cli.pyhas a last-resort fallback for a bareSIGINTTest plan
pytest— full suite green (1496 passed, 1 skipped)uv run ruff check .— cleanuv run pyright— 0 errorstest_backup.py,test_git_sync.py,test_backup_controller.py, plus controller tests for the new list/graph export formatstest_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--demoand scratch configs only)