From eba2e42855e9413f035e5093d64543184dce6fae Mon Sep 17 00:00:00 2001 From: Sam Thursfield Date: Wed, 18 Feb 2015 15:54:56 +0000 Subject: distbuild: Log in build-step-xx.log files when initiator cancels build This makes it easier to spot if an incomplete build was due to the user cancelling, or if it represents a dropped connection or internal error. --- distbuild/initiator.py | 32 ++++++++++++++++++-------------- distbuild/mainloop.py | 5 ++++- morphlib/buildcommand.py | 10 +++++++++- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/distbuild/initiator.py b/distbuild/initiator.py index 548ba496..8f9e0c38 100644 --- a/distbuild/initiator.py +++ b/distbuild/initiator.py @@ -151,16 +151,17 @@ class Initiator(distbuild.StateMachine): def _get_output(self, msg): return self._step_outputs[msg['step_name']] + def _write_status_to_build_log(self, f, status): + f.write(time.strftime('%Y-%m-%d %H:%M:%S ') + status + '\n') + f.flush() + def _handle_step_already_started_message(self, msg): status = '%s is already building on %s' % ( msg['step_name'], msg['worker_name']) self._app.status(msg=status) self._open_output(msg) - - f = self._get_output(msg) - f.write(time.strftime('%Y-%m-%d %H:%M:%S ') + status + '\n') - f.flush() + self._write_status_to_build_log(self._get_output(msg), status) def _handle_step_started_message(self, msg): status = 'Started building %s on %s' % ( @@ -168,10 +169,7 @@ class Initiator(distbuild.StateMachine): self._app.status(msg=status) self._open_output(msg) - - f = self._get_output(msg) - f.write(time.strftime('%Y-%m-%d %H:%M:%S ') + status + '\n') - f.flush() + self._write_status_to_build_log(self._get_output(msg), status) def _handle_step_output_message(self, msg): step_name = msg['step_name'] @@ -190,9 +188,7 @@ class Initiator(distbuild.StateMachine): status = 'Finished building %s' % step_name self._app.status(msg=status) - f = self._get_output(msg) - f.write(time.strftime('%Y-%m-%d %H:%M:%S ') + status + '\n') - + self._write_status_to_build_log(self._get_output(msg), status) self._close_output(msg) else: logging.warning( @@ -204,9 +200,7 @@ class Initiator(distbuild.StateMachine): status = 'Build of %s failed.' % step_name self._app.status(msg=status) - f = self._get_output(msg) - f.write(time.strftime('%Y-%m-%d %H:%M:%S ') + status + '\n') - + self._write_status_to_build_log(self._get_output(msg), status) self._close_output(msg) else: logging.warning( @@ -237,3 +231,13 @@ class Initiator(distbuild.StateMachine): self.mainloop.queue_event(self._cm, distbuild.StopConnecting()) self._jm.close() + def handle_cancel(self): + # Note in each build-step.log file that the initiator cancelled: this + # makes it easier to tell whether a build was aborted due to a bug or + # dropped connection, or if the user cancelled with CTRL+C / SIGINT. + + for f in self._step_outputs.itervalues(): + self._write_status_to_build_log(f, 'Initiator cancelled') + f.close() + + self._step_outputs = {} diff --git a/distbuild/mainloop.py b/distbuild/mainloop.py index 97e439f3..f15a3ac1 100644 --- a/distbuild/mainloop.py +++ b/distbuild/mainloop.py @@ -57,8 +57,11 @@ class MainLoop(object): logging.debug('MainLoop.remove_state_machine: %s' % machine) self._machines.remove(machine) + def state_machines_of_type(self, machine_type): + return [m for m in self._machines if isinstance(m, machine_type)] + def n_state_machines_of_type(self, machine_type): - return len([m for m in self._machines if isinstance(m, machine_type)]) + return len(self.state_machines_of_type(machine_type)) def add_event_source(self, event_source): logging.debug('MainLoop.add_event_source: %s' % event_source) diff --git a/morphlib/buildcommand.py b/morphlib/buildcommand.py index a22e689b..c3accf73 100644 --- a/morphlib/buildcommand.py +++ b/morphlib/buildcommand.py @@ -574,4 +574,12 @@ class InitiatorBuildCommand(BuildCommand): self.MAX_RETRIES) loop.add_state_machine(cm) - loop.run() + try: + loop.run() + except KeyboardInterrupt: + # This will run if the user presses Ctrl+C or sends SIGINT during + # the build. It won't trigger on SIGTERM, SIGKILL or unhandled + # Python exceptions. + logging.info('Received KeyboardInterrupt, aborting.') + for initiator in loop.state_machines_of_type(distbuild.Initiator): + initiator.handle_cancel() -- cgit v1.2.1