瀏覽代碼

Add --rsh command line option to complement BORG_RSH env var. Fixes #… (#4290)

Add --rsh command line option to complement BORG_RSH env var. Fixes #1701
Manuel Riel 6 年之前
父節點
當前提交
9ab0a095ab
共有 5 個文件被更改,包括 28 次插入13 次删除
  1. 1 0
      docs/man/borg.1
  2. 2 1
      docs/usage_general.rst.inc
  3. 2 0
      src/borg/archiver.py
  4. 3 1
      src/borg/remote.py
  5. 20 11
      src/borg/testsuite/repository.py

+ 1 - 0
docs/man/borg.1

@@ -379,6 +379,7 @@ When set, use the given filename as \fI\%INI\fP\-style logging configuration.
 .B BORG_RSH
 .B BORG_RSH
 When set, use this command instead of \fBssh\fP\&. This can be used to specify ssh options, such as
 When set, use this command instead of \fBssh\fP\&. This can be used to specify ssh options, such as
 a custom identity file \fBssh \-i /path/to/private/key\fP\&. See \fBman ssh\fP for other options.
 a custom identity file \fBssh \-i /path/to/private/key\fP\&. See \fBman ssh\fP for other options.
+Using the \fB\-\-rsh CMD\fP commandline option overrides the environment variable.
 .TP
 .TP
 .B BORG_REMOTE_PATH
 .B BORG_REMOTE_PATH
 When set, use the given path as borg executable on the remote (defaults to "borg" if unset).
 When set, use the given path as borg executable on the remote (defaults to "borg" if unset).

+ 2 - 1
docs/usage_general.rst.inc

@@ -204,7 +204,8 @@ General:
         When set, use the given filename as INI_-style logging configuration.
         When set, use the given filename as INI_-style logging configuration.
     BORG_RSH
     BORG_RSH
         When set, use this command instead of ``ssh``. This can be used to specify ssh options, such as
         When set, use this command instead of ``ssh``. This can be used to specify ssh options, such as
-        a custom identity file ``ssh -i /path/to/private/key``. See ``man ssh`` for other options.
+        a custom identity file ``ssh -i /path/to/private/key``. See ``man ssh`` for other options. Using
+        the ``--rsh CMD`` commandline option overrides the environment variable.
     BORG_REMOTE_PATH
     BORG_REMOTE_PATH
         When set, use the given path as borg executable on the remote (defaults to "borg" if unset).
         When set, use the given path as borg executable on the remote (defaults to "borg" if unset).
         Using ``--remote-path PATH`` commandline option overrides the environment variable.
         Using ``--remote-path PATH`` commandline option overrides the environment variable.

+ 2 - 0
src/borg/archiver.py

