Repository: buildbot/buildbot

Issue:
`MasterShellCommandNewStyle` and `MasterShellCommand` are the same
I noticed that the classes `MasterShellCommandNewStyle` and `MasterShellCommand` (as of buildbot version 2.9.1 at least) have the exact same code inside them, except for one single line of `self.warn_deprecated_if_oldstyle_subclass('MasterShellCommand')` inside `MasterShellCommand`.

I suspect that `MasterShellCommand` was intended to keep the previous code, but it looks like it was updated to contain new-style code.


Discussion:

Resolving patch:
diff --git a/master/buildbot/steps/http_oldstyle.py b/master/buildbot/steps/http_oldstyle.py
--- a/master/buildbot/steps/http_oldstyle.py
+++ b/master/buildbot/steps/http_oldstyle.py
@@ -87,8 +87,12 @@ def __init__(self, url, method, **kwargs):
         if self.__class__.__name__ not in ['POST', 'PUT', 'GET', 'DELETE', 'HEAD', 'OPTIONS']:
             self.warn_deprecated_if_oldstyle_subclass('HTTPStep')
 
+    def start(self):
+        d = self.doRequest()
+        d.addErrback(self.failed)
+
     @defer.inlineCallbacks
-    def run(self):
+    def doRequest(self):
         # create a new session if it doesn't exist
         self.session = getSession()
 
@@ -102,71 +106,71 @@ def run(self):
             if value is not None:
                 requestkwargs[param] = value
 
-        log = yield self.addLog('log')
+        log = self.addLog('log')
 
         # known methods already tested in __init__
 
-        yield log.addHeader('Performing {} request to {}\n'.format(self.method, self.url))
+        log.addHeader('Performing {} request to {}\n'.format(self.method, self.url))
         if self.params:
-            yield log.addHeader('Parameters:\n')
+            log.addHeader('Parameters:\n')
             params = requestkwargs.get("params", {})
             if params:
                 params = sorted(params.items(), key=lambda x: x[0])
                 requestkwargs['params'] = params
             for k, v in params:
-                yield log.addHeader('\t{}: {}\n'.format(k, v))
+                log.addHeader('\t{}: {}\n'.format(k, v))
         data = requestkwargs.get("data", None)
         if data:
-            yield log.addHeader('Data:\n')
+            log.addHeader('Data:\n')
             if isinstance(data, dict):
                 for k, v in data.items():
-                    yield log.addHeader('\t{}: {}\n'.format(k, v))
+                    log.addHeader('\t{}: {}\n'.format(k, v))
             else:
-                yield log.addHeader('\t{}\n'.format(data))
+                log.addHeader('\t{}\n'.format(data))
 
         try:
             r = yield self.session.request(**requestkwargs)
         except requests.exceptions.ConnectionError as e:
-            yield log.addStderr('An exception occurred while performing the request: {}'.format(e))
-            return FAILURE
+            log.addStderr('An exception occurred while performing the request: {}'.format(e))
+            self.finished(FAILURE)
+            return
 
         if r.history:
-            yield log.addStdout('\nRedirected %d times:\n\n' % len(r.history))
+            log.addStdout('\nRedirected %d times:\n\n' % len(r.history))
             for rr in r.history:
-                yield self.log_response(log, rr)
-                yield log.addStdout('=' * 60 + '\n')
+                self.log_response(rr)
+                log.addStdout('=' * 60 + '\n')
 
-        yield self.log_response(log, r)
+        self.log_response(r)
 
-        yield log.finish()
+        log.finish()
 
         self.descriptionDone = ["Status code: %d" % r.status_code]
         if (r.status_code < 400):
-            return SUCCESS
+            self.finished(SUCCESS)
         else:
-            return FAILURE
+            self.finished(FAILURE)
 
-    @defer.inlineCallbacks
-    def log_response(self, log, response):
+    def log_response(self, response):
+        log = self.getLog('log')
 
-        yield log.addHeader('Request Header:\n')
+        log.addHeader('Request Header:\n')
         for k, v in response.request.headers.items():
-            yield log.addHeader('\t{}: {}\n'.format(k, v))
+            log.addHeader('\t{}: {}\n'.format(k, v))
 
-        yield log.addStdout('URL: {}\n'.format(response.url))
+        log.addStdout('URL: {}\n'.format(response.url))
 
         if response.status_code == requests.codes.ok:
-            yield log.addStdout('Status: {}\n'.format(response.status_code))
+            log.addStdout('Status: {}\n'.format(response.status_code))
         else:
-            yield log.addStderr('Status: {}\n'.format(response.status_code))
+            log.addStderr('Status: {}\n'.format(response.status_code))
 
-        yield log.addHeader('Response Header:\n')
+        log.addHeader('Response Header:\n')
         for k, v in response.headers.items():
-            yield log.addHeader('\t{}: {}\n'.format(k, v))
+            log.addHeader('\t{}: {}\n'.format(k, v))
 
-        yield log.addStdout(' ------ Content ------\n{}'.format(response.text))
-        content_log = yield self.addLog('content')
-        yield content_log.addStdout(response.text)
+        log.addStdout(' ------ Content ------\n{}'.format(response.text))
+        self.addLog('content').addStdout(response.text)
 
 
 class POST(HTTPStep):
