浏览代码

if --(other-)repo option is not given, use default from environment

remove tests composing a repo+archive location with repo from env
and location from cli.
Thomas Waldmann 3 年之前
父节点
当前提交
0f0cd24354
共有 3 个文件被更改,包括 29 次插入113 次删除
  1. 10 7
      src/borg/archiver.py
  2. 19 26
      src/borg/helpers/parseformat.py
  3. 0 80
      src/borg/testsuite/helpers.py

+ 10 - 7
src/borg/archiver.py

@@ -174,8 +174,10 @@ def with_repository(fake=False, invert_fake=False, create=False, lock=True,
     def decorator(method):
         @functools.wraps(method)
         def wrapper(self, args, **kwargs):
+            location = getattr(args, 'location')
+            if not location.valid:  # location always must be given
+                raise Error('missing repository, please use --repo or BORG_REPO env var!')
             lock = getattr(args, 'lock', _lock)
-            location = args.location  # note: 'location' must be always present in args
             append_only = getattr(args, 'append_only', False)
             storage_quota = getattr(args, 'storage_quota', None)
             make_parent_dirs = getattr(args, 'make_parent_dirs', False)
@@ -220,8 +222,8 @@ def with_other_repository(manifest=False, key=False, cache=False, compatibility=
     def decorator(method):
         @functools.wraps(method)
         def wrapper(self, args, **kwargs):
-            location = getattr(args, 'other_location', None)
-            if location is None:  # nothing to do
+            location = getattr(args, 'other_location')
+            if not location.valid:  # nothing to do
                 return method(self, args, **kwargs)
 
             repository = get_repository(location, create=False, exclusive=True,
@@ -3203,8 +3205,9 @@ class Archiver:
                                    'compatible file can be generated by suffixing FILE with ".pyprof".')
             add_common_option('--rsh', metavar='RSH', dest='rsh',
                               help="Use this command to connect to the 'borg serve' process (default: 'ssh')")
-            add_common_option('--repo', metavar='REPO', dest='location', type=location_validator(),
-                              help="repository to use")  # XXXYYY
+            add_common_option('--repo', metavar='REPO', dest='location',
+                              type=location_validator(other=False), default=Location(other=False),
+                              help="repository to use")
 
         def define_exclude_and_patterns(add_option, *, tag_files=False, strip_components=False):
             add_option('-e', '--exclude', metavar='PATTERN', dest='patterns',
@@ -4165,7 +4168,7 @@ class Archiver:
         subparser.add_argument('-n', '--dry-run', dest='dry_run', action='store_true',
                                help='do not change repository, just check')
         subparser.add_argument('--other-repo', metavar='SRC_REPOSITORY', dest='other_location',
-                               type=location_validator(other=True),
+                               type=location_validator(other=True), default=Location(other=True),
                                help='source repository')
         define_archive_filters_group(subparser)
 
@@ -4502,7 +4505,7 @@ class Archiver:
                                           help='initialize empty repository')
         subparser.set_defaults(func=self.do_init)
         subparser.add_argument('--other-repo', metavar='SRC_REPOSITORY', dest='other_location',
-                               type=location_validator(other=True),
+                               type=location_validator(other=True), default=Location(other=True),
                                help='reuse the key material from the other repository')
         subparser.add_argument('-e', '--encryption', metavar='MODE', dest='encryption', required=True,
                                choices=key_argument_names(),

+ 19 - 26
src/borg/helpers/parseformat.py

@@ -365,15 +365,6 @@ class Location:
     local_re = re.compile(
         local_path_re + optional_archive_re, re.VERBOSE)    # local path with optional archive
 
-    # get the repo from BORG_REPO env and the optional archive from param.
-    # if the syntax requires giving REPOSITORY (see "borg mount"),
-    # use "::" to let it use the env var.
-    # if REPOSITORY argument is optional, it'll automatically use the env.
-    env_re = re.compile(r"""                                # the repo part is fetched from BORG_REPO
-        (?:::$)                                             # just "::" is ok (when a pos. arg is required, no archive)
-        |                                                   # or
-        """ + optional_archive_re, re.VERBOSE)              # archive name (optional, may be empty)
-
     win_file_re = re.compile(r"""
         (?:file://)?                                        # optional file protocol
         (?P<path>
@@ -384,27 +375,29 @@ class Location:
 
     def __init__(self, text='', overrides={}, other=False):
         self.repo_env_var = 'BORG_OTHER_REPO' if other else 'BORG_REPO'
-        if not self.parse(text, overrides):
-            raise ValueError('Invalid location format: "%s"' % self.processed)
+        self.valid = False
+        self.proto = None
+        self.user = None
+        self._host = None
+        self.port = None
+        self.path = None
+        self.archive = None
+        self.parse(text, overrides)
 
     def parse(self, text, overrides={}):
+        if not text:
+            # we did not get a text to parse, so we try to fetch from the environment
+            text = os.environ.get(self.repo_env_var)
+            if text is None:
+                return
+
         self.raw = text  # as given by user, might contain placeholders
-        self.processed = text = replace_placeholders(text, overrides)  # after placeholder replacement
-        valid = self._parse(text)
+        self.processed = replace_placeholders(self.raw, overrides)  # after placeholder replacement
+        valid = self._parse(self.processed)
         if valid:
-            return True
-        m = self.env_re.match(text)
-        if not m:
-            return False
-        repo_raw = os.environ.get(self.repo_env_var)
-        if repo_raw is None:
-            return False
-        repo = replace_placeholders(repo_raw, overrides)
-        valid = self._parse(repo)
-        self.archive = m.group('archive')
-        self.raw = repo_raw if not self.archive else repo_raw + self.raw
-        self.processed = repo if not self.archive else f'{repo}::{self.archive}'
-        return valid
+            self.valid = True
+        else:
+            raise ValueError('Invalid location format: "%s"' % self.processed)
 
     def _parse(self, text):
         def normpath_special(p):

+ 0 - 80
src/borg/testsuite/helpers.py

@@ -166,15 +166,6 @@ class TestLocationWithoutEnv:
         assert repr(Location('path::archive-{utcnow}').with_timestamp(datetime(2002, 9, 19, tzinfo=timezone.utc))) == \
             "Location(proto='file', user=None, host=None, port=None, path='path', archive='archive-2002-09-19T00:00:00')"
 
-    def test_underspecified(self, monkeypatch):
-        monkeypatch.delenv('BORG_REPO', raising=False)
-        with pytest.raises(ValueError):
-            Location('::archive')
-        with pytest.raises(ValueError):
-            Location('::')
-        with pytest.raises(ValueError):
-            Location()
-
     def test_no_slashes(self, monkeypatch):
         monkeypatch.delenv('BORG_REPO', raising=False)
         with pytest.raises(ValueError):
@@ -213,77 +204,6 @@ class TestLocationWithoutEnv:
         assert loc_without_archive.processed == "ssh://user@host:1234/repos/%s" % hostname
 
 
-class TestLocationWithEnv:
-    def test_ssh(self, monkeypatch):
-        monkeypatch.setenv('BORG_REPO', 'ssh://user@host:1234/some/path')
-        assert repr(Location('::archive')) == \
-            "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path', archive='archive')"
-        assert repr(Location('::')) == \
-            "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path', archive=None)"
-        assert repr(Location()) == \
-               "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path', archive=None)"
-
-    def test_ssh_placeholder(self, monkeypatch):
-        from borg.platform import hostname
-        monkeypatch.setenv('BORG_REPO', 'ssh://user@host:1234/{hostname}')
-        assert repr(Location('::archive')) == \
-            f"Location(proto='ssh', user='user', host='host', port=1234, path='/{hostname}', archive='archive')"
-        assert repr(Location('::')) == \
-            f"Location(proto='ssh', user='user', host='host', port=1234, path='/{hostname}', archive=None)"
-        assert repr(Location()) == \
-            f"Location(proto='ssh', user='user', host='host', port=1234, path='/{hostname}', archive=None)"
-
-    def test_file(self, monkeypatch):
-        monkeypatch.setenv('BORG_REPO', 'file:///some/path')
-        assert repr(Location('::archive')) == \
-            "Location(proto='file', user=None, host=None, port=None, path='/some/path', archive='archive')"
-        assert repr(Location('::')) == \
-            "Location(proto='file', user=None, host=None, port=None, path='/some/path', archive=None)"
-        assert repr(Location()) == \
-               "Location(proto='file', user=None, host=None, port=None, path='/some/path', archive=None)"
-
-    def test_folder(self, monkeypatch):
-        monkeypatch.setenv('BORG_REPO', 'path')
-        assert repr(Location('::archive')) == \
-            "Location(proto='file', user=None, host=None, port=None, path='path', archive='archive')"
-        assert repr(Location('::')) == \
-            "Location(proto='file', user=None, host=None, port=None, path='path', archive=None)"
-        assert repr(Location()) == \
-               "Location(proto='file', user=None, host=None, port=None, path='path', archive=None)"
-
-    def test_abspath(self, monkeypatch):
-        monkeypatch.setenv('BORG_REPO', '/some/absolute/path')
-        assert repr(Location('::archive')) == \
-            "Location(proto='file', user=None, host=None, port=None, path='/some/absolute/path', archive='archive')"
-        assert repr(Location('::')) == \
-            "Location(proto='file', user=None, host=None, port=None, path='/some/absolute/path', archive=None)"
-        assert repr(Location()) == \
-               "Location(proto='file', user=None, host=None, port=None, path='/some/absolute/path', archive=None)"
-
-    def test_relpath(self, monkeypatch):
-        monkeypatch.setenv('BORG_REPO', 'some/relative/path')
-        assert repr(Location('::archive')) == \
-            "Location(proto='file', user=None, host=None, port=None, path='some/relative/path', archive='archive')"
-        assert repr(Location('::')) == \
-            "Location(proto='file', user=None, host=None, port=None, path='some/relative/path', archive=None)"
-        assert repr(Location()) == \
-               "Location(proto='file', user=None, host=None, port=None, path='some/relative/path', archive=None)"
-
-    def test_with_colons(self, monkeypatch):
-        monkeypatch.setenv('BORG_REPO', '/abs/path:w:cols')
-        assert repr(Location('::arch:col')) == \
-            "Location(proto='file', user=None, host=None, port=None, path='/abs/path:w:cols', archive='arch:col')"
-        assert repr(Location('::')) == \
-               "Location(proto='file', user=None, host=None, port=None, path='/abs/path:w:cols', archive=None)"
-        assert repr(Location()) == \
-               "Location(proto='file', user=None, host=None, port=None, path='/abs/path:w:cols', archive=None)"
-
-    def test_no_slashes(self, monkeypatch):
-        monkeypatch.setenv('BORG_REPO', '/some/absolute/path')
-        with pytest.raises(ValueError):
-            Location('::archive_name_with/slashes/is_invalid')
-
-
 class FormatTimedeltaTestCase(BaseTestCase):
 
     def test(self):