@@ -2474,6 +2474,8 @@ class Archiver:
             add_common_option('--debug-profile', metavar='FILE', dest='debug_profile', default=None,
             add_common_option('--debug-profile', metavar='FILE', dest='debug_profile', default=None,
                               help='Write execution profile in Borg format into FILE. For local use a Python-'
                               help='Write execution profile in Borg format into FILE. For local use a Python-'
                                    'compatible file can be generated by suffixing FILE with ".pyprof".')
                                    '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')")
 
 
         def define_exclude_and_patterns(add_option, *, tag_files=False, strip_components=False):
         def define_exclude_and_patterns(add_option, *, tag_files=False, strip_components=False):
             add_option('-e', '--exclude', metavar='PATTERN', dest='patterns',
             add_option('-e', '--exclude', metavar='PATTERN', dest='patterns',

+ 3 - 1
src/borg/remote.py

@@ -540,6 +540,7 @@ class RemoteRepository:
         self.unpacker = get_limited_unpacker('client')
         self.unpacker = get_limited_unpacker('client')
         self.server_version = parse_version('1.0.8')  # fallback version if server is too old to send version information
         self.server_version = parse_version('1.0.8')  # fallback version if server is too old to send version information
         self.p = None
         self.p = None
+        self._args = args
         testing = location.host == '__testsuite__'
         testing = location.host == '__testsuite__'
         # when testing, we invoke and talk to a borg process directly (no ssh).
         # when testing, we invoke and talk to a borg process directly (no ssh).
         # when not testing, we invoke the system-installed ssh binary to talk to a remote borg.
         # when not testing, we invoke the system-installed ssh binary to talk to a remote borg.
@@ -685,7 +686,8 @@ This problem will go away as soon as the server has been upgraded to 1.0.7+.
 
 
     def ssh_cmd(self, location):
     def ssh_cmd(self, location):
         """return a ssh command line that can be prefixed to a borg command line"""
         """return a ssh command line that can be prefixed to a borg command line"""
-        args = shlex.split(os.environ.get('BORG_RSH', 'ssh'))
+        rsh = self._args.rsh or os.environ.get('BORG_RSH', 'ssh')
+        args = shlex.split(rsh)
         if location.port:
         if location.port:
             args += ['-p', str(location.port)]
             args += ['-p', str(location.port)]
         if location.user:
         if location.user:

+ 20 - 11
src/borg/testsuite/repository.py

@@ -799,6 +799,19 @@ class RemoteRepositoryTestCase(RepositoryTestCase):
         return RemoteRepository(Location('__testsuite__:' + os.path.join(self.tmppath, 'repository')),
         return RemoteRepository(Location('__testsuite__:' + os.path.join(self.tmppath, 'repository')),
                                 exclusive=True, create=create)
                                 exclusive=True, create=create)
 
 
+    def _get_mock_args(self):
+        class MockArgs:
+            remote_path = 'borg'
+            umask = 0o077
+            debug_topics = []
+            rsh = None
+
+            def __contains__(self, item):
+                # To behave like argparse.Namespace
+                return hasattr(self, item)
+
+        return MockArgs()
+
     def test_invalid_rpc(self):
     def test_invalid_rpc(self):
         self.assert_raises(InvalidRPCMethod, lambda: self.repository.call('__init__', {}))
         self.assert_raises(InvalidRPCMethod, lambda: self.repository.call('__init__', {}))
 
 
@@ -857,6 +870,8 @@ class RemoteRepositoryTestCase(RepositoryTestCase):
             assert len(e.exception_full) > 0
             assert len(e.exception_full) > 0
 
 
     def test_ssh_cmd(self):
     def test_ssh_cmd(self):
+        args = self._get_mock_args()
+        self.repository._args = args
         assert self.repository.ssh_cmd(Location('example.com:foo')) == ['ssh', 'example.com']
         assert self.repository.ssh_cmd(Location('example.com:foo')) == ['ssh', 'example.com']
         assert self.repository.ssh_cmd(Location('ssh://example.com/foo')) == ['ssh', 'example.com']
         assert self.repository.ssh_cmd(Location('ssh://example.com/foo')) == ['ssh', 'example.com']
         assert self.repository.ssh_cmd(Location('ssh://user@example.com/foo')) == ['ssh', 'user@example.com']
         assert self.repository.ssh_cmd(Location('ssh://user@example.com/foo')) == ['ssh', 'user@example.com']
@@ -865,17 +880,8 @@ class RemoteRepositoryTestCase(RepositoryTestCase):
         assert self.repository.ssh_cmd(Location('example.com:foo')) == ['ssh', '--foo', 'example.com']
         assert self.repository.ssh_cmd(Location('example.com:foo')) == ['ssh', '--foo', 'example.com']
 
 
     def test_borg_cmd(self):
     def test_borg_cmd(self):
-        class MockArgs:
-            remote_path = 'borg'
-            umask = 0o077
-            debug_topics = []
-
-            def __contains__(self, item):
-                # To behave like argparse.Namespace
-                return hasattr(self, item)
-
         assert self.repository.borg_cmd(None, testing=True) == [sys.executable, '-m', 'borg.archiver', 'serve']
         assert self.repository.borg_cmd(None, testing=True) == [sys.executable, '-m', 'borg.archiver', 'serve']
-        args = MockArgs()
+        args = self._get_mock_args()
         # XXX without next line we get spurious test fails when using pytest-xdist, root cause unknown:
         # XXX without next line we get spurious test fails when using pytest-xdist, root cause unknown:
         logging.getLogger().setLevel(logging.INFO)
         logging.getLogger().setLevel(logging.INFO)
         # note: test logger is on info log level, so --info gets added automagically
         # note: test logger is on info log level, so --info gets added automagically
@@ -885,12 +891,15 @@ class RemoteRepositoryTestCase(RepositoryTestCase):
         args.debug_topics = ['something_client_side', 'repository_compaction']
         args.debug_topics = ['something_client_side', 'repository_compaction']
         assert self.repository.borg_cmd(args, testing=False) == ['borg-0.28.2', 'serve', '--umask=077', '--info',
         assert self.repository.borg_cmd(args, testing=False) == ['borg-0.28.2', 'serve', '--umask=077', '--info',
                                                                  '--debug-topic=borg.debug.repository_compaction']
                                                                  '--debug-topic=borg.debug.repository_compaction']
-        args = MockArgs()
+        args = self._get_mock_args()
         args.storage_quota = 0
         args.storage_quota = 0
         assert self.repository.borg_cmd(args, testing=False) == ['borg', 'serve', '--umask=077', '--info']
         assert self.repository.borg_cmd(args, testing=False) == ['borg', 'serve', '--umask=077', '--info']
         args.storage_quota = 314159265
         args.storage_quota = 314159265
         assert self.repository.borg_cmd(args, testing=False) == ['borg', 'serve', '--umask=077', '--info',
         assert self.repository.borg_cmd(args, testing=False) == ['borg', 'serve', '--umask=077', '--info',
                                                                  '--storage-quota=314159265']
                                                                  '--storage-quota=314159265']
+        args.rsh = 'ssh -i foo'
+        self.repository._args = args
+        assert self.repository.ssh_cmd(Location('example.com:foo')) == ['ssh', '-i', 'foo', 'example.com']
 
 
 
 
 class RemoteLegacyFree(RepositoryTestCaseBase):
 class RemoteLegacyFree(RepositoryTestCaseBase):