From de05e332a24fccd9f8b494f2ad505489627d26bc Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Sun, 19 Jan 2014 21:54:33 -0500 Subject: [PATCH] revert LoggingBuildStep and everything that depends on it, and merge the modifications to it into ShellBaseStep --- master/buildbot/process/buildstep.py | 266 ++++++++++++++---- master/buildbot/steps/shell.py | 204 +++++++++++--- master/buildbot/steps/slave.py | 13 +- master/buildbot/steps/source/oldsource.py | 11 - master/buildbot/steps/vstudio.py | 4 +- .../test/unit/test_process_buildstep.py | 14 +- 6 files changed, 392 insertions(+), 120 deletions(-) diff --git a/master/buildbot/process/buildstep.py b/master/buildbot/process/buildstep.py index 01737b6ccb9..bbdef3fbdc3 100644 --- a/master/buildbot/process/buildstep.py +++ b/master/buildbot/process/buildstep.py @@ -720,82 +720,83 @@ class LoggingBuildStep(BuildStep): progressMetrics = ('output',) logfiles = {} - parms = BuildStep.parms + parms = BuildStep.parms + ['logfiles', 'lazylogfiles'] cmd = None - def __init__(self, logfiles=None, lazylogfiles=None, log_eval_func=None, + renderables = ['logfiles', 'lazylogfiles'] + + def __init__(self, logfiles={}, lazylogfiles=False, log_eval_func=None, *args, **kwargs): BuildStep.__init__(self, *args, **kwargs) - if any([x is not None for x in [logfiles, lazylogfiles, log_eval_func]]): + if logfiles and not isinstance(logfiles, dict): config.error( - "The LoggingBuildStep parameters 'logfiles', 'lazylogfiles' and 'log_eval_func' are no longer available") + "the ShellCommand 'logfiles' parameter must be a dictionary") + + # merge a class-level 'logfiles' attribute with one passed in as an + # argument + self.logfiles = self.logfiles.copy() + self.logfiles.update(logfiles) + self.lazylogfiles = lazylogfiles + if log_eval_func is not None: + config.error( + "the 'log_eval_func' paramater is no longer available") self.addLogObserver('stdio', OutputProgressObserver("output")) def addLogFile(self, logname, filename): self.logfiles[logname] = filename - def setupLogsRunCommandAndProcessResults(self, cmd, stdioLog=None, closeLogWhenFinished=True, - errorMessages=None, logfiles=None, lazylogfiles=False): - if errorMessages is None: - errorMessages = [] - if logfiles is None: - logfiles = {} - if logfiles: - cmd.setLogFiles(logfiles) - log.msg("%s.setupLogsRunCommandAndProcessResults(cmd=%s)" % (self.__class__.__name__, cmd)) - log.msg(" cmd.args = %r" % (cmd.args,)) + def buildCommandKwargs(self): + kwargs = dict() + kwargs['logfiles'] = self.logfiles + return kwargs + + def startCommand(self, cmd, errorMessages=[]): + """ + @param cmd: a suitable RemoteCommand which will be launched, with + all output being put into our self.stdio_log LogFile + """ + log.msg("ShellCommand.startCommand(cmd=%s)" % (cmd,)) + log.msg(" cmd.args = %r" % (cmd.args)) self.cmd = cmd # so we can interrupt it + self.step_status.setText(self.describe(False)) + + # stdio is the first log + self.stdio_log = stdio_log = self.addLog("stdio") + cmd.useLog(stdio_log, True) + for em in errorMessages: + stdio_log.addHeader(em) + # TODO: consider setting up self.stdio_log earlier, and have the + # code that passes in errorMessages instead call + # self.stdio_log.addHeader() directly. + + # there might be other logs + self.setupLogfiles(cmd, self.logfiles) + + d = self.runCommand(cmd) # might raise ConnectionLost + d.addCallback(lambda res: self.commandComplete(cmd)) + # TODO: when the status.LogFile object no longer exists, then this # method will a synthetic logfile for old-style steps, and to be called # without the `logs` parameter for new-style steps. Unfortunately, # lots of createSummary methods exist, but don't look at the log, so # it's difficult to optimize when the synthetic logfile is needed. - if stdioLog is not None: - cmd.useLog(stdioLog, closeLogWhenFinished) - for em in errorMessages: - stdioLog.addHeader(em) - # TODO: consider setting up self.stdioLog earlier, and have the - # code that passes in errorMessages instead call - # self.stdioLog.addHeader() directly. - self.setupLogfiles(cmd, logfiles, lazylogfiles=lazylogfiles) - d = self.runCommand(cmd) # might raise ConnectionLost - d.addCallback(lambda _: self.commandComplete(cmd)) - - if stdioLog is not None: - def _createSummary(res): - self.createSummary(cmd.logs[stdioLog.getName()]) - return res - d.addCallback(lambda res: _createSummary(res)) + d.addCallback(lambda res: self.createSummary(cmd.logs['stdio'])) - d.addCallback(lambda _: self.evaluateCommand(cmd)) # returns results - - def _gotResults(results): - if stdioLog is not None: - # finish off the stdio logfile - stdioLog.finish() - return results - d.addCallback(_gotResults) # returns results - d.addErrback(self.checkDisconnect) # handle slave lost - return d - - def startCommandAndSetStatus(self, cmd, stdioLog=None, closeLogWhenFinished=True, - errorMessages=None, logfiles=None, lazylogfiles=False): - self.step_status.setText(self.describe(False)) - d = self.setupLogsRunCommandAndProcessResults(cmd, stdioLog=stdioLog, - closeLogWhenFinished=closeLogWhenFinished, - errorMessages=errorMessages, - logfiles=logfiles, lazylogfiles=lazylogfiles) + d.addCallback(lambda res: self.evaluateCommand(cmd)) # returns results def _gotResults(results): self.setStatus(cmd, results) + # finish off the stdio logfile + stdio_log.finish() return results d.addCallback(_gotResults) # returns results - return d + d.addCallback(self.finished) + d.addErrback(self.failed) - def setupLogfiles(self, cmd, logfiles, lazylogfiles=False): + def setupLogfiles(self, cmd, logfiles): for logname, remotefilename in logfiles.items(): - if lazylogfiles: + if self.lazylogfiles: # Ask RemoteCommand to watch a logfile, but only add # it when/if we see any data. # @@ -878,7 +879,13 @@ def setStatus(self, cmd, results): return defer.succeed(None) -class ShellBaseStep(LoggingBuildStep): +class ShellBaseStep(BuildStep): + progressMetrics = ('output',) + logfiles = {} + + parms = BuildStep.parms + cmd = None + renderables = [ 'slaveEnvironment', 'remote_kwargs', 'description', 'descriptionDone', 'descriptionSuffix', 'haltOnFailure', 'flunkOnFailure'] @@ -890,6 +897,8 @@ def __init__(self, workdir=None, # that we create, but first strip out the ones that we pass to # BuildStep (like haltOnFailure and friends), and a couple that we # consume ourselves. + + # TODO: handle description stuff in BuildStep if description: self.description = description if isinstance(self.description, str): @@ -904,13 +913,17 @@ def __init__(self, workdir=None, if isinstance(self.descriptionSuffix, str): self.descriptionSuffix = [self.descriptionSuffix] - # pull out the ones that LoggingBuildStep wants, then upcall + if 'log_eval_func' in kwargs: + config.error( + "the 'log_eval_func' paramater is no longer available") + + # pull out the ones that BuildStep wants, then upcall buildstep_kwargs = {} for k in kwargs.keys()[:]: if k in self.__class__.parms: buildstep_kwargs[k] = kwargs[k] del kwargs[k] - LoggingBuildStep.__init__(self, **buildstep_kwargs) + BuildStep.__init__(self, **buildstep_kwargs) # check validity of arguments being passed to RemoteShellCommand invalid_args = [] @@ -928,13 +941,16 @@ def __init__(self, workdir=None, kwargs['usePTY'] = usePTY self.remote_kwargs = kwargs + # use the stdio log to monitor progress + self.addLogObserver('stdio', OutputProgressObserver("output")) + def setBuild(self, build): - LoggingBuildStep.setBuild(self, build) + BuildStep.setBuild(self, build) # Set this here, so it gets rendered when we start the step self.slaveEnvironment = self.build.slaveEnvironment def setStepStatus(self, step_status): - LoggingBuildStep.setStepStatus(self, step_status) + BuildStep.setStepStatus(self, step_status) def setDefaultWorkdir(self, workdir): rkw = self.remote_kwargs @@ -948,6 +964,81 @@ def getWorkdir(self): """ return self.remote_kwargs['workdir'] + def setupLogfiles(self, cmd, logfiles, lazylogfiles=False): + for logname, remotefilename in logfiles.items(): + if lazylogfiles: + # Ask RemoteCommand to watch a logfile, but only add + # it when/if we see any data. + # + # The dummy default argument local_logname is a work-around for + # Python name binding; default values are bound by value, but + # captured variables in the body are bound by name. + callback = lambda cmd_arg, local_logname=logname: self.addLog( + local_logname) + cmd.useLogDelayed(logname, callback, True) + else: + # tell the BuildStepStatus to add a LogFile + newlog = self.addLog(logname) + # and tell the RemoteCommand to feed it + cmd.useLog(newlog, True) + + def setupLogsRunCommandAndProcessResults(self, cmd, stdioLog=None, closeLogWhenFinished=True, + errorMessages=None, logfiles=None, lazylogfiles=False): + if errorMessages is None: + errorMessages = [] + if logfiles is None: + logfiles = {} + if logfiles: + cmd.setLogFiles(logfiles) + log.msg("%s.setupLogsRunCommandAndProcessResults(cmd=%s)" % (self.__class__.__name__, cmd)) + log.msg(" cmd.args = %r" % (cmd.args,)) + self.cmd = cmd # so we can interrupt it + # TODO: when the status.LogFile object no longer exists, then this + # method will a synthetic logfile for old-style steps, and to be called + # without the `logs` parameter for new-style steps. Unfortunately, + # lots of createSummary methods exist, but don't look at the log, so + # it's difficult to optimize when the synthetic logfile is needed. + if stdioLog is not None: + cmd.useLog(stdioLog, closeLogWhenFinished) + for em in errorMessages: + stdioLog.addHeader(em) + # TODO: consider setting up self.stdioLog earlier, and have the + # code that passes in errorMessages instead call + # self.stdioLog.addHeader() directly. + self.setupLogfiles(cmd, logfiles, lazylogfiles=lazylogfiles) + d = self.runCommand(cmd) # might raise ConnectionLost + d.addCallback(lambda _: self.commandComplete(cmd)) + + if stdioLog is not None: + def _createSummary(res): + self.createSummary(cmd.logs[stdioLog.getName()]) + return res + d.addCallback(lambda res: _createSummary(res)) + + d.addCallback(lambda _: self.evaluateCommand(cmd)) # returns results + + def _gotResults(results): + if stdioLog is not None: + # finish off the stdio logfile + stdioLog.finish() + return results + d.addCallback(_gotResults) # returns results + return d + + def startCommandAndSetStatus(self, cmd, stdioLog=None, closeLogWhenFinished=True, + errorMessages=None, logfiles=None, lazylogfiles=False): + self.step_status.setText(self.describe(False)) + d = self.setupLogsRunCommandAndProcessResults(cmd, stdioLog=stdioLog, + closeLogWhenFinished=closeLogWhenFinished, + errorMessages=errorMessages, + logfiles=logfiles, lazylogfiles=lazylogfiles) + + def _gotResults(results): + self.setStatus(cmd, results) + return results + d.addCallback(_gotResults) # returns results + return d + def setupEnvironment(self, cmd): # merge in anything from Build.slaveEnvironment # This can be set from a Builder-level environment, or from earlier @@ -984,9 +1075,26 @@ def buildCommandKwargs(self, command, warnings, logfiles=None): return kwargs def getCurrCommand(self): + # TODO: other code assumes self.cmd raise NotImplementedError() + def interrupt(self, reason): + # TODO: consider adding an INTERRUPTED or STOPPED status to use + # instead of FAILURE, might make the text a bit more clear. + # 'reason' can be a Failure, or text + BuildStep.interrupt(self, reason) + if self.step_status.isWaitingForLocks(): + self.addCompleteLog( + 'cancelled while waiting for locks', str(reason)) + else: + self.addCompleteLog('cancelled', str(reason)) + + if self.cmd: + d = self.cmd.interrupt(reason) + d.addErrback(log.err, 'while cancelling command') + def _describe(self, done=False): + # construct a description based on the current command and its status try: if done and self.descriptionDone is not None: return self.descriptionDone @@ -1030,6 +1138,52 @@ def _describe(self, done=False): log.err(failure.Failure(), "Error describing step") return ["???"] + def commandComplete(self, cmd): + pass + + def createSummary(self, stdio): + pass + + def evaluateCommand(self, cmd): + return cmd.results() + + def setStatus(self, cmd, results): + # this is good enough for most steps, but it can be overridden to + # get more control over the displayed text + self.step_status.setText(self.getText(cmd, results)) + self.step_status.setText2(self._maybeGetText2(cmd, results)) + return defer.succeed(None) + + def getText(self, cmd, results): + if results == SUCCESS: + return self.describe(True) + elif results == WARNINGS: + return self.describe(True) + ["warnings"] + elif results == EXCEPTION: + return self.describe(True) + ["exception"] + elif results == CANCELLED: + return self.describe(True) + ["cancelled"] + else: + return self.describe(True) + ["failed"] + + def getText2(self, cmd, results): + return [self.name] + + def _maybeGetText2(self, cmd, results): + if results == SUCCESS: + # successful steps do not add anything to the build's text + pass + elif results == WARNINGS: + if (self.flunkOnWarnings or self.warnOnWarnings): + # we're affecting the overall build, so tell them why + return self.getText2(cmd, results) + else: + if (self.haltOnFailure or self.flunkOnFailure + or self.warnOnFailure): + # we're affecting the overall build, so tell them why + return self.getText2(cmd, results) + return [] + # (WithProperties used to be available in this module) from buildbot.process.properties import WithProperties diff --git a/master/buildbot/steps/shell.py b/master/buildbot/steps/shell.py index 9898e7cafb6..e7f367928de 100644 --- a/master/buildbot/steps/shell.py +++ b/master/buildbot/steps/shell.py @@ -14,6 +14,7 @@ # Copyright Buildbot Team Members +import inspect import re from buildbot import config @@ -23,6 +24,9 @@ from buildbot.status.results import FAILURE from buildbot.status.results import SUCCESS from buildbot.status.results import WARNINGS +from buildbot.util import flatten +from twisted.python import failure +from twisted.python import log from twisted.python.deprecate import deprecatedModuleAttribute from twisted.python.versions import Version from twisted.spread import pb @@ -34,7 +38,7 @@ del _hush_pyflakes -class ShellCommand(buildstep.ShellBaseStep): +class ShellCommand(buildstep.LoggingBuildStep): """I run a single shell command on the buildslave. I return FAILURE if the exit code of that command is non-zero, SUCCESS otherwise. To change @@ -72,58 +76,194 @@ class ShellCommand(buildstep.ShellBaseStep): """ name = "shell" - renderables = ['command', 'logfiles', 'lazylogfiles'] + renderables = [ + 'slaveEnvironment', 'remote_kwargs', 'command', + 'description', 'descriptionDone', 'descriptionSuffix', + 'haltOnFailure', 'flunkOnFailure'] command = None # set this to a command, or set in kwargs - logfiles = {} # you can also set 'logfiles' to a dictionary, and it - # will be merged with any logfiles= argument passed in - # to __init__ + # logfiles={} # you can also set 'logfiles' to a dictionary, and it + # will be merged with any logfiles= argument passed in + # to __init__ # override this on a specific ShellCommand if you want to let it fail # without dooming the entire build to a status of FAILURE flunkOnFailure = True - def __init__(self, command=None, logfiles=None, lazylogfiles=False, **kwargs): + def __init__(self, workdir=None, + description=None, descriptionDone=None, descriptionSuffix=None, + command=None, + usePTY="slave-config", + **kwargs): + # most of our arguments get passed through to the RemoteShellCommand + # that we create, but first strip out the ones that we pass to + # BuildStep (like haltOnFailure and friends), and a couple that we + # consume ourselves. + + if description: + self.description = description + if isinstance(self.description, str): + self.description = [self.description] + if descriptionDone: + self.descriptionDone = descriptionDone + if isinstance(self.descriptionDone, str): + self.descriptionDone = [self.descriptionDone] + + if descriptionSuffix: + self.descriptionSuffix = descriptionSuffix + if isinstance(self.descriptionSuffix, str): + self.descriptionSuffix = [self.descriptionSuffix] + if command: self.setCommand(command) - if logfiles is None: - logfiles = {} - if logfiles and not isinstance(logfiles, dict): - config.error( - "the %s 'logfiles' parameter must be a dictionary" % (self.__class__.__name__,)) - - # merge a class-level 'logfiles' attribute with one passed in as an - # argument - self.logfiles = self.logfiles.copy() - self.logfiles.update(logfiles) - self.lazylogfiles = lazylogfiles - super(ShellCommand, self).__init__(**kwargs) + # pull out the ones that LoggingBuildStep wants, then upcall + buildstep_kwargs = {} + for k in kwargs.keys()[:]: + if k in self.__class__.parms: + buildstep_kwargs[k] = kwargs[k] + del kwargs[k] + buildstep.LoggingBuildStep.__init__(self, **buildstep_kwargs) + + # check validity of arguments being passed to RemoteShellCommand + invalid_args = [] + valid_rsc_args = inspect.getargspec(remotecommand.RemoteShellCommand.__init__)[0] + for arg in kwargs.keys(): + if arg not in valid_rsc_args: + invalid_args.append(arg) + # Raise Configuration error in case invalid arguments are present + if invalid_args: + config.error("Invalid argument(s) passed to RemoteShellCommand: " + + ', '.join(invalid_args)) + + # everything left over goes to the RemoteShellCommand + kwargs['workdir'] = workdir # including a copy of 'workdir' + kwargs['usePTY'] = usePTY + self.remote_kwargs = kwargs + + def setBuild(self, build): + buildstep.LoggingBuildStep.setBuild(self, build) + # Set this here, so it gets rendered when we start the step + self.slaveEnvironment = self.build.slaveEnvironment + + def setStepStatus(self, step_status): + buildstep.LoggingBuildStep.setStepStatus(self, step_status) + + def setDefaultWorkdir(self, workdir): + rkw = self.remote_kwargs + rkw['workdir'] = rkw['workdir'] or workdir + + def getWorkdir(self): + """ + Get the current notion of the workdir. Note that this may change + between instantiation of the step and C{start}, as it is based on the + build's default workdir, and may even be C{None} before that point. + """ + return self.remote_kwargs['workdir'] def setCommand(self, command): self.command = command - def getCurrCommand(self): - return self.command + def _describe(self, done=False): + """Return a list of short strings to describe this step, for the + status display. This uses the first few words of the shell command. + You can replace this by setting .description in your subclass, or by + overriding this method to describe the step better. + + @type done: boolean + @param done: whether the command is complete or not, to improve the + way the command is described. C{done=False} is used + while the command is still running, so a single + imperfect-tense verb is appropriate ('compiling', + 'testing', ...) C{done=True} is used when the command + has finished, and the default getText() method adds some + text, so a simple noun is appropriate ('compile', + 'tests' ...) + """ + + try: + if done and self.descriptionDone is not None: + return self.descriptionDone + if self.description is not None: + return self.description + + # we may have no command if this is a step that sets its command + # name late in the game (e.g., in start()) + if not self.command: + return ["???"] + + words = self.command + if isinstance(words, (str, unicode)): + words = words.split() + + try: + len(words) + except (AttributeError, TypeError): + # WithProperties and Property don't have __len__ + # For old-style classes instances AttributeError raised, + # for new-style classes instances - TypeError. + return ["???"] + + # flatten any nested lists + words = flatten(words, (list, tuple)) + + # strip instances and other detritus (which can happen if a + # description is requested before rendering) + words = [w for w in words if isinstance(w, (str, unicode))] + + if len(words) < 1: + return ["???"] + if len(words) == 1: + return ["'%s'" % words[0]] + if len(words) == 2: + return ["'%s" % words[0], "%s'" % words[1]] + return ["'%s" % words[0], "%s" % words[1], "...'"] + + except: + log.err(failure.Failure(), "Error describing step") + return ["???"] + + def setupEnvironment(self, cmd): + # merge in anything from Build.slaveEnvironment + # This can be set from a Builder-level environment, or from earlier + # BuildSteps. The latter method is deprecated and superseded by + # BuildProperties. + # Environment variables passed in by a BuildStep override + # those passed in at the Builder level. + slaveEnv = self.slaveEnvironment + if slaveEnv: + if cmd.args['env'] is None: + cmd.args['env'] = {} + fullSlaveEnv = slaveEnv.copy() + fullSlaveEnv.update(cmd.args['env']) + cmd.args['env'] = fullSlaveEnv + # note that each RemoteShellCommand gets its own copy of the + # dictionary, so we shouldn't be affecting anyone but ourselves. def buildCommandKwargs(self, warnings): - return super(ShellCommand, self).buildCommandKwargs(self.command, warnings) + kwargs = buildstep.LoggingBuildStep.buildCommandKwargs(self) + kwargs.update(self.remote_kwargs) - def startCommand(self, cmd, errorMessages=None): - if errorMessages is None: - errorMessages = [] + kwargs['command'] = flatten(self.command, (list, tuple)) - # stdio is the first log - self.stdio_log = self.addLog("stdio") + # check for the usePTY flag + if 'usePTY' in kwargs and kwargs['usePTY'] != 'slave-config': + if self.slaveVersionIsOlderThan("svn", "2.7"): + warnings.append("NOTE: slave does not allow master to override usePTY\n") + del kwargs['usePTY'] - d = self.startCommandAndSetStatus(cmd, self.stdio_log, - logfiles=self.logfiles, - lazylogfiles=self.lazylogfiles, - errorMessages=errorMessages) - d.addCallback(self.finished) - d.addErrback(self.failed) + # check for the interruptSignal flag + if "interruptSignal" in kwargs and self.slaveVersionIsOlderThan("shell", "2.15"): + warnings.append("NOTE: slave does not allow master to specify interruptSignal\n") + del kwargs['interruptSignal'] + + return kwargs def start(self): + # this block is specific to ShellCommands. subclasses that don't need + # to set up an argv array, an environment, or extra logfiles= (like + # the Source subclasses) can just skip straight to startCommand() + warnings = [] # create the actual RemoteShellCommand instance now diff --git a/master/buildbot/steps/slave.py b/master/buildbot/steps/slave.py index fc7e85c02be..4f26eec9e36 100644 --- a/master/buildbot/steps/slave.py +++ b/master/buildbot/steps/slave.py @@ -257,15 +257,14 @@ def addLogForRemoteCommands(self, logname): def runRemoteCommand(self, cmd, args, abandonOnFailure=True): """generic RemoteCommand boilerplate""" cmd = remotecommand.RemoteCommand(cmd, args) - d = self.setupLogsRunCommandAndProcessResults(cmd, stdioLog=self.rc_log, - closeLogWhenFinished=False) + cmd.useLog(self.rc_log, False) + d = self.runCommand(cmd) - def commandComplete(res): - isFailure = res == FAILURE - if abandonOnFailure and isFailure: + def commandComplete(cmd): + if abandonOnFailure and cmd.didFail(): raise buildstep.BuildStepFailed() - return isFailure - d.addCallback(lambda res: commandComplete(res)) + return cmd.didFail() + d.addCallback(lambda res: commandComplete(cmd)) return d def runRmdir(self, dir, **kwargs): diff --git a/master/buildbot/steps/source/oldsource.py b/master/buildbot/steps/source/oldsource.py index e03aac3d4dd..5fba40b60b1 100644 --- a/master/buildbot/steps/source/oldsource.py +++ b/master/buildbot/steps/source/oldsource.py @@ -133,17 +133,6 @@ def __init__(self, mode='update', retry=None, **kwargs): 'retry': retry, } - def startCommand(self, cmd, errorMessages=None): - if errorMessages is None: - errorMessages = [] - - # stdio is the first log - self.stdio_log = self.addLog("stdio") - - d = self.startCommandWithoutEnding(cmd, self.stdio_log, errorMessages=errorMessages) - d.addCallbacks(self.finished) - d.addErrback(self.failed) - def start(self): self.args['workdir'] = self.workdir self.args['logEnviron'] = self.logEnviron diff --git a/master/buildbot/steps/vstudio.py b/master/buildbot/steps/vstudio.py index f112a7dfd0e..644d6a5b022 100644 --- a/master/buildbot/steps/vstudio.py +++ b/master/buildbot/steps/vstudio.py @@ -136,12 +136,12 @@ def __init__(self, # always upcall ! ShellCommand.__init__(self, **kwargs) - def setupLogfiles(self, cmd, logfiles, lazylogfiles=False): + def setupLogfiles(self, cmd, logfiles): logwarnings = self.addLog("warnings") logerrors = self.addLog("errors") self.logobserver = MSLogLineObserver(logwarnings, logerrors) self.addLogObserver('stdio', self.logobserver) - ShellCommand.setupLogfiles(self, cmd, logfiles, lazylogfiles=lazylogfiles) + ShellCommand.setupLogfiles(self, cmd, logfiles) def setupInstalldir(self): if not self.installdir: diff --git a/master/buildbot/test/unit/test_process_buildstep.py b/master/buildbot/test/unit/test_process_buildstep.py index 433d291f294..1d84eda10c2 100644 --- a/master/buildbot/test/unit/test_process_buildstep.py +++ b/master/buildbot/test/unit/test_process_buildstep.py @@ -326,9 +326,6 @@ def test_isNewStyle(self): class TestLoggingBuildStep(config.ConfigErrorsMixin, unittest.TestCase): - deprecatedMsg = ("The LoggingBuildStep parameters 'logfiles', " - "'lazylogfiles' and 'log_eval_func' are no longer " - "available") def makeRemoteCommand(self, rc, stdout, stderr=''): cmd = fakeremotecommand.FakeRemoteCommand('cmd', {}) @@ -353,17 +350,10 @@ def test_evaluateCommand_failed(self): (status, FAILURE)) def test_evaluateCommand_log_eval_func(self): - self.assertRaisesConfigError(self.deprecatedMsg, lambda: + deprecatedMsg = "the 'log_eval_func' paramater is no longer available" + self.assertRaisesConfigError(deprecatedMsg, lambda: buildstep.LoggingBuildStep(log_eval_func=mock.Mock())) - def test_evaluateCommand_logfiles(self): - self.assertRaisesConfigError(self.deprecatedMsg, lambda: - buildstep.LoggingBuildStep(logfiles=mock.Mock())) - - def test_evaluateCommand_lazylogfiles(self): - self.assertRaisesConfigError(self.deprecatedMsg, lambda: - buildstep.LoggingBuildStep(lazylogfiles=mock.Mock())) - class InterfaceTests(interfaces.InterfaceTests):