# # # patch "monotone.py" # from [4e67396bf438dcc0efe8594221d0e6f63cdda798] # to [4800fb3c8a713d9a959ca4ec9823306469860dc1] # ============================================================ --- monotone.py 4e67396bf438dcc0efe8594221d0e6f63cdda798 +++ monotone.py 4800fb3c8a713d9a959ca4ec9823306469860dc1 @@ -221,3 +221,76 @@ def is_valid_id(s): return len(s) == 40 and id_re.match(s) != None +import popen2 +import select +from utility import set_nonblocking + +class RecvPacket: + "A packet received from monotone automate stdio" + def __init__(self, init_buffer=""): + self.buffer = init_buffer + self.cmdnum = None + self.error = None + self.length = None + self.is_last = None + self.result = "" + def process_data(self, data): + self.buffer += data + if self.length == None: + m = re.match(r'(\d+):(\d+):([lm]):(\d+):', data) + if m: + self.cmdnum, self.error, pstate, self.length = m.groups() + self.length = int(self.length) + self.is_last = pstate == "l" + self.buffer = self.buffer[m.end(m.lastindex)+1:] + if self.length != None and len(self.result) < self.length: + needed = self.length - len(self.result) + if len(self.buffer) >= needed: + available = needed + else: + available = len(self.buffer) + self.result += self.buffer[:available] + self.buffer = self.buffer[available:] + if len(self.result) == self.length: + return (self.cmdnum, self.error, self.length, self.is_last, self.result) + else: return None + +class Automation: + def __init__(self, mt, dbfile): + self.mt = mt + self.dbfile = dbfile + self.command = "%s --db=%s automate stdio" % (self.mt, pipes.quote(self.dbfile)) + #self.command = "/bin/cat" + self.process = None + def start(self): + self.process = popen2.Popen3(self.command) + set_nonblocking(self.process.fromchild) + def run(self, command, args): + if self.process == None: self.start() + enc = "l%d:%s" % (len(command), command) + enc += ''.join(map(lambda x: "%d:%s" % (len(x), x), args)) + 'e' + self.process.tochild.write(enc) + self.process.tochild.flush() + r = RecvPacket() + complete = False + result_string = "" + result_code = None + while not complete: + ro, rw, re = select.select([self.process.fromchild], [], [], None) + if not ro and not rw and not re: + break + if self.process.fromchild in ro: + recv = self.process.fromchild.read() + if recv == "": break + tv = r.process_data(recv) + if tv != None: + cmdnum, error, length, is_last, result = tv + if result_code == None: result_code = error + result_string += result + if is_last: + complete = True + else: + # in case there is anything left over we + # didn't parse + r = RecvPacket(r.buffer) + return result_code, result_string