2
0
Эх сурвалжийг харах

Display a nicer error message when the "recreate" action encounters an archive that already exists (#1053).

Dan Helfman 1 сар өмнө
parent
commit
f27a96e22d

+ 2 - 2
NEWS

@@ -1,8 +1,8 @@
 2.0.2.dev0
  * #1035: Document potential performance issues and workarounds with the ZFS, Btrfs, and LVM hooks:
    https://torsion.org/borgmatic/docs/how-to/snapshot-your-filesystems/
- * #1053: Display a nicer error message when running the "recreate" action on a leftover temporary
-   archive from a prior recreate run.
+ * #1053: Display a nicer error message when the "recreate" action encounters an archive that
+   already exists.
  * #1059: Fix a regression in which soft failure exit codes in command hooks were not respected.
  * #1060: Fix action command hooks getting run too many times when multiple borgmatic actions are
    executed (implicitly or explicitly).

+ 29 - 11
borgmatic/actions/recreate.py

@@ -1,5 +1,7 @@
 import logging
+import subprocess
 
+import borgmatic.borg.info
 import borgmatic.borg.recreate
 import borgmatic.borg.repo_list
 import borgmatic.config.validate
@@ -8,6 +10,9 @@ from borgmatic.actions.pattern import collect_patterns, process_patterns
 logger = logging.getLogger(__name__)
 
 
+BORG_EXIT_CODE_ARCHIVE_ALREADY_EXISTS = 30
+
+
 def run_recreate(
     repository,
     config,
@@ -53,14 +58,27 @@ def run_recreate(
                     f'The archive "{recreate_arguments.archive}" is leftover from a prior recreate. Select a different archive.'
                 )
 
-        borgmatic.borg.recreate.recreate_archive(
-            repository['path'],
-            archive,
-            config,
-            local_borg_version,
-            recreate_arguments,
-            global_arguments,
-            local_path=local_path,
-            remote_path=remote_path,
-            patterns=processed_patterns,
-        )
+        try:
+            borgmatic.borg.recreate.recreate_archive(
+                repository['path'],
+                archive,
+                config,
+                local_borg_version,
+                recreate_arguments,
+                global_arguments,
+                local_path=local_path,
+                remote_path=remote_path,
+                patterns=processed_patterns,
+            )
+        except subprocess.CalledProcessError as error:
+            if error.returncode == BORG_EXIT_CODE_ARCHIVE_ALREADY_EXISTS:
+                if recreate_arguments.target:
+                    raise ValueError(
+                        f'The archive "{recreate_arguments.target}" already exists. Delete it first or set a different target archive name.'
+                    )
+                elif archive:
+                    raise ValueError(
+                        f'The archive "{archive}.recreate" is leftover from a prior recreate. Delete it first or select a different archive.'
+                    )
+
+            raise

+ 88 - 0
tests/unit/actions/test_recreate.py

@@ -92,3 +92,91 @@ def test_run_recreate_with_latest_archive_resolving_to_leftover_recreate_archive
             local_path=None,
             remote_path=None,
         )
+
+
+def test_run_recreate_with_archive_already_exists_error_raises():
+    flexmock(module.logger).answer = lambda message: None
+    flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
+    flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
+        flexmock()
+    )
+    flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
+        'test-archive'
+    )
+    flexmock(module.borgmatic.borg.recreate).should_receive('recreate_archive').and_raise(
+        module.subprocess.CalledProcessError(
+            returncode=module.BORG_EXIT_CODE_ARCHIVE_ALREADY_EXISTS,
+            cmd='borg recreate or whatever',
+        )
+    )
+
+    with pytest.raises(ValueError):
+        module.run_recreate(
+            repository={'path': 'repo'},
+            config={},
+            local_borg_version=None,
+            recreate_arguments=flexmock(repository=flexmock(), archive='test-archive', target=None),
+            global_arguments=flexmock(),
+            local_path=None,
+            remote_path=None,
+        )
+
+
+def test_run_recreate_with_target_and_archive_already_exists_error_raises():
+    flexmock(module.logger).answer = lambda message: None
+    flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
+    flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
+        flexmock()
+    )
+    flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
+        'test-archive'
+    )
+    flexmock(module.borgmatic.borg.recreate).should_receive('recreate_archive').and_raise(
+        module.subprocess.CalledProcessError(
+            returncode=module.BORG_EXIT_CODE_ARCHIVE_ALREADY_EXISTS,
+            cmd='borg recreate or whatever',
+        )
+    )
+
+    with pytest.raises(ValueError):
+        module.run_recreate(
+            repository={'path': 'repo'},
+            config={},
+            local_borg_version=None,
+            recreate_arguments=flexmock(
+                repository=flexmock(), archive='test-archive', target='target-archive'
+            ),
+            global_arguments=flexmock(),
+            local_path=None,
+            remote_path=None,
+        )
+
+
+def test_run_recreate_with_other_called_process_error_passes_it_through():
+    flexmock(module.logger).answer = lambda message: None
+    flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
+    flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
+        flexmock()
+    )
+    flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
+        'test-archive'
+    )
+    flexmock(module.borgmatic.borg.recreate).should_receive('recreate_archive').and_raise(
+        module.subprocess.CalledProcessError(
+            returncode=1,
+            cmd='borg recreate or whatever',
+        )
+    )
+
+    with pytest.raises(module.subprocess.CalledProcessError):
+        module.run_recreate(
+            repository={'path': 'repo'},
+            config={},
+            local_borg_version=None,
+            recreate_arguments=flexmock(
+                repository=flexmock(), archive='test-archive', target='target-archive'
+            ),
+            global_arguments=flexmock(),
+            local_path=None,
+            remote_path=None,
+        )