blob: 9808f6bc8f8ddc5c079acc03ec2e3d7fda419550 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
2# BitBake ToasterUI Implementation
3# based on (No)TTY UI Implementation by Richard Purdie
4#
5# Handling output to TTYs or files (no TTY)
6#
7# Copyright (C) 2006-2012 Richard Purdie
8# Copyright (C) 2013 Intel Corporation
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23from __future__ import division
Patrick Williamsf1e5d692016-03-30 15:21:19 -050024import time
Patrick Williamsc124f4f2015-09-15 14:41:29 -050025import sys
26try:
27 import bb
28except RuntimeError as exc:
29 sys.exit(str(exc))
30
31from bb.ui import uihelper
32from bb.ui.buildinfohelper import BuildInfoHelper
33
34import bb.msg
35import logging
36import os
37
38# pylint: disable=invalid-name
39# module properties for UI modules are read by bitbake and the contract should not be broken
40
41
Patrick Williamsc0f7c042017-02-23 20:41:17 -060042featureSet = [bb.cooker.CookerFeatures.HOB_EXTRA_CACHES, bb.cooker.CookerFeatures.BASEDATASTORE_TRACKING, bb.cooker.CookerFeatures.SEND_SANITYEVENTS]
Patrick Williamsc124f4f2015-09-15 14:41:29 -050043
44logger = logging.getLogger("ToasterLogger")
45interactive = sys.stdout.isatty()
46
Patrick Williamsc124f4f2015-09-15 14:41:29 -050047def _log_settings_from_server(server):
48 # Get values of variables which control our output
49 includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"])
50 if error:
51 logger.error("Unable to get the value of BBINCLUDELOGS variable: %s", error)
52 raise BaseException(error)
53 loglines, error = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
54 if error:
55 logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s", error)
56 raise BaseException(error)
57 consolelogfile, error = server.runCommand(["getVariable", "BB_CONSOLELOG"])
58 if error:
59 logger.error("Unable to get the value of BB_CONSOLELOG variable: %s", error)
60 raise BaseException(error)
Patrick Williamsf1e5d692016-03-30 15:21:19 -050061 return consolelogfile
Patrick Williamsc124f4f2015-09-15 14:41:29 -050062
Patrick Williamsf1e5d692016-03-30 15:21:19 -050063# create a log file for a single build and direct the logger at it;
64# log file name is timestamped to the millisecond (depending
65# on system clock accuracy) to ensure it doesn't overlap with
66# other log file names
67#
68# returns (log file, path to log file) for a build
69def _open_build_log(log_dir):
70 format_str = "%(levelname)s: %(message)s"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050071
Patrick Williamsf1e5d692016-03-30 15:21:19 -050072 now = time.time()
73 now_ms = int((now - int(now)) * 1000)
74 time_str = time.strftime('build_%Y%m%d_%H%M%S', time.localtime(now))
75 log_file_name = time_str + ('.%d.log' % now_ms)
76 build_log_file_path = os.path.join(log_dir, log_file_name)
77
78 build_log = logging.FileHandler(build_log_file_path)
79
80 logformat = bb.msg.BBLogFormatter(format_str)
81 build_log.setFormatter(logformat)
82
83 bb.msg.addDefaultlogFilter(build_log)
84 logger.addHandler(build_log)
85
86 return (build_log, build_log_file_path)
87
88# stop logging to the build log if it exists
89def _close_build_log(build_log):
90 if build_log:
91 build_log.flush()
92 build_log.close()
93 logger.removeHandler(build_log)
94
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050095_evt_list = [
96 "bb.build.TaskBase",
97 "bb.build.TaskFailed",
98 "bb.build.TaskFailedSilent",
99 "bb.build.TaskStarted",
100 "bb.build.TaskSucceeded",
101 "bb.command.CommandCompleted",
102 "bb.command.CommandExit",
103 "bb.command.CommandFailed",
104 "bb.cooker.CookerExit",
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600105 "bb.event.BuildInit",
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500106 "bb.event.BuildCompleted",
107 "bb.event.BuildStarted",
108 "bb.event.CacheLoadCompleted",
109 "bb.event.CacheLoadProgress",
110 "bb.event.CacheLoadStarted",
111 "bb.event.ConfigParsed",
112 "bb.event.DepTreeGenerated",
113 "bb.event.LogExecTTY",
114 "bb.event.MetadataEvent",
115 "bb.event.MultipleProviders",
116 "bb.event.NoProvider",
117 "bb.event.ParseCompleted",
118 "bb.event.ParseProgress",
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600119 "bb.event.ParseStarted",
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500120 "bb.event.RecipeParsed",
121 "bb.event.SanityCheck",
122 "bb.event.SanityCheckPassed",
123 "bb.event.TreeDataPreparationCompleted",
124 "bb.event.TreeDataPreparationStarted",
125 "bb.runqueue.runQueueTaskCompleted",
126 "bb.runqueue.runQueueTaskFailed",
127 "bb.runqueue.runQueueTaskSkipped",
128 "bb.runqueue.runQueueTaskStarted",
129 "bb.runqueue.sceneQueueTaskCompleted",
130 "bb.runqueue.sceneQueueTaskFailed",
131 "bb.runqueue.sceneQueueTaskStarted",
132 "logging.LogRecord"]
133
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500134def main(server, eventHandler, params):
135 # set to a logging.FileHandler instance when a build starts;
136 # see _open_build_log()
137 build_log = None
138
139 # set to the log path when a build starts
140 build_log_file_path = None
141
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500142 helper = uihelper.BBUIHelper()
143
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500144 # TODO don't use log output to determine when bitbake has started
145 #
146 # WARNING: this log handler cannot be removed, as localhostbecontroller
147 # relies on output in the toaster_ui.log file to determine whether
148 # the bitbake server has started, which only happens if
149 # this logger is setup here (see the TODO in the loop below)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150 console = logging.StreamHandler(sys.stdout)
151 format_str = "%(levelname)s: %(message)s"
152 formatter = bb.msg.BBLogFormatter(format_str)
153 bb.msg.addDefaultlogFilter(console)
154 console.setFormatter(formatter)
155 logger.addHandler(console)
156 logger.setLevel(logging.INFO)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500157 llevel, debug_domains = bb.msg.constructLogOptions()
158 result, error = server.runCommand(["setEventMask", server.getEventHandle(), llevel, debug_domains, _evt_list])
159 if not result or error:
160 logger.error("can't set event mask: %s", error)
161 return 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500162
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500163 # verify and warn
164 build_history_enabled = True
165 inheritlist, _ = server.runCommand(["getVariable", "INHERIT"])
166
167 if not "buildhistory" in inheritlist.split(" "):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600168 logger.warning("buildhistory is not enabled. Please enable INHERIT += \"buildhistory\" to see image details.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500169 build_history_enabled = False
170
171 if not params.observe_only:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500172 params.updateFromServer(server)
173 params.updateToServer(server, os.environ.copy())
174 cmdline = params.parseActions()
175 if not cmdline:
176 print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
177 return 1
178 if 'msg' in cmdline and cmdline['msg']:
179 logger.error(cmdline['msg'])
180 return 1
181
182 ret, error = server.runCommand(cmdline['action'])
183 if error:
184 logger.error("Command '%s' failed: %s" % (cmdline, error))
185 return 1
186 elif ret != True:
187 logger.error("Command '%s' failed: returned %s" % (cmdline, ret))
188 return 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500189
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500190 # set to 1 when toasterui needs to shut down
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500191 main.shutdown = 0
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500192
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500193 interrupted = False
194 return_value = 0
195 errors = 0
196 warnings = 0
197 taskfailures = []
198 first = True
199
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500200 buildinfohelper = BuildInfoHelper(server, build_history_enabled,
201 os.getenv('TOASTER_BRBE'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500202
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500203 # write our own log files into bitbake's log directory;
204 # we're only interested in the path to the parent directory of
205 # this file, as we're writing our own logs into the same directory
206 consolelogfile = _log_settings_from_server(server)
207 log_dir = os.path.dirname(consolelogfile)
208 bb.utils.mkdirhier(log_dir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500209
210 while True:
211 try:
212 event = eventHandler.waitEvent(0.25)
213 if first:
214 first = False
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500215
216 # TODO don't use log output to determine when bitbake has started
217 #
218 # this is the line localhostbecontroller needs to
219 # see in toaster_ui.log which it uses to decide whether
220 # the bitbake server has started...
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500221 logger.info("ToasterUI waiting for events")
222
223 if event is None:
224 if main.shutdown > 0:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500225 # if shutting down, close any open build log first
226 _close_build_log(build_log)
227
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500228 break
229 continue
230
231 helper.eventHandler(event)
232
233 # pylint: disable=protected-access
234 # the code will look into the protected variables of the event; no easy way around this
235
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500236 if isinstance(event, bb.event.ParseStarted):
237 if not (build_log and build_log_file_path):
238 build_log, build_log_file_path = _open_build_log(log_dir)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600239
240 buildinfohelper.store_started_build()
241 buildinfohelper.save_build_log_file_path(build_log_file_path)
242 buildinfohelper.set_recipes_to_parse(event.total)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500243 continue
244
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600245 # create a build object in buildinfohelper from either BuildInit
246 # (if available) or BuildStarted (for jethro and previous versions)
247 if isinstance(event, (bb.event.BuildStarted, bb.event.BuildInit)):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500248 if not (build_log and build_log_file_path):
249 build_log, build_log_file_path = _open_build_log(log_dir)
250
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600251 buildinfohelper.save_build_targets(event)
252 buildinfohelper.save_build_log_file_path(build_log_file_path)
253
254 # get additional data from BuildStarted
255 if isinstance(event, bb.event.BuildStarted):
256 buildinfohelper.save_build_layers_and_variables()
257 continue
258
259 if isinstance(event, bb.event.ParseProgress):
260 buildinfohelper.set_recipes_parsed(event.current)
261 continue
262
263 if isinstance(event, bb.event.ParseCompleted):
264 buildinfohelper.set_recipes_parsed(event.total)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500265 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500266
267 if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)):
268 buildinfohelper.update_and_store_task(event)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500269 logger.info("Logfile for task %s", event.logfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500270 continue
271
272 if isinstance(event, bb.build.TaskBase):
273 logger.info(event._message)
274
275 if isinstance(event, bb.event.LogExecTTY):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500276 logger.info(event.msg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500277 continue
278
279 if isinstance(event, logging.LogRecord):
280 if event.levelno == -1:
281 event.levelno = formatter.ERROR
282
283 buildinfohelper.store_log_event(event)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500284
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500285 if event.levelno >= formatter.ERROR:
286 errors = errors + 1
287 elif event.levelno == formatter.WARNING:
288 warnings = warnings + 1
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500289
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500290 # For "normal" logging conditions, don't show note logs from tasks
291 # but do show them if the user has changed the default log level to
292 # include verbose/debug messages
293 if event.taskpid != 0 and event.levelno <= formatter.NOTE:
294 continue
295
296 logger.handle(event)
297 continue
298
299 if isinstance(event, bb.build.TaskFailed):
300 buildinfohelper.update_and_store_task(event)
301 logfile = event.logfile
302 if logfile and os.path.exists(logfile):
303 bb.error("Logfile of failure stored in: %s" % logfile)
304 continue
305
306 # these events are unprocessed now, but may be used in the future to log
307 # timing and error informations from the parsing phase in Toaster
308 if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)):
309 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500310 if isinstance(event, bb.event.CacheLoadStarted):
311 continue
312 if isinstance(event, bb.event.CacheLoadProgress):
313 continue
314 if isinstance(event, bb.event.CacheLoadCompleted):
315 continue
316 if isinstance(event, bb.event.MultipleProviders):
317 logger.info("multiple providers are available for %s%s (%s)", event._is_runtime and "runtime " or "",
318 event._item,
319 ", ".join(event._candidates))
320 logger.info("consider defining a PREFERRED_PROVIDER entry to match %s", event._item)
321 continue
322
323 if isinstance(event, bb.event.NoProvider):
324 errors = errors + 1
325 if event._runtime:
326 r = "R"
327 else:
328 r = ""
329
330 if event._dependees:
331 text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % (r, event._item, ", ".join(event._dependees), r)
332 else:
333 text = "Nothing %sPROVIDES '%s'" % (r, event._item)
334
335 logger.error(text)
336 if event._reasons:
337 for reason in event._reasons:
338 logger.error("%s", reason)
339 text += reason
340 buildinfohelper.store_log_error(text)
341 continue
342
343 if isinstance(event, bb.event.ConfigParsed):
344 continue
345 if isinstance(event, bb.event.RecipeParsed):
346 continue
347
348 # end of saved events
349
350 if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)):
351 buildinfohelper.store_started_task(event)
352 continue
353
354 if isinstance(event, bb.runqueue.runQueueTaskCompleted):
355 buildinfohelper.update_and_store_task(event)
356 continue
357
358 if isinstance(event, bb.runqueue.runQueueTaskFailed):
359 buildinfohelper.update_and_store_task(event)
360 taskfailures.append(event.taskstring)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600361 logger.error("Task (%s) failed with exit code '%s'",
362 event.taskstring, event.exitcode)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500363 continue
364
365 if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)):
366 buildinfohelper.update_and_store_task(event)
367 continue
368
369
370 if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)):
371 continue
372
373 if isinstance(event, (bb.event.BuildCompleted, bb.command.CommandFailed)):
374
375 errorcode = 0
376 if isinstance(event, bb.command.CommandFailed):
377 errors += 1
378 errorcode = 1
379 logger.error("Command execution failed: %s", event.error)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600380 elif isinstance(event, bb.event.BuildCompleted):
381 buildinfohelper.scan_image_artifacts()
382 buildinfohelper.clone_required_sdk_artifacts()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500383
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500384 # turn off logging to the current build log
385 _close_build_log(build_log)
386
387 # reset ready for next BuildStarted
388 build_log = None
389
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500390 # update the build info helper on BuildCompleted, not on CommandXXX
391 buildinfohelper.update_build_information(event, errors, warnings, taskfailures)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500392
393 brbe = buildinfohelper.brbe
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500394 buildinfohelper.close(errorcode)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500395
396 # we start a new build info
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500397 if params.observe_only:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500398 logger.debug("ToasterUI prepared for new build")
399 errors = 0
400 warnings = 0
401 taskfailures = []
402 buildinfohelper = BuildInfoHelper(server, build_history_enabled)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500403 else:
404 main.shutdown = 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500405
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500406 logger.info("ToasterUI build done, brbe: %s", brbe)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500407 continue
408
409 if isinstance(event, (bb.command.CommandCompleted,
410 bb.command.CommandFailed,
411 bb.command.CommandExit)):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500412 if params.observe_only:
413 errorcode = 0
414 else:
415 main.shutdown = 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500416
417 continue
418
419 if isinstance(event, bb.event.MetadataEvent):
420 if event.type == "SinglePackageInfo":
421 buildinfohelper.store_build_package_information(event)
422 elif event.type == "LayerInfo":
423 buildinfohelper.store_layer_info(event)
424 elif event.type == "BuildStatsList":
425 buildinfohelper.store_tasks_stats(event)
426 elif event.type == "ImagePkgList":
427 buildinfohelper.store_target_package_data(event)
428 elif event.type == "MissedSstate":
429 buildinfohelper.store_missed_state_tasks(event)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600430 elif event.type == "SDKArtifactInfo":
431 buildinfohelper.scan_sdk_artifacts(event)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500432 elif event.type == "SetBRBE":
433 buildinfohelper.brbe = buildinfohelper._get_data_from_event(event)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600434 elif event.type == "TaskArtifacts":
435 # not implemented yet
436 # see https://bugzilla.yoctoproject.org/show_bug.cgi?id=10283 for details
437 pass
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500438 elif event.type == "OSErrorException":
439 logger.error(event)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500440 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600441 logger.error("Unprocessed MetadataEvent %s", event.type)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500442 continue
443
444 if isinstance(event, bb.cooker.CookerExit):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500445 # shutdown when bitbake server shuts down
446 main.shutdown = 1
447 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500448
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500449 if isinstance(event, bb.event.DepTreeGenerated):
450 buildinfohelper.store_dependency_information(event)
451 continue
452
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600453 logger.warning("Unknown event: %s", event)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500454 return_value += 1
455
456 except EnvironmentError as ioerror:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600457 logger.warning("EnvironmentError: %s" % ioerror)
458 # ignore interrupted io system calls
459 if ioerror.args[0] == 4: # errno 4 is EINTR
460 logger.warning("Skipped EINTR: %s" % ioerror)
461 else:
462 raise
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500463 except KeyboardInterrupt:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600464 if params.observe_only:
465 print("\nKeyboard Interrupt, exiting observer...")
466 main.shutdown = 2
467 if not params.observe_only and main.shutdown == 1:
468 print("\nSecond Keyboard Interrupt, stopping...\n")
469 _, error = server.runCommand(["stateForceShutdown"])
470 if error:
471 logger.error("Unable to cleanly stop: %s" % error)
472 if not params.observe_only and main.shutdown == 0:
473 print("\nKeyboard Interrupt, closing down...\n")
474 interrupted = True
475 _, error = server.runCommand(["stateShutdown"])
476 if error:
477 logger.error("Unable to cleanly shutdown: %s" % error)
478 buildinfohelper.cancel_cli_build()
479 main.shutdown = main.shutdown + 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500480 except Exception as e:
481 # print errors to log
482 import traceback
483 from pprint import pformat
484 exception_data = traceback.format_exc()
485 logger.error("%s\n%s" , e, exception_data)
486
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500487 # save them to database, if possible; if it fails, we already logged to console.
488 try:
489 buildinfohelper.store_log_exception("%s\n%s" % (str(e), exception_data))
490 except Exception as ce:
491 logger.error("CRITICAL - Failed to to save toaster exception to the database: %s", str(ce))
492
493 # make sure we return with an error
494 return_value += 1
495
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500496 if interrupted and return_value == 0:
497 return_value += 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500498
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600499 logger.warning("Return value is %d", return_value)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500500 return return_value