fix: say why backup and restore do not apply to a native install

Both accepted a native install and then drove `docker compose` in a directory
with no compose file, so the user got "no configuration file provided" rather
than an explanation. They now refuse with what to do instead, and restore
refuses before it reads the archive or stops anything.
This commit is contained in:
Alex committed 2026-09-16 23:01:30 +01:00
1 parent 61f06fcce8
commit 501baf8aae
2 files changed
+20 -1

No files matched your search

+9 -1
View File
@@ -568,6 +568,10 @@ def backup(args, context: Optional[Context] = None) -> int:
env = _installed(directory)
if env is None:
return 1
if _mode(directory) == "native":
raise DeployError(
f"{directory} is a native install: its database and its files are not in Docker volumes, so there is nothing here to archive. Back up the PostgreSQL that POSTGRES_URI points at with pg_dump, and copy the indexes, inputs and vectors folders from the data home."
)
out_dir = Path(args.out).expanduser() if args.out else directory / "backups"
taken_at = datetime.now(timezone.utc)
@@ -657,13 +661,17 @@ def _restore_data(context: Context, directory: Path, archive: Path, volumes: lis
def restore(args, context: Optional[Context] = None) -> int:
"""Put a backup's database and data volumes back over this install."""
context = context or Context.default(args)
directory = stack.stack_dir(args.dir)
if _mode(directory) == "native":
raise DeployError(
f"{directory} is a native install: its database and its files are not in Docker volumes, so there is nothing here to archive. Back up the PostgreSQL that POSTGRES_URI points at with pg_dump, and copy the indexes, inputs and vectors folders from the data home. `docsgpt restore` puts back what `docsgpt backup` wrote for a Docker install."
)
archive = Path(args.archive).expanduser()
manifest = backup_format.read_manifest(archive)
backup_format.check_version(manifest, context.version, args.force)
# Everything the archive declares is checked here, while DocsGPT is still up.
volumes = backup_format.validate(archive, manifest)
directory = stack.stack_dir(args.dir)
env = _installed(directory)
if env is None:
return 1
+11
View File
@@ -238,6 +238,17 @@ class TestNativeLifecycle:
self._installed(tmp_path, FakeServices())
assert _run(["logs", "--dir", str(tmp_path)], _native_context()) == 0, "logs work in both modes"
def test_backup_says_why_there_is_nothing_to_archive(self, tmp_path):
"""Its data is not in Docker volumes, so compose would fail with no configuration file."""
self._installed(tmp_path, FakeServices())
with pytest.raises(DeployError, match="native install"):
_run(["backup", "--dir", str(tmp_path)], _native_context())
def test_restore_refuses_before_it_touches_anything(self, tmp_path):
self._installed(tmp_path, FakeServices())
with pytest.raises(DeployError, match="native install"):
_run(["restore", str(tmp_path / "any.tar.gz"), "--dir", str(tmp_path), "--yes"], _native_context())
class FakeLaunchctl:
"""launchctl, with a bootout that takes `unload_polls` polls to take effect."""