Explorar el Código

Display a nicer error message when running the "recreate" action on a leftover temporary archive from a prior recreate run (#1053).

Dan Helfman hace 1 mes
padre
commit
a892a308bd
Se han modificado 4 ficheros con 86 adiciones y 15 borrados
  1. 2 0
      NEWS
  2. 22 9
      borgmatic/actions/recreate.py
  3. 1 0
      borgmatic/borg/recreate.py
  4. 61 6
      tests/unit/actions/test_recreate.py

+ 2 - 0
NEWS

@@ -1,6 +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.
  * #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).

+ 22 - 9
borgmatic/actions/recreate.py

@@ -1,6 +1,7 @@
 import logging
 
 import borgmatic.borg.recreate
+import borgmatic.borg.repo_list
 import borgmatic.config.validate
 from borgmatic.actions.pattern import collect_patterns, process_patterns
 
@@ -32,17 +33,29 @@ def run_recreate(
             collect_patterns(config), borgmatic.config.paths.get_working_directory(config)
         )
 
+        archive = borgmatic.borg.repo_list.resolve_archive_name(
+            repository['path'],
+            recreate_arguments.archive,
+            config,
+            local_borg_version,
+            global_arguments,
+            local_path,
+            remote_path,
+        )
+
+        if archive and archive.endswith('.recreate'):
+            if recreate_arguments.archive == 'latest':
+                raise ValueError(
+                    f'The latest archive "{archive}" is leftover from a prior recreate. Delete it first or select a different archive.'
+                )
+            else:
+                raise ValueError(
+                    f'The archive "{recreate_arguments.archive}" is leftover from a prior recreate. Select a different archive.'
+                )
+
         borgmatic.borg.recreate.recreate_archive(
             repository['path'],
-            borgmatic.borg.repo_list.resolve_archive_name(
-                repository['path'],
-                recreate_arguments.archive,
-                config,
-                local_borg_version,
-                global_arguments,
-                local_path,
-                remote_path,
-            ),
+            archive,
             config,
             local_borg_version,
             recreate_arguments,

+ 1 - 0
borgmatic/borg/recreate.py

@@ -32,6 +32,7 @@ def recreate_archive(
     exclude_flags = flags.make_exclude_flags(config)
     compression = config.get('compression', None)
     chunker_params = config.get('chunker_params', None)
+
     # Available recompress MODES: "if-different", "always", "never" (default)
     recompress = config.get('recompress', None)
 

+ 61 - 6
tests/unit/actions/test_recreate.py

@@ -1,3 +1,4 @@
+import pytest
 from flexmock import flexmock
 
 from borgmatic.actions import recreate as module
@@ -6,15 +7,19 @@ from borgmatic.actions import recreate as module
 def test_run_recreate_does_not_raise():
     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(
+        None
+    )
     flexmock(module.borgmatic.borg.recreate).should_receive('recreate_archive')
 
-    recreate_arguments = flexmock(repository=flexmock(), archive=None)
-
     module.run_recreate(
         repository={'path': 'repo'},
         config={},
         local_borg_version=None,
-        recreate_arguments=recreate_arguments,
+        recreate_arguments=flexmock(repository=flexmock(), archive=None),
         global_arguments=flexmock(),
         local_path=None,
         remote_path=None,
@@ -24,16 +29,66 @@ def test_run_recreate_does_not_raise():
 def test_run_recreate_with_archive_does_not_raise():
     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')
 
-    recreate_arguments = flexmock(repository=flexmock(), archive='test-archive')
-
     module.run_recreate(
         repository={'path': 'repo'},
         config={},
         local_borg_version=None,
-        recreate_arguments=recreate_arguments,
+        recreate_arguments=flexmock(repository=flexmock(), archive='test-archive'),
         global_arguments=flexmock(),
         local_path=None,
         remote_path=None,
     )
+
+
+def test_run_recreate_with_leftover_recreate_archive_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.recreate'
+    )
+    flexmock(module.borgmatic.borg.recreate).should_receive('recreate_archive')
+
+    with pytest.raises(ValueError):
+        module.run_recreate(
+            repository={'path': 'repo'},
+            config={},
+            local_borg_version=None,
+            recreate_arguments=flexmock(repository=flexmock(), archive='test-archive.recreate'),
+            global_arguments=flexmock(),
+            local_path=None,
+            remote_path=None,
+        )
+
+
+def test_run_recreate_with_latest_archive_resolving_to_leftover_recreate_archive_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.recreate'
+    )
+    flexmock(module.borgmatic.borg.recreate).should_receive('recreate_archive')
+
+    with pytest.raises(ValueError):
+        module.run_recreate(
+            repository={'path': 'repo'},
+            config={},
+            local_borg_version=None,
+            recreate_arguments=flexmock(repository=flexmock(), archive='latest'),
+            global_arguments=flexmock(),
+            local_path=None,
+            remote_path=None,
+        )