From d99aff1276de3e4e3c230cba74a72e4896f98d73 Mon Sep 17 00:00:00 2001 From: Benedikt Neuffer Date: Mon, 6 Mar 2017 20:46:03 +0100 Subject: [PATCH] ipv6 address support also: Location: more informative exception when parsing fails --- src/borg/helpers.py | 10 ++++++--- src/borg/testsuite/helpers.py | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/borg/helpers.py b/src/borg/helpers.py index a93ba710c..2f4a33790 100644 --- a/src/borg/helpers.py +++ b/src/borg/helpers.py @@ -814,7 +814,7 @@ class Location: ssh_re = re.compile(r""" (?Pssh):// # ssh:// """ + optional_user_re + r""" # user@ (optional) - (?P[^:/]+)(?::(?P\d+))? # host or host:port + (?P([^:/]+|\[[0-9a-fA-F:.]+\]))(?::(?P\d+))? # host or host:port or [ipv6] or [ipv6]:port """ + abs_path_re + optional_archive_re, re.VERBOSE) # path or path::archive file_re = re.compile(r""" @@ -825,7 +825,7 @@ class Location: scp_re = re.compile(r""" ( """ + optional_user_re + r""" # user@ (optional) - (?P[^:/]+): # host: (don't match / in host to disambiguate from file:) + (?P([^:/]+|\[[0-9a-fA-F:.]+\])): # host: (don't match / or [ipv6] in host to disambiguate from file:) )? # user@host: part is optional """ + scp_path_re + optional_archive_re, re.VERBOSE) # path with optional archive @@ -841,7 +841,7 @@ class Location: def __init__(self, text=''): self.orig = text if not self.parse(self.orig): - raise ValueError + raise ValueError('Location: parse failed: %s' % self.orig) def parse(self, text): text = replace_placeholders(text) @@ -872,6 +872,8 @@ class Location: self.proto = m.group('proto') self.user = m.group('user') self.host = m.group('host') + if self.host is not None: + self.host = self.host.lstrip('[').rstrip(']') self.port = m.group('port') and int(m.group('port')) or None self.path = normpath_special(m.group('path')) self.archive = m.group('archive') @@ -886,6 +888,8 @@ class Location: if m: self.user = m.group('user') self.host = m.group('host') + if isinstance(self.host, str): + self.host = self.host.lstrip('[').rstrip(']') self.path = normpath_special(m.group('path')) self.archive = m.group('archive') self.proto = self.host and 'ssh' or 'file' diff --git a/src/borg/testsuite/helpers.py b/src/borg/testsuite/helpers.py index ff6b5efe6..7ce22dc2d 100644 --- a/src/borg/testsuite/helpers.py +++ b/src/borg/testsuite/helpers.py @@ -58,6 +58,30 @@ class TestLocationWithoutEnv: "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path', archive=None)" assert repr(Location('ssh://user@host/some/path')) == \ "Location(proto='ssh', user='user', host='host', port=None, path='/some/path', archive=None)" + assert repr(Location('ssh://user@[::]:1234/some/path::archive')) == \ + "Location(proto='ssh', user='user', host='::', port=1234, path='/some/path', archive='archive')" + assert repr(Location('ssh://user@[::]:1234/some/path')) == \ + "Location(proto='ssh', user='user', host='::', port=1234, path='/some/path', archive=None)" + assert repr(Location('ssh://user@[::]/some/path')) == \ + "Location(proto='ssh', user='user', host='::', port=None, path='/some/path', archive=None)" + assert repr(Location('ssh://user@[2001:db8::]:1234/some/path::archive')) == \ + "Location(proto='ssh', user='user', host='2001:db8::', port=1234, path='/some/path', archive='archive')" + assert repr(Location('ssh://user@[2001:db8::]:1234/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::', port=1234, path='/some/path', archive=None)" + assert repr(Location('ssh://user@[2001:db8::]/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::', port=None, path='/some/path', archive=None)" + assert repr(Location('ssh://user@[2001:db8::c0:ffee]:1234/some/path::archive')) == \ + "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=1234, path='/some/path', archive='archive')" + assert repr(Location('ssh://user@[2001:db8::c0:ffee]:1234/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=1234, path='/some/path', archive=None)" + assert repr(Location('ssh://user@[2001:db8::c0:ffee]/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=None, path='/some/path', archive=None)" + assert repr(Location('ssh://user@[2001:db8::192.0.2.1]:1234/some/path::archive')) == \ + "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=1234, path='/some/path', archive='archive')" + assert repr(Location('ssh://user@[2001:db8::192.0.2.1]:1234/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=1234, path='/some/path', archive=None)" + assert repr(Location('ssh://user@[2001:db8::192.0.2.1]/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=None, path='/some/path', archive=None)" def test_file(self, monkeypatch): monkeypatch.delenv('BORG_REPO', raising=False) @@ -72,6 +96,22 @@ class TestLocationWithoutEnv: "Location(proto='ssh', user='user', host='host', port=None, path='/some/path', archive='archive')" assert repr(Location('user@host:/some/path')) == \ "Location(proto='ssh', user='user', host='host', port=None, path='/some/path', archive=None)" + assert repr(Location('user@[::]:/some/path::archive')) == \ + "Location(proto='ssh', user='user', host='::', port=None, path='/some/path', archive='archive')" + assert repr(Location('user@[::]:/some/path')) == \ + "Location(proto='ssh', user='user', host='::', port=None, path='/some/path', archive=None)" + assert repr(Location('user@[2001:db8::]:/some/path::archive')) == \ + "Location(proto='ssh', user='user', host='2001:db8::', port=None, path='/some/path', archive='archive')" + assert repr(Location('user@[2001:db8::]:/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::', port=None, path='/some/path', archive=None)" + assert repr(Location('user@[2001:db8::c0:ffee]:/some/path::archive')) == \ + "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=None, path='/some/path', archive='archive')" + assert repr(Location('user@[2001:db8::c0:ffee]:/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=None, path='/some/path', archive=None)" + assert repr(Location('user@[2001:db8::192.0.2.1]:/some/path::archive')) == \ + "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=None, path='/some/path', archive='archive')" + assert repr(Location('user@[2001:db8::192.0.2.1]:/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=None, path='/some/path', archive=None)" def test_smb(self, monkeypatch): monkeypatch.delenv('BORG_REPO', raising=False)