Add utopia CLI with backup subcommand (restore stubbed) - #712
Open
rollroyces wants to merge 1 commit into
Open
rollroyces wants to merge 1 commit into
rollroyces wants to merge 1 commit into
Conversation
Roadmap item #2 (Enterprise — backup and restore commands). First cut: a separate `utopia-cli` crate that depends only on `utopia-core` for config loading, so backup/restore don't pull in the server, extractor, or chat loop. What lands: - crates/utopia-cli/src/main.rs (589 lines): hand-rolled arg parser, Manifest schema (schema_version, utopia_version, created_at, component paths + sha256 checksums), backup() that shells out to pg_dump -Fc + tar, restore() stubbed with a clear bail. - crates/utopia-cli/Cargo.toml - Cargo.toml workspace: add crates/utopia-cli to members - .roadmap-proposals/backup-restore.md: design with 5 open questions Flags on backup: --output, --include-data-dir, --dry-run, --pg-dump, --tar, --migration-url Flags on restore (stubbed): --from, --target-data-dir, --pg-restore, --dry-run, --force, --yes Tests: 8 unit tests, all pure (no live DB): arg parsing for both subcommands (minimal + full), --from is required on restore, unknown subcommand rejected, url-host redaction round-trips on urls with/without userinfo, hex_encode known value. Restore side is intentionally stubbed — design doc explains why (independent usefulness of backup, restore design questions benefit from running backup in production first). Restore cut follows when the maintainer answers the 5 open questions in the design doc. The CLI reuses AppConfig::load() for connection info, so it picks up the same .env / UTOPIA_DATABASE_URL / UTOPIA_DATA_DIR the server uses. No duplicate config wiring. Signed-off-by: Royce Lam <roycelam@umich.edu>
Merged
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
Roadmap item: Enterprise — backup and restore commands (README §Roadmap). First cut: a separate
utopiaoperator CLI withbackupimplemented andrestorestubbed.What's in this PR
crates/utopia-cli/— new crate, depends only onutopia-coreforAppConfig::load. Soutopia backupdoesn't pull in the server, extractor, chat loop, or any of the ~50 server modules.crates/utopia-cli/src/main.rs— 589 lines, hand-rolled arg parser, manifest schema with sha256 checksums,backupshells out topg_dump -Fcandtar,restoreparses flags and bails with a design-doc pointer.Cargo.toml— workspacemembers += ["crates/utopia-cli"].roadmap-proposals/backup-restore.md— design with 5 open questionsWhy a separate crate (not a subcommand of
utopia-server)utopia-server.utopia-serveris the largest crate in the workspace; making the operator compile it just to dump the database is a real CI / image-size cost.AppConfig::load()so connection info (UTOPIA_DATABASE_URL,UTOPIA_DATA_DIR,.env) is shared with the server. No duplicate config wiring.utopia backupWhat it does:
data_dirfromAppConfig.pg_dump -Fcto a temporary file under the current directory.-Fc(custom format) is the only formatpg_restoreconsumes.data/into a second temporary file.manifest.jsonwithschema_version,utopia_version,created_at, component paths/bytes, sha256 checksums.*.tar.gzcontainingmanifest.json+pg_dump.custom+ (optional)data/. Refuses to overwrite an existing archive.utopia restoreStubbed in this cut — parses flags, prints the plan, then
bail!s with a pointer to the design doc. The backup side is independently useful (operators want to take backups even before restore works) and the restore side has design questions that benefit from running backup in production first.Tests
8 unit tests, all pure (no live DB, no docker):
parses_backup_minimal—utopia backup --dry-runproduces aBackupArgswith all defaults.parses_backup_full— every flag set, every field populated.parses_restore_requires_from—--fromis mandatory on restore.parses_restore_full— every flag set, every field populated.rejects_unknown_subcommand—utopia frobnicatefails clearly.redact_url_host_keeps_userinfo_at_host—postgres://u:***@h/dbstays redacted on round-trip.redact_url_host_handles_no_at—postgres://h/dbredacts nothing (no userinfo).hex_encode_known_value—hex_encode(&[0xde, 0xad]) == "dead".Full workspace test: 799 passed, 0 failed.
Open questions for the maintainer
Full text in
.roadmap-proposals/backup-restore.md. In priority order:crates/utopia-cli/(this proposal) vs. abin/utopia.rsinsideutopia-server. Recommendation: separate crate.CREATEDB) vs. in-placepg_restore --clean. Recommendation: in-place--clean.postgresql-client? Recommendation: no — keep the runtime image minimal, ship a separateutopia-cliimage withpg_dumpandpg_restore. (Out of scope for this PR — lands the binary first.)UTOPIA_BACKUP_DIRbecome a new config knob for the default output location? Recommendation: yes, trivially.Out of scope (intentionally)
UTOPIA_BACKUP_DIRconfig (Q5).restorewill only readschema_version == current.utopia backup --output -toaws s3 cp - s3://…today.Checklist
Signed-off-by:in commit)cargo fmt --allclean (verified locally)cargo test -p utopia-cli8 passed, 0 failedcargo test --workspace799 passed, 0 failedcargo clippy -p utopia-cliclean (no warnings on the new crate)feat/instant-precision) unaffected — different branch, different files