diff options
Diffstat (limited to 'bitbake/lib')
| -rw-r--r-- | bitbake/lib/bb/ui/buildinfohelper.py | 8 | ||||
| -rw-r--r-- | bitbake/lib/bb/ui/toasterui.py | 116 |
2 files changed, 94 insertions, 30 deletions
diff --git a/bitbake/lib/bb/ui/buildinfohelper.py b/bitbake/lib/bb/ui/buildinfohelper.py index 2fc1a43c40..78f1e9274f 100644 --- a/bitbake/lib/bb/ui/buildinfohelper.py +++ b/bitbake/lib/bb/ui/buildinfohelper.py | |||
| @@ -784,7 +784,7 @@ class BuildInfoHelper(object): | |||
| 784 | ## methods to convert event/external info into objects that the ORM layer uses | 784 | ## methods to convert event/external info into objects that the ORM layer uses |
| 785 | 785 | ||
| 786 | 786 | ||
| 787 | def _get_build_information(self, consolelogfile): | 787 | def _get_build_information(self, build_log_path): |
| 788 | build_info = {} | 788 | build_info = {} |
| 789 | # Generate an identifier for each new build | 789 | # Generate an identifier for each new build |
| 790 | 790 | ||
| @@ -793,7 +793,7 @@ class BuildInfoHelper(object): | |||
| 793 | build_info['distro_version'] = self.server.runCommand(["getVariable", "DISTRO_VERSION"])[0] | 793 | build_info['distro_version'] = self.server.runCommand(["getVariable", "DISTRO_VERSION"])[0] |
| 794 | build_info['started_on'] = timezone.now() | 794 | build_info['started_on'] = timezone.now() |
| 795 | build_info['completed_on'] = timezone.now() | 795 | build_info['completed_on'] = timezone.now() |
| 796 | build_info['cooker_log_path'] = consolelogfile | 796 | build_info['cooker_log_path'] = build_log_path |
| 797 | build_info['build_name'] = self.server.runCommand(["getVariable", "BUILDNAME"])[0] | 797 | build_info['build_name'] = self.server.runCommand(["getVariable", "BUILDNAME"])[0] |
| 798 | build_info['bitbake_version'] = self.server.runCommand(["getVariable", "BB_VERSION"])[0] | 798 | build_info['bitbake_version'] = self.server.runCommand(["getVariable", "BB_VERSION"])[0] |
| 799 | 799 | ||
| @@ -934,9 +934,9 @@ class BuildInfoHelper(object): | |||
| 934 | logger.warn("buildinfohelper: cannot identify layer exception:%s ", nee) | 934 | logger.warn("buildinfohelper: cannot identify layer exception:%s ", nee) |
| 935 | 935 | ||
| 936 | 936 | ||
| 937 | def store_started_build(self, event, consolelogfile): | 937 | def store_started_build(self, event, build_log_path): |
| 938 | assert '_pkgs' in vars(event) | 938 | assert '_pkgs' in vars(event) |
| 939 | build_information = self._get_build_information(consolelogfile) | 939 | build_information = self._get_build_information(build_log_path) |
| 940 | 940 | ||
| 941 | build_obj = self.orm_wrapper.create_build_object(build_information, self.brbe, self.project) | 941 | build_obj = self.orm_wrapper.create_build_object(build_information, self.brbe, self.project) |
| 942 | 942 | ||
diff --git a/bitbake/lib/bb/ui/toasterui.py b/bitbake/lib/bb/ui/toasterui.py index 2b3bc3f436..3d261503ea 100644 --- a/bitbake/lib/bb/ui/toasterui.py +++ b/bitbake/lib/bb/ui/toasterui.py | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 22 | 22 | ||
| 23 | from __future__ import division | 23 | from __future__ import division |
| 24 | import time | ||
| 24 | import sys | 25 | import sys |
| 25 | try: | 26 | try: |
| 26 | import bb | 27 | import bb |
| @@ -43,8 +44,6 @@ featureSet = [bb.cooker.CookerFeatures.HOB_EXTRA_CACHES, bb.cooker.CookerFeature | |||
| 43 | logger = logging.getLogger("ToasterLogger") | 44 | logger = logging.getLogger("ToasterLogger") |
| 44 | interactive = sys.stdout.isatty() | 45 | interactive = sys.stdout.isatty() |
| 45 | 46 | ||
| 46 | |||
| 47 | |||
| 48 | def _log_settings_from_server(server): | 47 | def _log_settings_from_server(server): |
| 49 | # Get values of variables which control our output | 48 | # Get values of variables which control our output |
| 50 | includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"]) | 49 | includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"]) |
| @@ -55,16 +54,60 @@ def _log_settings_from_server(server): | |||
| 55 | if error: | 54 | if error: |
| 56 | logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s", error) | 55 | logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s", error) |
| 57 | raise BaseException(error) | 56 | raise BaseException(error) |
| 58 | consolelogfile, error = server.runCommand(["getSetVariable", "BB_CONSOLELOG"]) | 57 | consolelogfile, error = server.runCommand(["getVariable", "BB_CONSOLELOG"]) |
| 59 | if error: | 58 | if error: |
| 60 | logger.error("Unable to get the value of BB_CONSOLELOG variable: %s", error) | 59 | logger.error("Unable to get the value of BB_CONSOLELOG variable: %s", error) |
| 61 | raise BaseException(error) | 60 | raise BaseException(error) |
| 62 | return includelogs, loglines, consolelogfile | 61 | return consolelogfile |
| 62 | |||
| 63 | # 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 | ||
| 69 | def _open_build_log(log_dir): | ||
| 70 | format_str = "%(levelname)s: %(message)s" | ||
| 71 | |||
| 72 | 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) | ||
| 63 | 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 | ||
| 89 | def _close_build_log(build_log): | ||
| 90 | if build_log: | ||
| 91 | build_log.flush() | ||
| 92 | build_log.close() | ||
| 93 | logger.removeHandler(build_log) | ||
| 94 | |||
| 95 | def main(server, eventHandler, params): | ||
| 96 | # set to a logging.FileHandler instance when a build starts; | ||
| 97 | # see _open_build_log() | ||
| 98 | build_log = None | ||
| 99 | |||
| 100 | # set to the log path when a build starts | ||
| 101 | build_log_file_path = None | ||
| 64 | 102 | ||
| 65 | def main(server, eventHandler, params ): | ||
| 66 | helper = uihelper.BBUIHelper() | 103 | helper = uihelper.BBUIHelper() |
| 67 | 104 | ||
| 105 | # TODO don't use log output to determine when bitbake has started | ||
| 106 | # | ||
| 107 | # WARNING: this log handler cannot be removed, as localhostbecontroller | ||
| 108 | # relies on output in the toaster_ui.log file to determine whether | ||
| 109 | # the bitbake server has started, which only happens if | ||
| 110 | # this logger is setup here (see the TODO in the loop below) | ||
| 68 | console = logging.StreamHandler(sys.stdout) | 111 | console = logging.StreamHandler(sys.stdout) |
| 69 | format_str = "%(levelname)s: %(message)s" | 112 | format_str = "%(levelname)s: %(message)s" |
| 70 | formatter = bb.msg.BBLogFormatter(format_str) | 113 | formatter = bb.msg.BBLogFormatter(format_str) |
| @@ -73,8 +116,6 @@ def main(server, eventHandler, params ): | |||
| 73 | logger.addHandler(console) | 116 | logger.addHandler(console) |
| 74 | logger.setLevel(logging.INFO) | 117 | logger.setLevel(logging.INFO) |
| 75 | 118 | ||
| 76 | _, _, consolelogfile = _log_settings_from_server(server) | ||
| 77 | |||
| 78 | # verify and warn | 119 | # verify and warn |
| 79 | build_history_enabled = True | 120 | build_history_enabled = True |
| 80 | inheritlist, _ = server.runCommand(["getVariable", "INHERIT"]) | 121 | inheritlist, _ = server.runCommand(["getVariable", "INHERIT"]) |
| @@ -87,8 +128,9 @@ def main(server, eventHandler, params ): | |||
| 87 | logger.error("ToasterUI can only work in observer mode") | 128 | logger.error("ToasterUI can only work in observer mode") |
| 88 | return 1 | 129 | return 1 |
| 89 | 130 | ||
| 90 | 131 | # set to 1 when toasterui needs to shut down | |
| 91 | main.shutdown = 0 | 132 | main.shutdown = 0 |
| 133 | |||
| 92 | interrupted = False | 134 | interrupted = False |
| 93 | return_value = 0 | 135 | return_value = 0 |
| 94 | errors = 0 | 136 | errors = 0 |
| @@ -98,25 +140,31 @@ def main(server, eventHandler, params ): | |||
| 98 | 140 | ||
| 99 | buildinfohelper = BuildInfoHelper(server, build_history_enabled) | 141 | buildinfohelper = BuildInfoHelper(server, build_history_enabled) |
| 100 | 142 | ||
| 101 | if buildinfohelper.brbe is not None and consolelogfile: | 143 | # write our own log files into bitbake's log directory; |
| 102 | # if we are under managed mode we have no other UI and we need to write our own file | 144 | # we're only interested in the path to the parent directory of |
| 103 | bb.utils.mkdirhier(os.path.dirname(consolelogfile)) | 145 | # this file, as we're writing our own logs into the same directory |
| 104 | conlogformat = bb.msg.BBLogFormatter(format_str) | 146 | consolelogfile = _log_settings_from_server(server) |
| 105 | consolelog = logging.FileHandler(consolelogfile) | 147 | log_dir = os.path.dirname(consolelogfile) |
| 106 | bb.msg.addDefaultlogFilter(consolelog) | 148 | bb.utils.mkdirhier(log_dir) |
| 107 | consolelog.setFormatter(conlogformat) | ||
| 108 | logger.addHandler(consolelog) | ||
| 109 | |||
| 110 | 149 | ||
| 111 | while True: | 150 | while True: |
| 112 | try: | 151 | try: |
| 113 | event = eventHandler.waitEvent(0.25) | 152 | event = eventHandler.waitEvent(0.25) |
| 114 | if first: | 153 | if first: |
| 115 | first = False | 154 | first = False |
| 155 | |||
| 156 | # TODO don't use log output to determine when bitbake has started | ||
| 157 | # | ||
| 158 | # this is the line localhostbecontroller needs to | ||
| 159 | # see in toaster_ui.log which it uses to decide whether | ||
| 160 | # the bitbake server has started... | ||
| 116 | logger.info("ToasterUI waiting for events") | 161 | logger.info("ToasterUI waiting for events") |
| 117 | 162 | ||
| 118 | if event is None: | 163 | if event is None: |
| 119 | if main.shutdown > 0: | 164 | if main.shutdown > 0: |
| 165 | # if shutting down, close any open build log first | ||
| 166 | _close_build_log(build_log) | ||
| 167 | |||
| 120 | break | 168 | break |
| 121 | continue | 169 | continue |
| 122 | 170 | ||
| @@ -125,8 +173,21 @@ def main(server, eventHandler, params ): | |||
| 125 | # pylint: disable=protected-access | 173 | # pylint: disable=protected-access |
| 126 | # the code will look into the protected variables of the event; no easy way around this | 174 | # the code will look into the protected variables of the event; no easy way around this |
| 127 | 175 | ||
| 176 | # we treat ParseStarted as the first event of toaster-triggered | ||
| 177 | # builds; that way we get the Build Configuration included in the log | ||
| 178 | # and any errors that occur before BuildStarted is fired | ||
| 179 | if isinstance(event, bb.event.ParseStarted): | ||
| 180 | if not (build_log and build_log_file_path): | ||
| 181 | build_log, build_log_file_path = _open_build_log(log_dir) | ||
| 182 | continue | ||
| 183 | |||
| 128 | if isinstance(event, bb.event.BuildStarted): | 184 | if isinstance(event, bb.event.BuildStarted): |
| 129 | buildinfohelper.store_started_build(event, consolelogfile) | 185 | # command-line builds don't fire a ParseStarted event, |
| 186 | # so we have to start the log file for those on BuildStarted instead | ||
| 187 | if not (build_log and build_log_file_path): | ||
| 188 | build_log, build_log_file_path = _open_build_log(log_dir) | ||
| 189 | |||
| 190 | buildinfohelper.store_started_build(event, build_log_file_path) | ||
| 130 | 191 | ||
| 131 | if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)): | 192 | if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)): |
| 132 | buildinfohelper.update_and_store_task(event) | 193 | buildinfohelper.update_and_store_task(event) |
| @@ -171,8 +232,6 @@ def main(server, eventHandler, params ): | |||
| 171 | # timing and error informations from the parsing phase in Toaster | 232 | # timing and error informations from the parsing phase in Toaster |
| 172 | if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)): | 233 | if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)): |
| 173 | continue | 234 | continue |
| 174 | if isinstance(event, bb.event.ParseStarted): | ||
| 175 | continue | ||
| 176 | if isinstance(event, bb.event.ParseProgress): | 235 | if isinstance(event, bb.event.ParseProgress): |
| 177 | continue | 236 | continue |
| 178 | if isinstance(event, bb.event.ParseCompleted): | 237 | if isinstance(event, bb.event.ParseCompleted): |
| @@ -248,6 +307,12 @@ def main(server, eventHandler, params ): | |||
| 248 | errorcode = 1 | 307 | errorcode = 1 |
| 249 | logger.error("Command execution failed: %s", event.error) | 308 | logger.error("Command execution failed: %s", event.error) |
| 250 | 309 | ||
| 310 | # turn off logging to the current build log | ||
| 311 | _close_build_log(build_log) | ||
| 312 | |||
| 313 | # reset ready for next BuildStarted | ||
| 314 | build_log = None | ||
| 315 | |||
| 251 | # update the build info helper on BuildCompleted, not on CommandXXX | 316 | # update the build info helper on BuildCompleted, not on CommandXXX |
| 252 | buildinfohelper.update_build_information(event, errors, warnings, taskfailures) | 317 | buildinfohelper.update_build_information(event, errors, warnings, taskfailures) |
| 253 | buildinfohelper.close(errorcode) | 318 | buildinfohelper.close(errorcode) |
| @@ -256,7 +321,6 @@ def main(server, eventHandler, params ): | |||
| 256 | 321 | ||
| 257 | # we start a new build info | 322 | # we start a new build info |
| 258 | if buildinfohelper.brbe is not None: | 323 | if buildinfohelper.brbe is not None: |
| 259 | |||
| 260 | logger.debug("ToasterUI under BuildEnvironment management - exiting after the build") | 324 | logger.debug("ToasterUI under BuildEnvironment management - exiting after the build") |
| 261 | server.terminateServer() | 325 | server.terminateServer() |
| 262 | else: | 326 | else: |
| @@ -298,8 +362,9 @@ def main(server, eventHandler, params ): | |||
| 298 | continue | 362 | continue |
| 299 | 363 | ||
| 300 | if isinstance(event, bb.cooker.CookerExit): | 364 | if isinstance(event, bb.cooker.CookerExit): |
| 301 | # exit when the server exits | 365 | # shutdown when bitbake server shuts down |
| 302 | break | 366 | main.shutdown = 1 |
| 367 | continue | ||
| 303 | 368 | ||
| 304 | # ignore | 369 | # ignore |
| 305 | if isinstance(event, (bb.event.BuildBase, | 370 | if isinstance(event, (bb.event.BuildBase, |
| @@ -350,9 +415,8 @@ def main(server, eventHandler, params ): | |||
| 350 | # make sure we return with an error | 415 | # make sure we return with an error |
| 351 | return_value += 1 | 416 | return_value += 1 |
| 352 | 417 | ||
| 353 | if interrupted: | 418 | if interrupted and return_value == 0: |
| 354 | if return_value == 0: | 419 | return_value += 1 |
| 355 | return_value += 1 | ||
| 356 | 420 | ||
| 357 | logger.warn("Return value is %d", return_value) | 421 | logger.warn("Return value is %d", return_value) |
| 358 | return return_value | 422 | return return_value |