diff --git a/master/buildbot/steps/master_oldstyle.py b/master/buildbot/steps/master_oldstyle.py
--- a/master/buildbot/steps/master_oldstyle.py
+++ b/master/buildbot/steps/master_oldstyle.py
@@ -16,7 +16,6 @@
 import os
 import re
 
-from twisted.internet import defer
 from twisted.internet import error
 from twisted.internet import reactor
 from twisted.internet.protocol import ProcessProtocol
@@ -25,7 +24,6 @@
 from buildbot.process.buildstep import FAILURE
 from buildbot.process.buildstep import SUCCESS
 from buildbot.process.buildstep import BuildStep
-from buildbot.util import deferwaiter
 
 
 class MasterShellCommand(BuildStep):
@@ -53,37 +51,28 @@ def __init__(self, command, **kwargs):
 
         self.command = command
         self.masterWorkdir = self.workdir
-        self._deferwaiter = deferwaiter.DeferWaiter()
-        self._status_object = None
         self.warn_deprecated_if_oldstyle_subclass('MasterShellCommand')
 
     class LocalPP(ProcessProtocol):
 
         def __init__(self, step):
             self.step = step
-            self._finish_d = defer.Deferred()
-            self.step._deferwaiter.add(self._finish_d)
 
         def outReceived(self, data):
-            self.step._deferwaiter.add(self.step.stdio_log.addStdout(data))
+            self.step.stdio_log.addStdout(data)
 
         def errReceived(self, data):
-            self.step._deferwaiter.add(self.step.stdio_log.addStderr(data))
+            self.step.stdio_log.addStderr(data)
 
         def processEnded(self, status_object):
             if status_object.value.exitCode is not None:
-                msg = "exit status {}\n".format(status_object.value.exitCode)
-                self.step._deferwaiter.add(self.step.stdio_log.addHeader(msg))
-
+                self.step.stdio_log.addHeader(
+                    "exit status %d\n" % status_object.value.exitCode)
             if status_object.value.signal is not None:
-                msg = "signal {}\n".format(status_object.value.signal)
-                self.step._deferwaiter.add(self.step.stdio_log.addHeader(msg))
-
-            self.step._status_object = status_object
-            self._finish_d.callback(None)
+                self.step.stdio_log.addHeader("signal {}\n".format(status_object.value.signal))
+            self.step.processEnded(status_object)
 
-    @defer.inlineCallbacks
-    def run(self):
+    def start(self):
         # render properties
         command = self.command
         # set up argv
@@ -108,15 +97,16 @@ def run(self):
             else:
                 argv = command
 
-        self.stdio_log = yield self.addLog("stdio")
+        self.stdio_log = stdio_log = self.addLog("stdio")
 
         if isinstance(command, (str, bytes)):
-            yield self.stdio_log.addHeader(command.strip() + "\n\n")
+            stdio_log.addHeader(command.strip() + "\n\n")
         else:
-            yield self.stdio_log.addHeader(" ".join(command) + "\n\n")
-        yield self.stdio_log.addHeader("** RUNNING ON BUILDMASTER **\n")
-        yield self.stdio_log.addHeader(" in dir {}\n".format(os.getcwd()))
-        yield self.stdio_log.addHeader(" argv: {}\n".format(argv))
+            stdio_log.addHeader(" ".join(command) + "\n\n")
+        stdio_log.addHeader("** RUNNING ON BUILDMASTER **\n")
+        stdio_log.addHeader(" in dir {}\n".format(os.getcwd()))
+        stdio_log.addHeader(" argv: {}\n".format(argv))
+        self.step_status.setText(self.describe())
 
         if self.env is None:
             env = os.environ
@@ -147,25 +137,26 @@ def subst(match):
             env = newenv
 
         if self.logEnviron:
-            yield self.stdio_log.addHeader(" env: %r\n" % (env,))
+            stdio_log.addHeader(" env: %r\n" % (env,))
 
         # TODO add a timeout?
         self.process = reactor.spawnProcess(self.LocalPP(self), argv[0], argv,
                                             path=self.masterWorkdir, usePTY=self.usePTY, env=env)
-
-        # self._deferwaiter will yield only after LocalPP finishes
-
-        yield self._deferwaiter.wait()
-
-        status_value = self._status_object.value
-        if status_value.signal is not None:
-            self.descriptionDone = ["killed ({})".format(status_value.signal)]
-            return FAILURE
-        elif status_value.exitCode != 0:
-            self.descriptionDone = ["failed ({})".format(status_value.exitCode)]
-            return FAILURE
+        # (the LocalPP object will call processEnded for us)
+
+    def processEnded(self, status_object):
+        if status_object.value.signal is not None:
+            self.descriptionDone = ["killed ({})".format(status_object.value.signal)]
+            self.step_status.setText(self.describe(done=True))
+            self.finished(FAILURE)
+        elif status_object.value.exitCode != 0:
+            self.descriptionDone = [
+                "failed (%d)" % status_object.value.exitCode]
+            self.step_status.setText(self.describe(done=True))
+            self.finished(FAILURE)
         else:
-            return SUCCESS
+            self.step_status.setText(self.describe(done=True))
+            self.finished(SUCCESS)
 
     def interrupt(self, reason):
         try:


Test patch: