Browse Source

Make run_command async.

Jelmer Vernooij 5 years ago
parent
commit
cea505516b
5 changed files with 53 additions and 47 deletions
  1. 8 0
      NEWS
  2. 16 24
      dulwich/client.py
  3. 5 4
      dulwich/contrib/paramiko_vendor.py
  4. 1 1
      dulwich/tests/compat/test_client.py
  5. 23 18
      dulwich/tests/test_client.py

+ 8 - 0
NEWS

@@ -2,6 +2,14 @@
 
  * Drop support for Python 2. (Jelmer Vernooij)
 
+ * Various client functions are now implemented as asyncio functions:
+   (Jelmer Vernooij)
+
+ * SSHVendor.run_command is now async. (Jelmer Vernooij)
+
+ * SSHVendor.connect_ssh has been removed (it was deprecated in version 0.9.1).
+   (Jelmer Vernooij)
+
 0.19.15	2020-01-26
 
  * Properly handle files that are just executable for the

+ 16 - 24
dulwich/client.py

@@ -586,7 +586,7 @@ class GitClient(object):
                 if cb is not None:
                     cb(pkt)
 
-    def _handle_receive_pack_head(self, proto, capabilities, old_refs,
+    async def _handle_receive_pack_head(self, proto, capabilities, old_refs,
                                   new_refs):
         """Handle the head of a 'git-receive-pack' request.
 
@@ -686,8 +686,9 @@ class GitClient(object):
             self._fetch_capabilities & server_capabilities)
         return (negotiated_capabilities, symrefs, agent)
 
-    def _handle_upload_pack_head(self, proto, capabilities, graph_walker,
-                                 wants, can_read, depth):
+    async def _handle_upload_pack_head(
+            self, proto, capabilities, graph_walker,
+            wants, can_read, depth):
         """Handle the head of a 'git-upload-pack' request.
 
         Args:
@@ -904,7 +905,7 @@ class TraditionalGitClient(GitClient):
                     report_status_parser.check()
                 return old_refs
 
-            (have, want) = self._handle_receive_pack_head(
+            (have, want) = await self._handle_receive_pack_head(
                 proto, negotiated_capabilities, old_refs, new_refs)
             if (not want and
                     set(new_refs.items()).issubset(set(old_refs.items()))):
@@ -967,7 +968,7 @@ class TraditionalGitClient(GitClient):
             if not wants:
                 proto.write_pkt_line(None)
                 return FetchPackResult(refs, symrefs, agent)
-            (new_shallow, new_unshallow) = self._handle_upload_pack_head(
+            (new_shallow, new_unshallow) = await self._handle_upload_pack_head(
                 proto, negotiated_capabilities, graph_walker, wants, can_read,
                 depth=depth)
             await self._handle_upload_pack_tail(
@@ -1312,18 +1313,9 @@ default_local_git_client_cls = LocalGitClient
 class SSHVendor(object):
     """A client side SSH implementation."""
 
-    def connect_ssh(self, host, command, username=None, port=None,
-                    password=None, key_filename=None):
-        # This function was deprecated in 0.9.1
-        import warnings
-        warnings.warn(
-            "SSHVendor.connect_ssh has been renamed to SSHVendor.run_command",
-            DeprecationWarning)
-        return self.run_command(host, command, username=username, port=port,
-                                password=password, key_filename=key_filename)
-
-    def run_command(self, host, command, username=None, port=None,
-                    password=None, key_filename=None):
+    async def run_command(
+            self, host, command, username=None, port=None,
+            password=None, key_filename=None):
         """Connect to an SSH server.
 
         Run a command remotely and return a file-like object for interaction
@@ -1353,8 +1345,8 @@ class StrangeHostname(Exception):
 class SubprocessSSHVendor(SSHVendor):
     """SSH vendor that shells out to the local 'ssh' command."""
 
-    def run_command(self, host, command, username=None, port=None,
-                    password=None, key_filename=None):
+    async def run_command(self, host, command, username=None, port=None,
+                          password=None, key_filename=None):
 
         if password is not None:
             raise NotImplementedError(
@@ -1384,8 +1376,8 @@ class SubprocessSSHVendor(SSHVendor):
 class PLinkSSHVendor(SSHVendor):
     """SSH vendor that shells out to the local 'plink' command."""
 
-    def run_command(self, host, command, username=None, port=None,
-                    password=None, key_filename=None):
+    async def run_command(self, host, command, username=None, port=None,
+                          password=None, key_filename=None):
 
         if sys.platform == 'win32':
             args = ['plink.exe', '-ssh']
@@ -1481,7 +1473,7 @@ class SSHGitClient(TraditionalGitClient):
             kwargs['password'] = self.password
         if self.key_filename is not None:
             kwargs['key_filename'] = self.key_filename
-        con = self.ssh_vendor.run_command(
+        con = await self.ssh_vendor.run_command(
             self.host, argv, port=self.port, username=self.username,
             **kwargs)
         return (Protocol(con.read, con.write, con.close,
@@ -1773,7 +1765,7 @@ class HttpGitClient(GitClient):
             raise NotImplementedError(self.fetch_pack)
         req_data = BytesIO()
         req_proto = Protocol(None, req_data.write)
-        (have, want) = self._handle_receive_pack_head(
+        (have, want) = await self._handle_receive_pack_head(
             req_proto, negotiated_capabilities, old_refs, new_refs)
         if not want and set(new_refs.items()).issubset(set(old_refs.items())):
             return new_refs
@@ -1823,7 +1815,7 @@ class HttpGitClient(GitClient):
             raise NotImplementedError(self.send_pack)
         req_data = BytesIO()
         req_proto = Protocol(None, req_data.write)
-        (new_shallow, new_unshallow) = self._handle_upload_pack_head(
+        (new_shallow, new_unshallow) = await self._handle_upload_pack_head(
                 req_proto, negotiated_capabilities, graph_walker, wants,
                 can_read=None, depth=depth)
         resp, read = await self._smart_request(

+ 5 - 4
dulwich/contrib/paramiko_vendor.py

@@ -77,10 +77,11 @@ class ParamikoSSHVendor(object):
     def __init__(self, **kwargs):
         self.kwargs = kwargs
 
-    def run_command(self, host, command,
-                    username=None, port=None,
-                    password=None, pkey=None,
-                    key_filename=None, **kwargs):
+    async def run_command(
+            self, host, command,
+            username=None, port=None,
+            password=None, pkey=None,
+            key_filename=None, **kwargs):
 
         client = paramiko.SSHClient()
 

+ 1 - 1
dulwich/tests/compat/test_client.py

@@ -351,7 +351,7 @@ class DulwichTCPClientTest(CompatTestCase, DulwichClientTestBase):
 class TestSSHVendor(object):
 
     @staticmethod
-    def run_command(host, command, username=None, port=None,
+    async def run_command(host, command, username=None, port=None,
                     password=None, key_filename=None):
         cmd, path = command.split(' ')
         cmd = cmd.split('-', 1)

+ 23 - 18
dulwich/tests/test_client.py

@@ -675,8 +675,8 @@ class TestSSHVendor(object):
         self.password = None
         self.key_filename = None
 
-    def run_command(self, host, command, username=None, port=None,
-                    password=None, key_filename=None):
+    async def run_command(self, host, command, username=None, port=None,
+                          password=None, key_filename=None):
         self.host = host
         self.command = command
         self.username = username
@@ -1114,29 +1114,32 @@ class SubprocessSSHVendorTests(TestCase):
 
     def test_run_command_dashes(self):
         vendor = SubprocessSSHVendor()
-        self.assertRaises(StrangeHostname, vendor.run_command, '--weird-host',
-                          'git-clone-url')
+        self.assertRaises(
+            StrangeHostname, asyncio.run,
+            vendor.run_command('--weird-host', 'git-clone-url'))
 
     def test_run_command_password(self):
         vendor = SubprocessSSHVendor()
-        self.assertRaises(NotImplementedError, vendor.run_command, 'host',
-                          'git-clone-url', password='12345')
+        self.assertRaises(
+            NotImplementedError, asyncio.run,
+            vendor.run_command('host', 'git-clone-url', password='12345'))
 
     def test_run_command_password_and_privkey(self):
         vendor = SubprocessSSHVendor()
-        self.assertRaises(NotImplementedError, vendor.run_command,
-                          'host', 'git-clone-url',
-                          password='12345', key_filename='/tmp/id_rsa')
+        self.assertRaises(
+            NotImplementedError, asyncio.run, vendor.run_command(
+                  'host', 'git-clone-url',
+                  password='12345', key_filename='/tmp/id_rsa'))
 
     def test_run_command_with_port_username_and_privkey(self):
         expected = ['ssh', '-x', '-p', '2200',
                     '-i', '/tmp/id_rsa', 'user@host', 'git-clone-url']
 
         vendor = SubprocessSSHVendor()
-        command = vendor.run_command(
+        command = asyncio.run(vendor.run_command(
             'host', 'git-clone-url',
             username='user', port='2200',
-            key_filename='/tmp/id_rsa')
+            key_filename='/tmp/id_rsa'))
 
         args = command.proc.args
 
@@ -1155,8 +1158,9 @@ class PLinkSSHVendorTests(TestCase):
 
     def test_run_command_dashes(self):
         vendor = PLinkSSHVendor()
-        self.assertRaises(StrangeHostname, vendor.run_command, '--weird-host',
-                          'git-clone-url')
+        self.assertRaises(
+            StrangeHostname, asyncio.run,
+            vendor.run_command('--weird-host', 'git-clone-url'))
 
     def test_run_command_password_and_privkey(self):
         vendor = PLinkSSHVendor()
@@ -1166,9 +1170,9 @@ class PLinkSSHVendorTests(TestCase):
         warnings_list, restore_warnings = setup_warning_catcher()
         self.addCleanup(restore_warnings)
 
-        command = vendor.run_command(
+        command = asyncio.run(vendor.run_command(
                 'host', 'git-clone-url', password='12345',
-                key_filename='/tmp/id_rsa')
+                key_filename='/tmp/id_rsa'))
 
         expected_warning = UserWarning(
             'Invoking PLink with a password exposes the password in the '
@@ -1207,7 +1211,8 @@ class PLinkSSHVendorTests(TestCase):
         warnings_list, restore_warnings = setup_warning_catcher()
         self.addCleanup(restore_warnings)
 
-        command = vendor.run_command('host', 'git-clone-url', password='12345')
+        command = asyncio.run(
+            vendor.run_command('host', 'git-clone-url', password='12345'))
 
         expected_warning = UserWarning(
             'Invoking PLink with a password exposes the password in the '
@@ -1236,10 +1241,10 @@ class PLinkSSHVendorTests(TestCase):
             'user@host', 'git-clone-url']
 
         vendor = PLinkSSHVendor()
-        command = vendor.run_command(
+        command = asyncio.run(vendor.run_command(
             'host', 'git-clone-url',
             username='user', port='2200',
-            key_filename='/tmp/id_rsa')
+            key_filename='/tmp/id_rsa'))
 
         args = command.proc.args