summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bitbake/lib/bb/cooker.py32
-rw-r--r--bitbake/lib/bb/event.py9
-rw-r--r--bitbake/lib/bb/exceptions.py96
-rw-r--r--bitbake/lib/bb/msg.py4
-rw-r--r--bitbake/lib/bb/ui/teamcity.py5
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
17from io import StringIO, UnsupportedOperation 17from io import StringIO, UnsupportedOperation
18from contextlib import closing 18from contextlib import closing
19from collections import defaultdict, namedtuple 19from collections import defaultdict, namedtuple
20import bb, bb.exceptions, bb.command 20import bb, bb.command
21from bb import utils, data, parse, event, cache, providers, taskdata, runqueue, build 21from bb import utils, data, parse, event, cache, providers, taskdata, runqueue, build
22import queue 22import queue
23import signal 23import 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
19import threading 19import threading
20import traceback 20import traceback
21 21
22import bb.exceptions
23import bb.utils 22import 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
7import inspect
8import traceback
9import bb.namedtuple_with_abc
10from collections import namedtuple
11
12
13class 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
37def _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
63def 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
72def 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
82def 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
92def 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
30import bb.command 30import bb.command
31import bb.cooker 31import bb.cooker
32import bb.event 32import bb.event
33import bb.exceptions
34import bb.runqueue 33import bb.runqueue
35from bb.ui import uihelper 34from 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