From cd537fa3dda69ea256051b12de1b417b834b9f1c Mon Sep 17 00:00:00 2001 From: Paulo Madeira Date: Wed, 22 Jun 2011 00:16:31 +0100 Subject: [PATCH] Launch a reader thread in Win32 to implement can_read(). --- dulwich/client.py | 86 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 80 insertions(+), 6 deletions(-) diff --git a/dulwich/client.py b/dulwich/client.py index 1e72543..75ab4ad 100644 --- a/dulwich/client.py +++ b/dulwich/client.py @@ -308,6 +308,72 @@ class SubprocessWrapper(object): self.proc.wait() +class SubprocessWrapperThread(object): + def __init__(self, proc): + import threading + + self.proc = proc + self.cv = threading.Condition() + self.eof = False + self.read_buffer = '' + self.to_read = 1 + + self.thread = threading.Thread(target=self.read_ahead) + self.thread.daemon = True + self.thread.start() + + def read_ahead(self): + to_read = 1 + while True: + data = self.proc.stdout.read(to_read) + with self.cv: + self.read_buffer = data + self.cv.notify() + if data == '': + self.eof = True + break + self.cv.wait() + to_read = self.to_read + + def read(self, size): + data = '' + while self.thread.is_alive(): + with self.cv: + if self.read_buffer == '' and not self.eof: + self.cv.wait() + if self.read_buffer == '': + break + elif len(self.read_buffer) > size: + data += self.read_buffer[:size] + self.read_buffer = self.read_buffer[size:] + break + else: + data += self.read_buffer + size -= len(self.read_buffer) + self.read_buffer = '' + self.to_read = max(1, size) + self.cv.notify() + if size == 0: + break + return data + + def write(self, data): + return self.proc.stdin.write(data) + + def can_read(self): + with self.cv: + return self.read_buffer != '' + + def close(self): + self.proc.stdin.close() + self.proc.stdout.close() + if self.thread.is_alive(): + with self.cv: + self.to_read = 0 + self.cv.notify() + self.thread.join() + + class SubprocessGitClient(GitClient): """Git client that talks to a server using a subprocess.""" @@ -316,11 +382,16 @@ class SubprocessGitClient(GitClient): GitClient.__init__(self, *args, **kwargs) def _connect(self, service, path): - import subprocess + import subprocess, sys argv = ['git', service, path] - p = SubprocessWrapper( - subprocess.Popen(argv, bufsize=0, stdin=subprocess.PIPE, - stdout=subprocess.PIPE)) + proc = subprocess.Popen(argv, + bufsize=0, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + if sys.platform == 'win32': + p = SubprocessWrapperThread(proc) + else: + p = SubprocessWrapper(proc) return Protocol(p.read, p.write, report_activity=self._report_activity), p.can_read @@ -328,7 +399,7 @@ class SubprocessGitClient(GitClient): class SSHVendor(object): def connect_ssh(self, host, command, username=None, port=None): - import subprocess + import subprocess, sys #FIXME: This has no way to deal with passwords.. args = ['ssh', '-x'] if port is not None: @@ -339,7 +410,10 @@ class SSHVendor(object): proc = subprocess.Popen(args + command, stdin=subprocess.PIPE, stdout=subprocess.PIPE) - return SubprocessWrapper(proc) + if sys.platform == 'win32': + return SubprocessWrapperThread(proc) + else: + return SubprocessWrapper(proc) # Can be overridden by users get_ssh_vendor = SSHVendor -- 1.7.4.msysgit.0