1# This file is part of Buildbot. Buildbot is free software: you can 2# redistribute it and/or modify it under the terms of the GNU General Public 3# License as published by the Free Software Foundation, version 2. 4# 5# This program is distributed in the hope that it will be useful, but WITHOUT 6# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 7# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 8# details. 9# 10# You should have received a copy of the GNU General Public License along with 11# this program; if not, write to the Free Software Foundation, Inc., 51 12# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 13# 14# Portions Copyright Buildbot Team Members 15 16 17from twisted.internet import protocol 18 19 20class LineBuffer: 21 def __init__(self): 22 self._buffer = b'' 23 24 def add_data(self, data): 25 # returns lines that have been processed, if any 26 lines = (self._buffer + data).split(b'\n') 27 self._buffer = lines.pop(-1) 28 for l in lines: 29 yield l.rstrip(b'\r') 30 31 def get_trailing_line(self): 32 if self._buffer: 33 ret = [self._buffer] 34 self._buffer = b'' 35 return ret 36 return [] 37 38 39class LineProcessProtocol(protocol.ProcessProtocol): 40 41 def __init__(self): 42 self._out_buffer = LineBuffer() 43 self._err_buffer = LineBuffer() 44 45 def outReceived(self, data): 46 """ 47 Translates bytes into lines, and calls outLineReceived. 48 """ 49 for line in self._out_buffer.add_data(data): 50 self.outLineReceived(line) 51 52 def errReceived(self, data): 53 """ 54 Translates bytes into lines, and calls errLineReceived. 55 """ 56 for line in self._err_buffer.add_data(data): 57 self.errLineReceived(line) 58 59 def processEnded(self, status): 60 for line in self._out_buffer.get_trailing_line(): 61 self.outLineReceived(line) 62 for line in self._err_buffer.get_trailing_line(): 63 self.errLineReceived(line) 64 65 def outLineReceived(self, line): 66 """ 67 Callback to which stdout lines will be sent. 68 Any line that is not terminated by a newline will be processed once the next line comes, 69 or when processEnded is called. 70 """ 71 raise NotImplementedError 72 73 def errLineReceived(self, line): 74 """ 75 Callback to which stdout lines will be sent. 76 Any line that is not terminated by a newline will be processed once the next line comes, 77 or when processEnded is called. 78 """ 79 raise NotImplementedError 80