mirror of
https://github.com/borgbackup/borg.git
synced 2026-06-11 01:41:57 -04:00
support "rest:" repository URLs, fixes #9593
That is borgstore's REST http over stdio (over ssh, if a host is given).
This commit is contained in:
parent
4d9369f897
commit
39ac734b9c
4 changed files with 95 additions and 3 deletions
|
|
@ -12,7 +12,13 @@ expanded by your shell).
|
|||
|
||||
Note: You may also prepend ``file://`` to a filesystem path to use URL style.
|
||||
|
||||
**Remote repositories** accessed via SSH user@host:
|
||||
**Remote repositories** accessed via SSH user@host (REST http over stdio):
|
||||
|
||||
``rest://user@host:port//abs/path/to/repo`` — absolute path
|
||||
|
||||
``rest://user@host:port/rel/path/to/repo`` — path relative to the current directory
|
||||
|
||||
**Remote repositories** accessed via SSH user@host (legacy borg RPC protocol):
|
||||
|
||||
``ssh://user@host:port//abs/path/to/repo`` — absolute path
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ def get_repository(location, *, create, exclusive, lock_wait, lock, args, v1_leg
|
|||
)
|
||||
|
||||
elif (
|
||||
location.proto in ("sftp", "file", "http", "https", "rclone", "s3", "b2") and not v1_legacy
|
||||
location.proto in ("rest", "sftp", "file", "http", "https", "rclone", "s3", "b2") and not v1_legacy
|
||||
): # stuff directly supported by borgstore
|
||||
repository = Repository(location, create=create, exclusive=exclusive, lock_wait=lock_wait, lock=lock)
|
||||
|
||||
|
|
|
|||
|
|
@ -552,6 +552,19 @@ class Location:
|
|||
re.VERBOSE,
|
||||
)
|
||||
|
||||
# REST http via stdio (via ssh, if host given):
|
||||
rest_re = re.compile(
|
||||
r"(?P<proto>(rest))://"
|
||||
+ r"("
|
||||
+ optional_user_re
|
||||
+ host_re
|
||||
+ optional_port_re
|
||||
+ r")?"
|
||||
+ r"/" # this is the separator, not part of the path!
|
||||
+ abs_or_rel_path_re,
|
||||
re.VERBOSE,
|
||||
)
|
||||
|
||||
# BorgStore REST server
|
||||
# (http|https)://user:pass@host:port/
|
||||
http_re = re.compile(
|
||||
|
|
@ -624,6 +637,14 @@ class Location:
|
|||
|
||||
def _parse(self, text):
|
||||
m = self.ssh_or_sftp_re.match(text)
|
||||
if m:
|
||||
self.proto = m.group("proto")
|
||||
self.user = m.group("user")
|
||||
self._host = m.group("host")
|
||||
self.port = m.group("port") and int(m.group("port")) or None
|
||||
self.path = os.path.normpath(m.group("path"))
|
||||
return True
|
||||
m = self.rest_re.match(text)
|
||||
if m:
|
||||
self.proto = m.group("proto")
|
||||
self.user = m.group("user")
|
||||
|
|
@ -692,7 +713,7 @@ class Location:
|
|||
return self.path
|
||||
if self.proto == "rclone":
|
||||
return f"{self.proto}:{self.path}"
|
||||
if self.proto in ("sftp", "ssh", "s3", "b2", "http", "https"):
|
||||
if self.proto in ("rest", "sftp", "ssh", "s3", "b2", "http", "https"):
|
||||
return (
|
||||
f"{self.proto}://"
|
||||
f"{(self.user + '@') if self.user else ''}"
|
||||
|
|
|
|||
|
|
@ -133,6 +133,71 @@ class TestLocationWithoutEnv:
|
|||
"host='2a02:0001:0002:0003:0004:0005:0006:0007', port=1234, path='relative/path')"
|
||||
)
|
||||
|
||||
def test_rest(self, monkeypatch):
|
||||
monkeypatch.delenv("BORG_REPO", raising=False)
|
||||
assert (
|
||||
repr(Location("rest://user@host:1234//absolute/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='host', port=1234, path='/absolute/path')"
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@host:1234/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='host', port=1234, path='relative/path')"
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@host/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='host', port=None, path='relative/path')"
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@[::]:1234/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='::', port=1234, path='relative/path')"
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@[::]/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='::', port=None, path='relative/path')"
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@[2001:db8::]:1234/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='2001:db8::', port=1234, path='relative/path')"
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@[2001:db8::]/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='2001:db8::', port=None, path='relative/path')"
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@[2001:db8::c0:ffee]:1234/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='2001:db8::c0:ffee', port=1234, path='relative/path')" # noqa: E501
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@[2001:db8::c0:ffee]/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='2001:db8::c0:ffee', port=None, path='relative/path')" # noqa: E501
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@[2001:db8::192.0.2.1]:1234/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='2001:db8::192.0.2.1', port=1234, path='relative/path')" # noqa: E501
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@[2001:db8::192.0.2.1]/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, host='2001:db8::192.0.2.1', port=None, path='relative/path')" # noqa: E501
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@[2a02:0001:0002:0003:0004:0005:0006:0007]/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, "
|
||||
"host='2a02:0001:0002:0003:0004:0005:0006:0007', port=None, path='relative/path')"
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest://user@[2a02:0001:0002:0003:0004:0005:0006:0007]:1234/relative/path"))
|
||||
== "Location(proto='rest', user='user', pass=None, "
|
||||
"host='2a02:0001:0002:0003:0004:0005:0006:0007', port=1234, path='relative/path')"
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest:///relative/path"))
|
||||
== "Location(proto='rest', user=None, pass=None, host=None, port=None, path='relative/path')"
|
||||
)
|
||||
assert (
|
||||
repr(Location("rest:////absolute/path"))
|
||||
== "Location(proto='rest', user=None, pass=None, host=None, port=None, path='/absolute/path')"
|
||||
)
|
||||
|
||||
def test_s3(self, monkeypatch):
|
||||
monkeypatch.delenv("BORG_REPO", raising=False)
|
||||
assert (
|
||||
|
|
|
|||
Loading…
Reference in a new issue