aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/bb/cookerdata.py4
-rw-r--r--lib/bb/event.py10
-rw-r--r--lib/bb/methodpool.py4
-rw-r--r--lib/bb/parse/ast.py16
-rw-r--r--lib/bb/utils.py12
5 files changed, 32 insertions, 14 deletions
diff --git a/lib/bb/cookerdata.py b/lib/bb/cookerdata.py
index 671c0cb0e..b47e7f323 100644
--- a/lib/bb/cookerdata.py
+++ b/lib/bb/cookerdata.py
@@ -317,7 +317,9 @@ class CookerDataBuilder(object):
# Nomally we only register event handlers at the end of parsing .bb files
# We register any handlers we've found so far here...
for var in data.getVar('__BBHANDLERS', False) or []:
- bb.event.register(var, data.getVar(var, False), (data.getVarFlag(var, "eventmask", True) or "").split())
+ handlerfn = data.getVarFlag(var, "filename", False)
+ handlerln = int(data.getVarFlag(var, "lineno", False))
+ bb.event.register(var, data.getVar(var, False), (data.getVarFlag(var, "eventmask", True) or "").split(), handlerfn, handlerln)
if data.getVar("BB_WORKERCONTEXT", False) is None:
bb.fetch.fetcher_init(data)
diff --git a/lib/bb/event.py b/lib/bb/event.py
index ec25ce77f..bd2b0a4b0 100644
--- a/lib/bb/event.py
+++ b/lib/bb/event.py
@@ -177,7 +177,7 @@ def fire_from_worker(event, d):
fire_ui_handlers(event, d)
noop = lambda _: None
-def register(name, handler, mask=None):
+def register(name, handler, mask=None, filename=None, lineno=None):
"""Register an Event handler"""
# already registered
@@ -189,7 +189,13 @@ def register(name, handler, mask=None):
if isinstance(handler, basestring):
tmp = "def %s(e):\n%s" % (name, handler)
try:
- code = compile(tmp, "%s(e)" % name, "exec")
+ import ast
+ if filename is None:
+ filename = "%s(e)" % name
+ code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST)
+ if lineno is not None:
+ ast.increment_lineno(code, lineno-1)
+ code = compile(code, filename, "exec")
except SyntaxError:
logger.error("Unable to register event handler '%s':\n%s", name,
''.join(traceback.format_exc(limit=0)))
diff --git a/lib/bb/methodpool.py b/lib/bb/methodpool.py
index bf2e9f554..b2ea1a188 100644
--- a/lib/bb/methodpool.py
+++ b/lib/bb/methodpool.py
@@ -19,11 +19,11 @@
from bb.utils import better_compile, better_exec
-def insert_method(modulename, code, fn):
+def insert_method(modulename, code, fn, lineno):
"""
Add code of a module should be added. The methods
will be simply added, no checking will be done
"""
- comp = better_compile(code, modulename, fn )
+ comp = better_compile(code, modulename, fn, lineno=lineno)
better_exec(comp, None, code, fn)
diff --git a/lib/bb/parse/ast.py b/lib/bb/parse/ast.py
index 11db1801b..e1bf82fe9 100644
--- a/lib/bb/parse/ast.py
+++ b/lib/bb/parse/ast.py
@@ -148,17 +148,19 @@ class MethodNode(AstNode):
def eval(self, data):
text = '\n'.join(self.body)
+ funcname = self.func_name
if self.func_name == "__anonymous":
funcname = ("__anon_%s_%s" % (self.lineno, self.filename.translate(MethodNode.tr_tbl)))
text = "def %s(d):\n" % (funcname) + text
- bb.methodpool.insert_method(funcname, text, self.filename)
+ bb.methodpool.insert_method(funcname, text, self.filename, self.lineno - len(self.body))
anonfuncs = data.getVar('__BBANONFUNCS', False) or []
anonfuncs.append(funcname)
data.setVar('__BBANONFUNCS', anonfuncs)
- data.setVar(funcname, text, parsing=True)
else:
data.setVarFlag(self.func_name, "func", 1)
- data.setVar(self.func_name, text, parsing=True)
+ data.setVar(funcname, text, parsing=True)
+ data.setVarFlag(funcname, 'filename', self.filename)
+ data.setVarFlag(funcname, 'lineno', str(self.lineno - len(self.body)))
class PythonMethodNode(AstNode):
def __init__(self, filename, lineno, function, modulename, body):
@@ -172,10 +174,12 @@ class PythonMethodNode(AstNode):
# 'this' file. This means we will not parse methods from
# bb classes twice
text = '\n'.join(self.body)
- bb.methodpool.insert_method(self.modulename, text, self.filename)
+ bb.methodpool.insert_method(self.modulename, text, self.filename, self.lineno - len(self.body) - 1)
data.setVarFlag(self.function, "func", 1)
data.setVarFlag(self.function, "python", 1)
data.setVar(self.function, text, parsing=True)
+ data.setVarFlag(self.function, 'filename', self.filename)
+ data.setVarFlag(self.function, 'lineno', str(self.lineno - len(self.body) - 1))
class MethodFlagsNode(AstNode):
def __init__(self, filename, lineno, key, m):
@@ -317,7 +321,9 @@ def finalize(fn, d, variant = None):
all_handlers = {}
for var in d.getVar('__BBHANDLERS', False) or []:
# try to add the handler
- bb.event.register(var, d.getVar(var, False), (d.getVarFlag(var, "eventmask", True) or "").split())
+ handlerfn = d.getVarFlag(var, "filename", False)
+ handlerln = int(d.getVarFlag(var, "lineno", False))
+ bb.event.register(var, d.getVar(var, False), (d.getVarFlag(var, "eventmask", True) or "").split(), handlerfn, handlerln)
bb.event.fire(bb.event.RecipePreFinalise(fn), d)
diff --git a/lib/bb/utils.py b/lib/bb/utils.py
index 31ec2b7c9..c5ff903ce 100644
--- a/lib/bb/utils.py
+++ b/lib/bb/utils.py
@@ -33,6 +33,7 @@ import fnmatch
import traceback
import errno
import signal
+import ast
from commands import getstatusoutput
from contextlib import contextmanager
from ctypes import cdll
@@ -291,19 +292,22 @@ def _print_trace(body, line):
error.append(' %.4d:%s' % (i, body[i-1].rstrip()))
return error
-def better_compile(text, file, realfile, mode = "exec"):
+def better_compile(text, file, realfile, mode = "exec", lineno = None):
"""
A better compile method. This method
will print the offending lines.
"""
try:
- return compile(text, file, mode)
+ code = compile(text, realfile, mode, ast.PyCF_ONLY_AST)
+ if lineno is not None:
+ ast.increment_lineno(code, lineno)
+ return compile(code, realfile, mode)
except Exception as e:
error = []
# split the text into lines again
body = text.split('\n')
- error.append("Error in compiling python function in %s:\n" % realfile)
- if e.lineno:
+ error.append("Error in compiling python function in %s, line %s:\n" % (realfile, lineno))
+ if hasattr(e, "lineno"):
error.append("The code lines resulting in this error were:")
error.extend(_print_trace(body, e.lineno))
else: