Преглед изворни кода

add support for rclone:// repositories (via borgstore)

Thomas Waldmann пре 8 месеци
родитељ
комит
bd6caf835d

+ 1 - 0
docs/quickstart.rst

@@ -411,6 +411,7 @@ Due to using the `borgstore` project, borg now also supports other kinds of
 
 - sftp: the borg client will directly talk to an sftp server.
   This does not require borg being installed on the sftp server.
+- rclone: the borg client will talk via rclone to cloud storage.
 - Others may come in the future, adding backends to `borgstore` is rather simple.
 
 Restoring a backup

+ 1 - 1
docs/usage/general/file-systems.rst.inc

@@ -24,7 +24,7 @@ Pros:
   and re-write segment files to free space.
 - In future, easier to adapt to other kinds of storage:
   borgstore's backends are quite simple to implement.
-  A ``sftp:`` backend already exists, cloud storage might be easy to add.
+  ``sftp:`` and ``rclone:`` backends already exists, others might be easy to add.
 - Parallel repository access with less locking is easier to implement.
 
 Cons:

+ 7 - 2
docs/usage/general/repository-urls.rst.inc

@@ -14,7 +14,7 @@ Note: you may also prepend a ``file://`` to a filesystem path to get URL style.
 
 **Remote repositories** accessed via ssh user@host:
 
-``ssh://user@host:port/path/to/repo`` - absolute path`
+``ssh://user@host:port/path/to/repo`` - absolute path
 
 ``ssh://user@host:port/./path/to/repo`` - path relative to current directory
 
@@ -22,10 +22,15 @@ Note: you may also prepend a ``file://`` to a filesystem path to get URL style.
 
 **Remote repositories** accessed via sftp:
 
-``sftp://user@host:port/path/to/repo`` - absolute path`
+``sftp://user@host:port/path/to/repo`` - absolute path
 
 For ssh and sftp URLs, the ``user@`` and ``:port`` parts are optional.
 
+**Remote repositories** accessed via rclone:
+
+``rclone://remote:path``
+
+
 If you frequently need the same repo URL, it is a good idea to set the
 ``BORG_REPO`` environment variable to set a default for the repo URL:
 

+ 1 - 1
pyproject.toml

@@ -30,7 +30,7 @@ classifiers = [
 ]
 license = {text="BSD"}
 dependencies = [
-  "borgstore ~= 0.0.1",
+  "borgstore ~= 0.0.4",
   "msgpack >=1.0.3, <=1.1.0",
   "packaging",
   "platformdirs >=3.0.0, <5.0.0; sys_platform == 'darwin'",  # for macOS: breaking changes in 3.0.0,

+ 1 - 1
src/borg/archiver/_common.py

@@ -46,7 +46,7 @@ def get_repository(
             args=args,
         )
 
-    elif location.proto in ("sftp", "file") and not v1_or_v2:  # stuff directly supported by borgstore
+    elif location.proto in ("sftp", "file", "rclone") and not v1_or_v2:  # stuff directly supported by borgstore
         repository = Repository(
             location,
             create=create,

+ 14 - 1
src/borg/helpers/parseformat.py

@@ -467,6 +467,14 @@ class Location:
         re.VERBOSE,
     )  # path
 
+    rclone_re = re.compile(
+        r"""
+        (?P<proto>rclone)://                                    # rclone://
+        (?P<path>(.*))
+        """,
+        re.VERBOSE,
+    )  # path
+
     socket_re = re.compile(
         r"""
         (?P<proto>socket)://                                    # socket://
@@ -546,6 +554,11 @@ class Location:
             self.port = m.group("port") and int(m.group("port")) or None
             self.path = normpath_special(m.group("path"))
             return True
+        m = self.rclone_re.match(text)
+        if m:
+            self.proto = m.group("proto")
+            self.path = m.group("path")
+            return True
         m = self.file_re.match(text)
         if m:
             self.proto = m.group("proto")
@@ -575,7 +588,7 @@ class Location:
 
     def to_key_filename(self):
         name = re.sub(r"[^\w]", "_", self.path).strip("_")
-        if self.proto not in ("file", "socket"):
+        if self.proto not in ("file", "socket", "rclone"):
             name = re.sub(r"[^\w]", "_", self.host) + "__" + name
         if len(name) > 100:
             # Limit file names to some reasonable length. Most file systems

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

@@ -187,6 +187,14 @@ class TestLocationWithoutEnv:
             "host='2a02:0001:0002:0003:0004:0005:0006:0007', port=1234, path='/some/path')"
         )
 
+    def test_rclone(self, monkeypatch, keys_dir):
+        monkeypatch.delenv("BORG_REPO", raising=False)
+        assert (
+            repr(Location("rclone://remote:path"))
+            == "Location(proto='rclone', user=None, host=None, port=None, path='remote:path')"
+        )
+        assert Location("rclone://remote:path").to_key_filename() == keys_dir + "remote_path"
+
     def test_sftp(self, monkeypatch, keys_dir):
         monkeypatch.delenv("BORG_REPO", raising=False)
         assert (