浏览代码

Fix extracting from remote repositories with working_directory defined

Benjamin Bock 2 月之前
父节点
当前提交
81a3a99578
共有 4 个文件被更改,包括 59 次插入10 次删除
  1. 1 3
      borgmatic/borg/extract.py
  2. 9 3
      borgmatic/config/validate.py
  3. 2 2
      tests/unit/borg/test_extract.py
  4. 47 2
      tests/unit/config/test_validate.py

+ 1 - 3
borgmatic/borg/extract.py

@@ -134,9 +134,7 @@ def extract_archive(
             # Make the repository path absolute so the destination directory used below via changing
             # the working directory doesn't prevent Borg from finding the repo. But also apply the
             # user's configured working directory (if any) to the repo path.
-            borgmatic.config.validate.normalize_repository_path(
-                os.path.join(working_directory or '', repository)
-            ),
+            borgmatic.config.validate.normalize_repository_path(repository, working_directory),
             archive,
             local_borg_version,
         )

+ 9 - 3
borgmatic/config/validate.py

@@ -138,16 +138,22 @@ def parse_configuration(config_filename, schema_filename, overrides=None, resolv
     return config, config_paths, logs
 
 
-def normalize_repository_path(repository):
+def normalize_repository_path(repository, base=None):
     '''
     Given a repository path, return the absolute path of it (for local repositories).
+    Optionally, use a base path for resolving relative paths, e.g. to the configured working directory.
     '''
     # A colon in the repository could mean that it's either a file:// URL or a remote repository.
     # If it's a remote repository, we don't want to normalize it. If it's a file:// URL, we do.
     if ':' not in repository:
-        return os.path.abspath(repository)
+        return (
+            os.path.abspath(os.path.join(base, repository)) if base else os.path.abspath(repository)
+        )
     elif repository.startswith('file://'):
-        return os.path.abspath(repository.partition('file://')[-1])
+        local_path = repository.partition('file://')[-1]
+        return (
+            os.path.abspath(os.path.join(base, local_path)) if base else os.path.abspath(local_path)
+        )
     else:
         return repository
 

+ 2 - 2
tests/unit/borg/test_extract.py

@@ -710,7 +710,7 @@ def test_extract_archive_uses_configured_working_directory_in_repo_path_and_dest
     )
     flexmock(module.borgmatic.config.validate).should_receive(
         'normalize_repository_path'
-    ).with_args('/working/dir/repo').and_return('/working/dir/repo').once()
+    ).with_args('repo', '/working/dir').and_return('/working/dir/repo').once()
 
     module.extract_archive(
         dry_run=False,
@@ -733,7 +733,7 @@ def test_extract_archive_uses_configured_working_directory_in_repo_path_when_des
     )
     flexmock(module.borgmatic.config.validate).should_receive(
         'normalize_repository_path'
-    ).with_args('/working/dir/repo').and_return('/working/dir/repo').once()
+    ).with_args('repo', '/working/dir').and_return('/working/dir/repo').once()
 
     module.extract_archive(
         dry_run=False,

+ 47 - 2
tests/unit/config/test_validate.py

@@ -94,13 +94,40 @@ def test_normalize_repository_path_passes_through_remote_repository():
     module.normalize_repository_path(repository) == repository
 
 
+def test_normalize_repository_path_passes_through_remote_repository_with_base_dir():
+    repository = 'example.org:test.borg'
+
+    flexmock(module.os.path).should_receive('abspath').never()
+    module.normalize_repository_path(repository, '/working') == repository
+
+
 def test_normalize_repository_path_passes_through_file_repository():
     repository = 'file:///foo/bar/test.borg'
-    flexmock(module.os.path).should_receive('abspath').and_return('/foo/bar/test.borg')
+    flexmock(module.os.path).should_receive('abspath').with_args('/foo/bar/test.borg').and_return(
+        '/foo/bar/test.borg'
+    )
 
     module.normalize_repository_path(repository) == '/foo/bar/test.borg'
 
 
+def test_normalize_repository_path_passes_through_absolute_file_repository_with_base_dir():
+    repository = 'file:///foo/bar/test.borg'
+    flexmock(module.os.path).should_receive('abspath').with_args('/foo/bar/test.borg').and_return(
+        '/foo/bar/test.borg'
+    )
+
+    module.normalize_repository_path(repository, '/working') == '/foo/bar/test.borg'
+
+
+def test_normalize_repository_path_resolves_relative_file_repository_with_base_dir():
+    repository = 'file://foo/bar/test.borg'
+    flexmock(module.os.path).should_receive('abspath').with_args(
+        '/working/foo/bar/test.borg'
+    ).and_return('/working/foo/bar/test.borg')
+
+    module.normalize_repository_path(repository, '/working') == '/working/foo/bar/test.borg'
+
+
 def test_normalize_repository_path_passes_through_absolute_repository():
     repository = '/foo/bar/test.borg'
     flexmock(module.os.path).should_receive('abspath').and_return(repository)
@@ -108,14 +135,32 @@ def test_normalize_repository_path_passes_through_absolute_repository():
     module.normalize_repository_path(repository) == repository
 
 
+def test_normalize_repository_path_passes_through_absolute_repository_with_base_dir():
+    repository = '/foo/bar/test.borg'
+    flexmock(module.os.path).should_receive('abspath').and_return(repository)
+
+    module.normalize_repository_path(repository, '/working') == repository
+
+
 def test_normalize_repository_path_resolves_relative_repository():
     repository = 'test.borg'
     absolute = '/foo/bar/test.borg'
-    flexmock(module.os.path).should_receive('abspath').and_return(absolute)
+    flexmock(module.os.path).should_receive('abspath').with_args(repository).and_return(absolute)
 
     module.normalize_repository_path(repository) == absolute
 
 
+def test_normalize_repository_path_resolves_relative_repository_with_base_dir():
+    repository = 'test.borg'
+    base = '/working'
+    absolute = '/working/test.borg'
+    flexmock(module.os.path).should_receive('abspath').with_args('/working/test.borg').and_return(
+        absolute
+    )
+
+    module.normalize_repository_path(repository, base) == absolute
+
+
 @pytest.mark.parametrize(
     'first,second,expected_result',
     (