# # # patch "tracvc/mtn/automate.py" # from [9a1badc84e1e884634783dbe0ce71e67a237dd6d] # to [195fa3542464fd9b5a8cfa2a5acf8e8ce3cff4a8] # ============================================================ --- tracvc/mtn/automate.py 9a1badc84e1e884634783dbe0ce71e67a237dd6d +++ tracvc/mtn/automate.py 195fa3542464fd9b5a8cfa2a5acf8e8ce3cff4a8 @@ -24,11 +24,11 @@ USA """ -import os +from subprocess import Popen, PIPE try: - import threading as _threading + from threading import Lock except ImportError: - import dummy_threading as _threading + from dummy_threading import Lock #IGNORE:E0611 from tracvc.mtn import basic_io from tracvc.mtn.util import add_slash, to_unicode, natsort_key from tracvc.mtn.cache import memoize @@ -37,33 +37,37 @@ class AutomateException(Exception): """Thrown when the status of an automate command is not null, indicating that there is no valid result.""" - def __init__(self, errno): + def __init__(self, cause): Exception.__init__(self) - self.errno = errno + self.cause = cause + def __str__(self): + return self.cause + class Automate(object): """General interface to the 'automate stdio' command.""" def __init__(self, database, binary): - self.to_child, self.from_child = os.popen2( - "%s --norc --automate-stdio-size=1048576 " - "--db=%s --root=. automate stdio" % - (binary, database), "b") - self.lock = _threading.Lock() + import locale + self.process = Popen( + (binary, '--norc', '--root=.', '--automate-stdio-size=1048576', + '--db=%s' % database, 'automate', 'stdio'), + stdin=PIPE, stdout=PIPE, stderr=None) + self.lock = Lock() - def _read(self, maxlen = -1): - """Read maxlen bytes from automate process.""" - return self.from_child.read(maxlen) - def _write(self, data): """Write data to automate process.""" - return self.to_child.write(data) + return self.process.stdin.write(data) def _flush(self): """Send flush to automate process.""" - return self.to_child.flush() + return self.process.stdin.flush() + def _read(self, maxlen = -1): + """Read maxlen bytes from automate process.""" + return self.process.stdout.read(maxlen) + def _read_until_colon(self): """Return bytes until and excluding next colon.""" result = '' @@ -112,12 +116,17 @@ class Automate(object): # critical region: only one thread may send a command and read # back the result at a time self.lock.acquire() - self._write_cmd(cmd, args) - status, result = self._get_result() - self.lock.release() + try: + if self.process.poll(): + raise AutomateException("Monotone process died") + self._write_cmd(cmd, args) + status, result = self._get_result() + finally: + self.lock.release() if status == 0: return result - raise AutomateException(status) + raise AutomateException("Monotone error code %d: %s (%s)" % + (status, to_unicode(result), cmd)) class MTN(object):