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 |