浏览代码

Fix "--repository" flag to accept relative paths.

Dan Helfman 5 年之前
父节点
当前提交
65cc4c9429
共有 4 个文件被更改,包括 77 次插入9 次删除
  1. 1 0
      NEWS
  2. 15 5
      borgmatic/commands/borgmatic.py
  3. 21 4
      borgmatic/config/validate.py
  4. 40 0
      tests/unit/config/test_validate.py

+ 1 - 0
NEWS

@@ -1,4 +1,5 @@
 1.4.18
+ * Fix "--repository" flag to accept relative paths.
  * #253: Mount whole repositories via "borgmatic mount" without any "--archive" flag.
 
 1.4.17

+ 15 - 5
borgmatic/commands/borgmatic.py

@@ -234,7 +234,9 @@ def run_actions(
             only_checks=arguments['check'].only,
         )
     if 'extract' in arguments:
-        if arguments['extract'].repository is None or repository == arguments['extract'].repository:
+        if arguments['extract'].repository is None or validate.repositories_match(
+            repository, arguments['extract'].repository
+        ):
             logger.info(
                 '{}: Extracting archive {}'.format(repository, arguments['extract'].archive)
             )
@@ -251,7 +253,9 @@ def run_actions(
                 progress=arguments['extract'].progress,
             )
     if 'mount' in arguments:
-        if arguments['mount'].repository is None or repository == arguments['mount'].repository:
+        if arguments['mount'].repository is None or validate.repositories_match(
+            repository, arguments['mount'].repository
+        ):
             if arguments['mount'].archive:
                 logger.info(
                     '{}: Mounting archive {}'.format(repository, arguments['mount'].archive)
@@ -278,7 +282,9 @@ def run_actions(
             mount_point=arguments['umount'].mount_point, local_path=local_path
         )
     if 'restore' in arguments:
-        if arguments['restore'].repository is None or repository == arguments['restore'].repository:
+        if arguments['restore'].repository is None or validate.repositories_match(
+            repository, arguments['restore'].repository
+        ):
             logger.info(
                 '{}: Restoring databases from archive {}'.format(
                     repository, arguments['restore'].archive
@@ -336,7 +342,9 @@ def run_actions(
                 global_arguments.dry_run,
             )
     if 'list' in arguments:
-        if arguments['list'].repository is None or repository == arguments['list'].repository:
+        if arguments['list'].repository is None or validate.repositories_match(
+            repository, arguments['list'].repository
+        ):
             logger.info('{}: Listing archives'.format(repository))
             json_output = borg_list.list_archives(
                 repository,
@@ -348,7 +356,9 @@ def run_actions(
             if json_output:
                 yield json.loads(json_output)
     if 'info' in arguments:
-        if arguments['info'].repository is None or repository == arguments['info'].repository:
+        if arguments['info'].repository is None or validate.repositories_match(
+            repository, arguments['info'].repository
+        ):
             logger.info('{}: Displaying summary info for archives'.format(repository))
             json_output = borg_info.display_archives_info(
                 repository,

+ 21 - 4
borgmatic/config/validate.py

@@ -1,4 +1,5 @@
 import logging
+import os
 
 import pkg_resources
 import pykwalify.core
@@ -112,6 +113,24 @@ def parse_configuration(config_filename, schema_filename):
     return parsed_result
 
 
+def normalize_repository_path(repository):
+    '''
+    Given a repository path, return the absolute path of it (for local repositories).
+    '''
+    # A colon in the repository indicates it's a remote repository. Bail.
+    if ':' in repository:
+        return repository
+
+    return os.path.abspath(repository)
+
+
+def repositories_match(first, second):
+    '''
+    Given two repository paths (relative and/or absolute), return whether they match.
+    '''
+    return normalize_repository_path(first) == normalize_repository_path(second)
+
+
 def guard_configuration_contains_repository(repository, configurations):
     '''
     Given a repository path and a dict mapping from config filename to corresponding parsed config
@@ -133,9 +152,7 @@ def guard_configuration_contains_repository(repository, configurations):
 
         if count > 1:
             raise ValueError(
-                'Can\'t determine which repository to use. Use --repository option to disambiguate'.format(
-                    repository
-                )
+                'Can\'t determine which repository to use. Use --repository option to disambiguate'
             )
 
         return
@@ -145,7 +162,7 @@ def guard_configuration_contains_repository(repository, configurations):
             config_repository
             for config in configurations.values()
             for config_repository in config['location']['repositories']
-            if repository == config_repository
+            if repositories_match(repository, config_repository)
         )
     )
 

+ 40 - 0
tests/unit/config/test_validate.py

@@ -1,4 +1,5 @@
 import pytest
+from flexmock import flexmock
 
 from borgmatic.config import validate as module
 
@@ -95,7 +96,38 @@ def test_remove_examples_strips_examples_from_sequence_of_maps():
     assert schema == {'seq': [{'map': {'foo': {'desc': 'thing'}}}]}
 
 
+def test_normalize_repository_path_passes_through_remote_repository():
+    repository = 'example.org:test.borg'
+
+    module.normalize_repository_path(repository) == repository
+
+
+def test_normalize_repository_path_passes_through_absolute_repository():
+    repository = '/foo/bar/test.borg'
+    flexmock(module.os.path).should_receive('abspath').and_return(repository)
+
+    module.normalize_repository_path(repository) == 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)
+
+    module.normalize_repository_path(repository) == absolute
+
+
+def test_repositories_match_does_not_raise():
+    flexmock(module).should_receive('normalize_repository_path')
+
+    module.repositories_match('foo', 'bar')
+
+
 def test_guard_configuration_contains_repository_does_not_raise_when_repository_in_config():
+    flexmock(module).should_receive('repositories_match').replace_with(
+        lambda first, second: first == second
+    )
+
     module.guard_configuration_contains_repository(
         repository='repo', configurations={'config.yaml': {'location': {'repositories': ['repo']}}}
     )
@@ -116,6 +148,10 @@ def test_guard_configuration_contains_repository_errors_when_repository_assumed_
 
 
 def test_guard_configuration_contains_repository_errors_when_repository_missing_from_config():
+    flexmock(module).should_receive('repositories_match').replace_with(
+        lambda first, second: first == second
+    )
+
     with pytest.raises(ValueError):
         module.guard_configuration_contains_repository(
             repository='nope',
@@ -124,6 +160,10 @@ def test_guard_configuration_contains_repository_errors_when_repository_missing_
 
 
 def test_guard_configuration_contains_repository_errors_when_repository_matches_config_twice():
+    flexmock(module).should_receive('repositories_match').replace_with(
+        lambda first, second: first == second
+    )
+
     with pytest.raises(ValueError):
         module.guard_configuration_contains_repository(
             repository='repo',