Browse Source

Fix the "source_directories_must_exist" option to work with relative "source_directories" paths when a "working_directory" is set (#905).

Dan Helfman 9 months ago
parent
commit
e0298685a1
3 changed files with 39 additions and 10 deletions
  1. 2 0
      NEWS
  2. 22 10
      borgmatic/borg/create.py
  3. 15 0
      tests/unit/borg/test_create.py

+ 2 - 0
NEWS

@@ -6,6 +6,8 @@
  * #900: Fix for a potential traceback (TypeError) during the handling of another error.
  * #904: Clarify the configuration reference about the "spot" check options:
    https://torsion.org/borgmatic/docs/reference/configuration/
+ * #905: Fix the "source_directories_must_exist" option to work with relative "source_directories"
+   paths when a "working_directory" is set.
  * Fix a regression in which the "color" option had no effect.
  * Add a recent contributors section to the documentation, because credit where credit's due! See:
    https://torsion.org/borgmatic/#recent-contributors

+ 22 - 10
borgmatic/borg/create.py

@@ -306,15 +306,25 @@ def collect_special_file_paths(
     )
 
 
-def check_all_source_directories_exist(source_directories):
+def check_all_source_directories_exist(source_directories, working_directory=None):
     '''
-    Given a sequence of source directories, check that they all exist. If any do not, raise an
-    exception.
+    Given a sequence of source directories and an optional working directory to serve as a prefix
+    for each (if it's a relative directory), check that the source directories all exist. If any do
+    not, raise an exception.
     '''
     missing_directories = [
         source_directory
         for source_directory in source_directories
-        if not all([os.path.exists(directory) for directory in expand_directory(source_directory)])
+        if not all(
+            [
+                os.path.exists(directory)
+                for directory in expand_directory(
+                    os.path.join(working_directory, source_directory)
+                    if working_directory
+                    else source_directory
+                )
+            ]
+        )
     ]
     if missing_directories:
         raise ValueError(f"Source directories do not exist: {', '.join(missing_directories)}")
@@ -342,8 +352,15 @@ def make_base_create_command(
     (base Borg create command flags, Borg create command positional arguments, open pattern file
     handle, open exclude file handle).
     '''
+    try:
+        working_directory = os.path.expanduser(config.get('working_directory'))
+    except TypeError:
+        working_directory = None
+
     if config.get('source_directories_must_exist', False):
-        check_all_source_directories_exist(config.get('source_directories'))
+        check_all_source_directories_exist(
+            config.get('source_directories'), working_directory=working_directory
+        )
 
     sources = deduplicate_directories(
         map_directories_to_devices(
@@ -445,11 +462,6 @@ def make_base_create_command(
         logger.warning(
             f'{repository_path}: Ignoring configured "read_special" value of false, as true is needed for database hooks.'
         )
-        try:
-            working_directory = os.path.expanduser(config.get('working_directory'))
-        except TypeError:
-            working_directory = None
-
         borg_environment = environment.make_environment(config)
 
         logger.debug(f'{repository_path}: Collecting special file paths')

+ 15 - 0
tests/unit/borg/test_create.py

@@ -1891,3 +1891,18 @@ def test_check_all_source_directories_exist_with_non_existent_directory_raises()
 
     with pytest.raises(ValueError):
         module.check_all_source_directories_exist(['foo'])
+
+
+def test_check_all_source_directories_exist_with_working_directory_applies_to_relative_source_directories():
+    flexmock(module).should_receive('expand_directory').with_args('/tmp/foo*').and_return(
+        ('/tmp/foo', '/tmp/food')
+    )
+    flexmock(module).should_receive('expand_directory').with_args('/root/bar').and_return(
+        ('/root/bar',)
+    )
+    flexmock(module.os.path).should_receive('exists').and_return(False)
+    flexmock(module.os.path).should_receive('exists').with_args('/tmp/foo').and_return(True)
+    flexmock(module.os.path).should_receive('exists').with_args('/tmp/food').and_return(True)
+    flexmock(module.os.path).should_receive('exists').with_args('/root/bar').and_return(True)
+
+    module.check_all_source_directories_exist(['foo*', '/root/bar'], working_directory='/tmp')