Bläddra i källkod

new sftp: URLs, see #8372

sftp://user@host:port/rel/path
sftp://user@host:port//abs/path
Thomas Waldmann 7 månader sedan
förälder
incheckning
d60303eb8c
2 ändrade filer med 26 tillägg och 5 borttagningar
  1. 16 2
      src/borg/helpers/parseformat.py
  2. 10 3
      src/borg/testsuite/helpers_test.py

+ 16 - 2
src/borg/helpers/parseformat.py

@@ -431,6 +431,12 @@ class Location:
         (?P<path>(/([^:]|(:(?!:)))+))                       # start with /, then any chars, but no "::"
         (?P<path>(/([^:]|(:(?!:)))+))                       # start with /, then any chars, but no "::"
         """
         """
 
 
+    # path must not contain :: (it ends at :: or string end), but may contain single colons.
+    # it may or may not start with a /.
+    path_re = r"""
+        (?P<path>(([^:]|(:(?!:)))+))                        # any chars, but no "::"
+        """
+
     # host NAME, or host IP ADDRESS (v4 or v6, v6 must be in square brackets)
     # host NAME, or host IP ADDRESS (v4 or v6, v6 must be in square brackets)
     host_re = r"""
     host_re = r"""
         (?P<host>(
         (?P<host>(
@@ -461,9 +467,9 @@ class Location:
         + optional_user_re
         + optional_user_re
         + host_re
         + host_re
         + r"""                 # user@  (optional), host name or address
         + r"""                 # user@  (optional), host name or address
-        (?::(?P<port>\d+))?                                     # :port (optional)
+        (?::(?P<port>\d+))?/                                    # :port (optional) + "/" as separator
         """
         """
-        + abs_path_re,
+        + path_re,
         re.VERBOSE,
         re.VERBOSE,
     )  # path
     )  # path
 
 
@@ -618,6 +624,14 @@ class Location:
                 path = self.path
                 path = self.path
             if self.proto == "rclone":
             if self.proto == "rclone":
                 return f"{self.proto}:{self.path}"
                 return f"{self.proto}:{self.path}"
+            elif self.proto == "sftp":
+                return (
+                    f"{self.proto}://"
+                    f"{(self.user + '@') if self.user else ''}"
+                    f"{self._host if self._host else ''}"
+                    f"{self.port if self.port else ''}/"
+                    f"{path}"
+                )
             else:
             else:
                 return "{}://{}{}{}{}".format(
                 return "{}://{}{}{}{}".format(
                     self.proto if self.proto else "???",
                     self.proto if self.proto else "???",

+ 10 - 3
src/borg/testsuite/helpers_test.py

@@ -197,11 +197,18 @@ class TestLocationWithoutEnv:
 
 
     def test_sftp(self, monkeypatch, keys_dir):
     def test_sftp(self, monkeypatch, keys_dir):
         monkeypatch.delenv("BORG_REPO", raising=False)
         monkeypatch.delenv("BORG_REPO", raising=False)
+        # relative path
         assert (
         assert (
-            repr(Location("sftp://user@host:1234/some/path"))
-            == "Location(proto='sftp', user='user', host='host', port=1234, path='/some/path')"
+            repr(Location("sftp://user@host:1234/rel/path"))
+            == "Location(proto='sftp', user='user', host='host', port=1234, path='rel/path')"
         )
         )
-        assert Location("sftp://user@host:1234/some/path").to_key_filename() == keys_dir + "host__some_path"
+        assert Location("sftp://user@host:1234/rel/path").to_key_filename() == keys_dir + "host__rel_path"
+        # absolute path
+        assert (
+            repr(Location("sftp://user@host:1234//abs/path"))
+            == "Location(proto='sftp', user='user', host='host', port=1234, path='/abs/path')"
+        )
+        assert Location("sftp://user@host:1234//abs/path").to_key_filename() == keys_dir + "host__abs_path"
 
 
     def test_socket(self, monkeypatch, keys_dir):
     def test_socket(self, monkeypatch, keys_dir):
         monkeypatch.delenv("BORG_REPO", raising=False)
         monkeypatch.delenv("BORG_REPO", raising=False)