diff options
| -rw-r--r-- | bitbake/lib/bb/cooker.py | 32 | ||||
| -rw-r--r-- | bitbake/lib/bb/event.py | 9 | ||||
| -rw-r--r-- | bitbake/lib/bb/exceptions.py | 96 | ||||
| -rw-r--r-- | bitbake/lib/bb/msg.py | 4 | ||||
| -rw-r--r-- | bitbake/lib/bb/ui/teamcity.py | 5 |
5 files changed, 25 insertions, 121 deletions
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py index 6318ef4a8f..1cb3e189f4 100644 --- a/bitbake/lib/bb/cooker.py +++ b/bitbake/lib/bb/cooker.py | |||
| @@ -17,7 +17,7 @@ import threading | |||
| 17 | from io import StringIO, UnsupportedOperation | 17 | from io import StringIO, UnsupportedOperation |
| 18 | from contextlib import closing | 18 | from contextlib import closing |
| 19 | from collections import defaultdict, namedtuple | 19 | from collections import defaultdict, namedtuple |
| 20 | import bb, bb.exceptions, bb.command | 20 | import bb, bb.command |
| 21 | from bb import utils, data, parse, event, cache, providers, taskdata, runqueue, build | 21 | from bb import utils, data, parse, event, cache, providers, taskdata, runqueue, build |
| 22 | import queue | 22 | import queue |
| 23 | import signal | 23 | import signal |
| @@ -2097,7 +2097,6 @@ class Parser(multiprocessing.Process): | |||
| 2097 | except Exception as exc: | 2097 | except Exception as exc: |
| 2098 | tb = sys.exc_info()[2] | 2098 | tb = sys.exc_info()[2] |
| 2099 | exc.recipe = filename | 2099 | exc.recipe = filename |
| 2100 | exc.traceback = list(bb.exceptions.extract_traceback(tb, context=3)) | ||
| 2101 | return True, None, exc | 2100 | return True, None, exc |
| 2102 | # Need to turn BaseExceptions into Exceptions here so we gracefully shutdown | 2101 | # Need to turn BaseExceptions into Exceptions here so we gracefully shutdown |
| 2103 | # and for example a worker thread doesn't just exit on its own in response to | 2102 | # and for example a worker thread doesn't just exit on its own in response to |
| @@ -2298,8 +2297,12 @@ class CookerParser(object): | |||
| 2298 | return False | 2297 | return False |
| 2299 | except ParsingFailure as exc: | 2298 | except ParsingFailure as exc: |
| 2300 | self.error += 1 | 2299 | self.error += 1 |
| 2301 | logger.error('Unable to parse %s: %s' % | 2300 | |
| 2302 | (exc.recipe, bb.exceptions.to_string(exc.realexception))) | 2301 | exc_desc = str(exc) |
| 2302 | if isinstance(exc, SystemExit) and not isinstance(exc.code, str): | ||
| 2303 | exc_desc = 'Exited with "%d"' % exc.code | ||
| 2304 | |||
| 2305 | logger.error('Unable to parse %s: %s' % (exc.recipe, exc_desc)) | ||
| 2303 | self.shutdown(clean=False) | 2306 | self.shutdown(clean=False) |
| 2304 | return False | 2307 | return False |
| 2305 | except bb.parse.ParseError as exc: | 2308 | except bb.parse.ParseError as exc: |
| @@ -2308,20 +2311,33 @@ class CookerParser(object): | |||
| 2308 | self.shutdown(clean=False, eventmsg=str(exc)) | 2311 | self.shutdown(clean=False, eventmsg=str(exc)) |
| 2309 | return False | 2312 | return False |
| 2310 | except bb.data_smart.ExpansionError as exc: | 2313 | except bb.data_smart.ExpansionError as exc: |
| 2314 | def skip_frames(f, fn_prefix): | ||
| 2315 | while f and f.tb_frame.f_code.co_filename.startswith(fn_prefix): | ||
| 2316 | f = f.tb_next | ||
| 2317 | return f | ||
| 2318 | |||
| 2311 | self.error += 1 | 2319 | self.error += 1 |
| 2312 | bbdir = os.path.dirname(__file__) + os.sep | 2320 | bbdir = os.path.dirname(__file__) + os.sep |
| 2313 | etype, value, _ = sys.exc_info() | 2321 | etype, value, tb = sys.exc_info() |
| 2314 | tb = list(itertools.dropwhile(lambda e: e.filename.startswith(bbdir), exc.traceback)) | 2322 | |
| 2323 | # Remove any frames where the code comes from bitbake. This | ||
| 2324 | # prevents deep (and pretty useless) backtraces for expansion error | ||
| 2325 | tb = skip_frames(tb, bbdir) | ||
| 2326 | cur = tb | ||
| 2327 | while cur: | ||
| 2328 | cur.tb_next = skip_frames(cur.tb_next, bbdir) | ||
| 2329 | cur = cur.tb_next | ||
| 2330 | |||
| 2315 | logger.error('ExpansionError during parsing %s', value.recipe, | 2331 | logger.error('ExpansionError during parsing %s', value.recipe, |
| 2316 | exc_info=(etype, value, tb)) | 2332 | exc_info=(etype, value, tb)) |
| 2317 | self.shutdown(clean=False) | 2333 | self.shutdown(clean=False) |
| 2318 | return False | 2334 | return False |
| 2319 | except Exception as exc: | 2335 | except Exception as exc: |
| 2320 | self.error += 1 | 2336 | self.error += 1 |
| 2321 | etype, value, tb = sys.exc_info() | 2337 | _, value, _ = sys.exc_info() |
| 2322 | if hasattr(value, "recipe"): | 2338 | if hasattr(value, "recipe"): |
| 2323 | logger.error('Unable to parse %s' % value.recipe, | 2339 | logger.error('Unable to parse %s' % value.recipe, |
| 2324 | exc_info=(etype, value, exc.traceback)) | 2340 | exc_info=sys.exc_info()) |
| 2325 | else: | 2341 | else: |
| 2326 | # Most likely, an exception occurred during raising an exception | 2342 | # Most likely, an exception occurred during raising an exception |
| 2327 | import traceback | 2343 | import traceback |
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py index 4761c86880..952c85c0bd 100644 --- a/bitbake/lib/bb/event.py +++ b/bitbake/lib/bb/event.py | |||
| @@ -19,7 +19,6 @@ import sys | |||
| 19 | import threading | 19 | import threading |
| 20 | import traceback | 20 | import traceback |
| 21 | 21 | ||
| 22 | import bb.exceptions | ||
| 23 | import bb.utils | 22 | import bb.utils |
| 24 | 23 | ||
| 25 | # This is the pid for which we should generate the event. This is set when | 24 | # This is the pid for which we should generate the event. This is set when |
| @@ -759,13 +758,7 @@ class LogHandler(logging.Handler): | |||
| 759 | 758 | ||
| 760 | def emit(self, record): | 759 | def emit(self, record): |
| 761 | if record.exc_info: | 760 | if record.exc_info: |
| 762 | etype, value, tb = record.exc_info | 761 | record.bb_exc_formatted = traceback.format_exception(*record.exc_info) |
| 763 | if hasattr(tb, 'tb_next'): | ||
| 764 | tb = list(bb.exceptions.extract_traceback(tb, context=3)) | ||
| 765 | # Need to turn the value into something the logging system can pickle | ||
| 766 | record.bb_exc_info = (etype, value, tb) | ||
| 767 | record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5) | ||
| 768 | value = str(value) | ||
| 769 | record.exc_info = None | 762 | record.exc_info = None |
| 770 | fire(record, None) | 763 | fire(record, None) |
| 771 | 764 | ||
diff --git a/bitbake/lib/bb/exceptions.py b/bitbake/lib/bb/exceptions.py deleted file mode 100644 index 801db9c82f..0000000000 --- a/bitbake/lib/bb/exceptions.py +++ /dev/null | |||
| @@ -1,96 +0,0 @@ | |||
| 1 | # | ||
| 2 | # Copyright BitBake Contributors | ||
| 3 | # | ||
| 4 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 5 | # | ||
| 6 | |||
| 7 | import inspect | ||
| 8 | import traceback | ||
| 9 | import bb.namedtuple_with_abc | ||
| 10 | from collections import namedtuple | ||
| 11 | |||
| 12 | |||
| 13 | class TracebackEntry(namedtuple.abc): | ||
| 14 | """Pickleable representation of a traceback entry""" | ||
| 15 | _fields = 'filename lineno function args code_context index' | ||
| 16 | _header = ' File "{0.filename}", line {0.lineno}, in {0.function}{0.args}' | ||
| 17 | |||
| 18 | def format(self, formatter=None): | ||
| 19 | if not self.code_context: | ||
| 20 | return self._header.format(self) + '\n' | ||
| 21 | |||
| 22 | formatted = [self._header.format(self) + ':\n'] | ||
| 23 | |||
| 24 | for lineindex, line in enumerate(self.code_context): | ||
| 25 | if formatter: | ||
| 26 | line = formatter(line) | ||
| 27 | |||
| 28 | if lineindex == self.index: | ||
| 29 | formatted.append(' >%s' % line) | ||
| 30 | else: | ||
| 31 | formatted.append(' %s' % line) | ||
| 32 | return formatted | ||
| 33 | |||
| 34 | def __str__(self): | ||
| 35 | return ''.join(self.format()) | ||
| 36 | |||
| 37 | def _get_frame_args(frame): | ||
| 38 | """Get the formatted arguments and class (if available) for a frame""" | ||
| 39 | arginfo = inspect.getargvalues(frame) | ||
| 40 | |||
| 41 | try: | ||
| 42 | if not arginfo.args: | ||
| 43 | return '', None | ||
| 44 | # There have been reports from the field of python 2.6 which doesn't | ||
| 45 | # return a namedtuple here but simply a tuple so fallback gracefully if | ||
| 46 | # args isn't present. | ||
| 47 | except AttributeError: | ||
| 48 | return '', None | ||
| 49 | |||
| 50 | firstarg = arginfo.args[0] | ||
| 51 | if firstarg == 'self': | ||
| 52 | self = arginfo.locals['self'] | ||
| 53 | cls = self.__class__.__name__ | ||
| 54 | |||
| 55 | arginfo.args.pop(0) | ||
| 56 | del arginfo.locals['self'] | ||
| 57 | else: | ||
| 58 | cls = None | ||
| 59 | |||
| 60 | formatted = inspect.formatargvalues(*arginfo) | ||
| 61 | return formatted, cls | ||
| 62 | |||
| 63 | def extract_traceback(tb, context=1): | ||
| 64 | frames = inspect.getinnerframes(tb, context) | ||
| 65 | for frame, filename, lineno, function, code_context, index in frames: | ||
| 66 | formatted_args, cls = _get_frame_args(frame) | ||
| 67 | if cls: | ||
| 68 | function = '%s.%s' % (cls, function) | ||
| 69 | yield TracebackEntry(filename, lineno, function, formatted_args, | ||
| 70 | code_context, index) | ||
| 71 | |||
| 72 | def format_extracted(extracted, formatter=None, limit=None): | ||
| 73 | if limit: | ||
| 74 | extracted = extracted[-limit:] | ||
| 75 | |||
| 76 | formatted = [] | ||
| 77 | for tracebackinfo in extracted: | ||
| 78 | formatted.extend(tracebackinfo.format(formatter)) | ||
| 79 | return formatted | ||
| 80 | |||
| 81 | |||
| 82 | def format_exception(etype, value, tb, context=1, limit=None, formatter=None): | ||
| 83 | formatted = ['Traceback (most recent call last):\n'] | ||
| 84 | |||
| 85 | if hasattr(tb, 'tb_next'): | ||
| 86 | tb = extract_traceback(tb, context) | ||
| 87 | |||
| 88 | formatted.extend(format_extracted(tb, formatter, limit)) | ||
| 89 | formatted.extend(traceback.format_exception_only(etype, value)) | ||
| 90 | return formatted | ||
| 91 | |||
| 92 | def to_string(exc): | ||
| 93 | if isinstance(exc, SystemExit): | ||
| 94 | if not isinstance(exc.code, str): | ||
| 95 | return 'Exited with "%d"' % exc.code | ||
| 96 | return str(exc) | ||
diff --git a/bitbake/lib/bb/msg.py b/bitbake/lib/bb/msg.py index 3e18596faa..4f616ff42e 100644 --- a/bitbake/lib/bb/msg.py +++ b/bitbake/lib/bb/msg.py | |||
| @@ -89,10 +89,6 @@ class BBLogFormatter(logging.Formatter): | |||
| 89 | msg = logging.Formatter.format(self, record) | 89 | msg = logging.Formatter.format(self, record) |
| 90 | if hasattr(record, 'bb_exc_formatted'): | 90 | if hasattr(record, 'bb_exc_formatted'): |
| 91 | msg += '\n' + ''.join(record.bb_exc_formatted) | 91 | msg += '\n' + ''.join(record.bb_exc_formatted) |
| 92 | elif hasattr(record, 'bb_exc_info'): | ||
| 93 | etype, value, tb = record.bb_exc_info | ||
| 94 | formatted = bb.exceptions.format_exception(etype, value, tb, limit=5) | ||
| 95 | msg += '\n' + ''.join(formatted) | ||
| 96 | return msg | 92 | return msg |
| 97 | 93 | ||
| 98 | def colorize(self, record): | 94 | def colorize(self, record): |
diff --git a/bitbake/lib/bb/ui/teamcity.py b/bitbake/lib/bb/ui/teamcity.py index fca46c2874..7eeaab8d63 100644 --- a/bitbake/lib/bb/ui/teamcity.py +++ b/bitbake/lib/bb/ui/teamcity.py | |||
| @@ -30,7 +30,6 @@ import bb.build | |||
| 30 | import bb.command | 30 | import bb.command |
| 31 | import bb.cooker | 31 | import bb.cooker |
| 32 | import bb.event | 32 | import bb.event |
| 33 | import bb.exceptions | ||
| 34 | import bb.runqueue | 33 | import bb.runqueue |
| 35 | from bb.ui import uihelper | 34 | from bb.ui import uihelper |
| 36 | 35 | ||
| @@ -102,10 +101,6 @@ class TeamcityLogFormatter(logging.Formatter): | |||
| 102 | details = "" | 101 | details = "" |
| 103 | if hasattr(record, 'bb_exc_formatted'): | 102 | if hasattr(record, 'bb_exc_formatted'): |
| 104 | details = ''.join(record.bb_exc_formatted) | 103 | details = ''.join(record.bb_exc_formatted) |
| 105 | elif hasattr(record, 'bb_exc_info'): | ||
| 106 | etype, value, tb = record.bb_exc_info | ||
| 107 | formatted = bb.exceptions.format_exception(etype, value, tb, limit=5) | ||
| 108 | details = ''.join(formatted) | ||
| 109 | 104 | ||
| 110 | if record.levelno in [bb.msg.BBLogFormatter.ERROR, bb.msg.BBLogFormatter.CRITICAL]: | 105 | if record.levelno in [bb.msg.BBLogFormatter.ERROR, bb.msg.BBLogFormatter.CRITICAL]: |
| 111 | # ERROR gets a separate errorDetails field | 106 | # ERROR gets a separate errorDetails field |
