# # # add_file "utility.py" # content [88570a11369d681b233221f50615b86204d75cba] # # patch "config.py" # from [ec1da48608a688595fedb41cf4600a3d9d0699e7] # to [fde8b010525104fe45abbead5000f9c9c40c054e] # # patch "monotone.py" # from [428483fe538c6687671cdd2dd64841f217037a25] # to [1634b8668fdbc8e8019ca7140d3d33003bf4c019] # ============================================================ --- utility.py 88570a11369d681b233221f50615b86204d75cba +++ utility.py 88570a11369d681b233221f50615b86204d75cba @@ -0,0 +1,98 @@ + +import popen2 +import select +import fcntl +import os + +def set_nonblocking(fd): + fl = fcntl.fcntl(fd, fcntl.F_GETFL) + fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY) + +def run_command(command, timeout=None): + "returns a tuple of (was_timeout, exit_code, data_read)" + p = popen2.Popen3(command, capturestderr=True) + set_nonblocking(p.fromchild) + set_nonblocking(p.childerr) + fromchild_read = "" + childerr_read = "" + was_timeout = False + while 1: + ro, rw, re = select.select([p.fromchild], [], [p.childerr], timeout) + if not ro and not rw and not re: + was_timeout = True + break + if p.fromchild in ro: + recv = p.fromchild.read() + if recv == "": break + fromchild_read += recv + if p.childerr in re: + recv = p.childerr.read() + if recv == "": break + childerr_read += recv + if not was_timeout: + # check for any data we might have missed (due to a premature break) + # (if there isn't anything we just get a IOError, which we don't mind + try: fromchild_read += p.fromchild.read() + except IOError: pass + try: childerr_read += p.childerr.read() + except IOError: pass + p.fromchild.close() + p.tochild.close() + # if there wasn't a timeout, the program should have exited; in which case we should wait() for it + # otherwise, it might be hung, so the parent should wait for it. + # (wrap in a try: except: just in case some other thread happens to wait() and grab ours; god wrapping + # python around UNIX is horrible sometimes) + exitcode = None + try: + if not was_timeout: exitcode = p.wait() >> 8 + except: pass + return { 'run_command' : command, + 'timeout' : was_timeout, + 'exitcode' : exitcode, + 'fromchild' : fromchild_read, + 'childerr' : childerr_read } + +def iter_command(command, timeout=None): + p = popen2.Popen3(command, capturestderr=True) + set_nonblocking(p.fromchild) + set_nonblocking(p.childerr) + fromchild_read = "" + childerr_read = "" + was_timeout = False + while 1: + ro, rw, re = select.select([p.fromchild], [], [p.childerr], timeout) + if not ro and not rw and not re: + was_timeout = True + break + if p.fromchild in ro: + recv = p.fromchild.read() + if recv == "": break + fromchild_read += recv + while 1: + nl = fromchild_read.find('\n') + if nl == -1: break + yield fromchild_read[:nl] + fromchild_read = fromchild_read[nl+1:] + if p.childerr in re: + recv = p.childerr.read() + if recv == "": break + childerr_read += recv + if not was_timeout: + # check for any data we might have missed (due to a premature break) + # (if there isn't anything we just get a IOError, which we don't mind + try: fromchild_read += p.fromchild.read() + except IOError: pass + try: childerr_read += p.childerr.read() + except IOError: pass + p.fromchild.close() + p.tochild.close() + # yield anything left over + to_yield = fromchild_read.split('\n') + while len(to_yield): yield to_yield.pop() + # call wait() + try: + if not was_timeout: p.wait() + except: pass + if len(childerr_read): raise Exception("data on stderr", childerr_read) + if was_timeout: raise Exception("command timeout") + ============================================================ --- config.py ec1da48608a688595fedb41cf4600a3d9d0699e7 +++ config.py fde8b010525104fe45abbead5000f9c9c40c054e @@ -1,7 +1,5 @@ import sys -sys.path.append('/home/grahame/monotone/goatpy') - monotone = '/opt/monotone/bin/monotone' dbfile = '/home/grahame/public_html/viewmtn/viewmtn.db' graphdir = '/home/grahame/public_html/viewmtn/graph/' ============================================================ --- monotone.py 428483fe538c6687671cdd2dd64841f217037a25 +++ monotone.py 1634b8668fdbc8e8019ca7140d3d33003bf4c019 @@ -1,5 +1,5 @@ -from goatpy import utility +import utility import urllib import pipes import sets @@ -116,6 +116,7 @@ command = self.base_command + " log " + pipes.quote(id) if limit > 0: self.base_command += " --depth=%d" % (limit) iterator = utility.iter_command(self.base_command + " log %s" % (pipes.quote(id))) + raise Exception(command) for line in iterator: if dash_re.match(line): entry = {}