From patchwork Mon May 21 15:10:32 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [bitbake-devel, 2/2] data_smart.py: Track configuration file inclusions Date: Mon, 21 May 2012 15:10:32 -0000 From: Peter Seebach X-Patchwork-Id: 28221 Message-Id: To: This is a preliminary attempt to create a structured representation of the processing of include files. It ignores line numbers because they're meaningless. It could probably be updated to, say, distinguish between includes and requires. Output is added to bitbake -e. Signed-off-by: Peter Seebach --- lib/bb/data.py | 16 ++++++++++++++++ lib/bb/data_smart.py | 41 ++++++++++++++++++++++++++++++++++++++--- lib/bb/parse/__init__.py | 6 +++++- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/lib/bb/data.py b/lib/bb/data.py index aeb678c..72cf274 100644 --- a/lib/bb/data.py +++ b/lib/bb/data.py @@ -253,10 +253,26 @@ def emit_env(o=sys.__stdout__, d = init(), all=False): isfunc = lambda key: bool(d.getVarFlag(key, "func")) keys = sorted((key for key in d.keys() if not key.startswith("__")), key=isfunc) grouped = groupby(keys, isfunc) + # Include history! + if d.tracking(): + o.write('#\n# INCLUDE HISTORY:\n#\n') + emit_history(o, d.getIncludeHistory()) + for isfunc, keys in grouped: for key in keys: emit_var(key, o, d, all and not isfunc) and o.write('\n') +def emit_history(o, h, depth = 0): + if not h: + return + for event in h: + o.write("# %*s%s" % (depth * 2, "", event[0])) + if event[1]: + o.write(" includes:\n") + emit_history(o, event[1], depth + 1) + else: + o.write("\n") + def exported_keys(d): return (key for key in d.keys() if not key.startswith('__') and d.getVarFlag(key, 'export') and diff --git a/lib/bb/data_smart.py b/lib/bb/data_smart.py index 4a7b56c..48ee370 100644 --- a/lib/bb/data_smart.py +++ b/lib/bb/data_smart.py @@ -30,6 +30,7 @@ BitBake build tools. import traceback import copy, re +import sys from collections import MutableMapping import logging import hashlib @@ -113,6 +114,8 @@ class DataSmart(MutableMapping): def __init__(self, special = COWDictBase.copy(), seen = COWDictBase.copy() ): self.dict = {} self.history = {} + self.include_history = [] + self.include_stack = [(-1, self.include_history)] # cookie monster tribute self._special_values = special @@ -121,6 +124,25 @@ class DataSmart(MutableMapping): self.expand_cache = {} + def includeLog(self, filename): + """includeLog(included_file) shows that the file was included + by the currently-processed file or context.""" + if self._tracking_enabled: + event = (filename, []) + position = (len(self.include_stack[-1][1]), event[1]) + self.include_stack[-1][1].append(event) + self.include_stack.append(position) + + def includeLogDone(self, filename): + if self._tracking_enabled: + if len(self.include_stack) > 1: + self.include_stack.pop() + else: + bb.warn("Uh-oh: includeLogDone(%s) tried to empty the stack." % filename) + + def getIncludeHistory(self): + return self.include_history + def tracking(self): return self._tracking_enabled @@ -455,9 +477,22 @@ class DataSmart(MutableMapping): # we really want this to be a DataSmart... data = DataSmart(seen=self._seen_overrides.copy(), special=self._special_values.copy()) data.dict["_data"] = self.dict - data.history = self.history.copy() - data._tracking_enabled = self._tracking_enabled - + if self._tracking_enabled: + data._tracking_enabled = self._tracking_enabled + data.history = self.history.copy() + data.include_history = copy.deepcopy(self.include_history) + data.include_stack = [] + oldref = self.include_history + newref = data.include_history + # Create corresponding references, if we can + try: + for item in self.include_stack: + if item[0] >= 0: + newref = newref[item[0]] + newevent = (item[0], newref) + data.include_stack.append(newevent) + except Exception: + sys.exc_clear() return data def expandVarref(self, variable, parents=False, filename = None, lineno = None): diff --git a/lib/bb/parse/__init__.py b/lib/bb/parse/__init__.py index 7b9c47e..0ea6a55 100644 --- a/lib/bb/parse/__init__.py +++ b/lib/bb/parse/__init__.py @@ -88,7 +88,11 @@ def handle(fn, data, include = 0): """Call the handler that is appropriate for this file""" for h in handlers: if h['supports'](fn, data): - return h['handle'](fn, data, include) + data.includeLog(fn) + try: + return h['handle'](fn, data, include) + finally: + data.includeLogDone(fn) raise ParseError("not a BitBake file", fn) def init(fn, data):