Source

prise / src / output.py

Full commit
import threading

class MultiOutput(object):
    lock = threading.RLock()
    fps = []
    closed = False

    def addFile(self, fp):
        with self.lock:
            self.flush()
            self.fps.append(fp)

    def removeFile(self, fp):
        with self.lock:
            self.flush()
            self.fps.remove(fp)

    def write(self, str):
        with self.lock:
            for fp in self.fps:
                if fp.closed:
                    self.removeFile(fp)
                    continue
                fp.write(str)

    def writelines(self, seq):
        with self.lock:
            for fp in self.fps:
                if fp.closed:
                    self.removeFile(fp)
                    continue
                fp.writelines(seq)

    def flush(self):
        with self.lock:
            for fp in self.fps:
                if fp.closed:
                    self.removeFile(fp)
                    continue
                fp.flush()

    def close(self):
        with self.lock:
            for fp in self.fps:
                fp.close()
            self.closed = True

class CommandOutput(object):
    def __init__(self, path):
        with open(path, 'r') as fp:
            lines = [ line.rstrip() for line in fp ]

        # Parse header
        self.headers = {}
        bodyStart = 0
        for i in range(len(lines)):
            line = lines[i]
            if line[0] == '=':
                bodyStart = i + 1
                break
            (key, value) = line.split(':', 1)
            self.headers[key.strip()] = value.strip()

        # Deal with re-echo'ed lines
        for i in range(2):
            if lines[bodyStart].strip() == self.headers['Command']:
                bodyStart += 1

        # Read footer
        bodyEnd = len(lines) - 1
        for i in range(bodyEnd, bodyStart, -1):
            line = lines[i]
            if line[0] == '=':
                bodyEnd = i
                break
            (key, value) = line.split(':', 1)
            self.headers[key.strip()] = value.strip()

        # Remove trailing blank lines
        while bodyEnd > bodyStart and lines[bodyEnd-1].strip() == '':
            bodyEnd -= 1

        self.bodyLines = lines[bodyStart:bodyEnd]

    def getBody(self):
        return '\n'.join(self.bodyLines)

    def tail(self, lines = 10):
        return '\n'.join(self.bodyLines[-lines:])

    def head(self, lines = 10):
        return '\n'.join(self.bodyLines[:lines])