diff options
Diffstat (limited to 'bitbake/lib/bb/cookerdata.py')
-rw-r--r-- | bitbake/lib/bb/cookerdata.py | 145 |
1 files changed, 112 insertions, 33 deletions
diff --git a/bitbake/lib/bb/cookerdata.py b/bitbake/lib/bb/cookerdata.py index d54ac932e58..0649e409957 100644 --- a/bitbake/lib/bb/cookerdata.py +++ b/bitbake/lib/bb/cookerdata.py @@ -160,12 +160,7 @@ def catch_parse_error(func): def wrapped(fn, *args): try: return func(fn, *args) - except IOError as exc: - import traceback - parselog.critical(traceback.format_exc()) - parselog.critical("Unable to parse %s: %s" % (fn, exc)) - raise bb.BBHandledException() - except bb.data_smart.ExpansionError as exc: + except Exception as exc: import traceback bbdir = os.path.dirname(__file__) + os.sep @@ -177,14 +172,11 @@ def catch_parse_error(func): break parselog.critical("Unable to parse %s" % fn, exc_info=(exc_class, exc, tb)) raise bb.BBHandledException() - except bb.parse.ParseError as exc: - parselog.critical(str(exc)) - raise bb.BBHandledException() return wrapped @catch_parse_error def parse_config_file(fn, data, include=True): - return bb.parse.handle(fn, data, include) + return bb.parse.handle(fn, data, include, baseconfig=True) @catch_parse_error def _inherit(bbclass, data): @@ -254,6 +246,7 @@ class CookerDataBuilder(object): filtered_keys = bb.utils.approved_variables() bb.data.inheritFromOS(self.basedata, self.savedenv, filtered_keys) self.basedata.setVar("BB_ORIGENV", self.savedenv) + self.basedata.setVar("__bbclasstype", "global") if worker: self.basedata.setVar("BB_WORKERCONTEXT", "1") @@ -262,6 +255,7 @@ class CookerDataBuilder(object): self.mcdata = {} def parseBaseConfiguration(self, worker=False): + mcdata = {} data_hash = hashlib.sha256() try: self.data = self.parseConfigurationFiles(self.prefiles, self.postfiles) @@ -269,7 +263,6 @@ class CookerDataBuilder(object): if self.data.getVar("BB_WORKERCONTEXT", False) is None and not worker: bb.fetch.fetcher_init(self.data) bb.parse.init_parser(self.data) - bb.codeparser.parser_cache_init(self.data) bb.event.fire(bb.event.ConfigParsed(), self.data) @@ -287,29 +280,25 @@ class CookerDataBuilder(object): bb.parse.init_parser(self.data) data_hash.update(self.data.get_hash().encode('utf-8')) - self.mcdata[''] = self.data + mcdata[''] = self.data multiconfig = (self.data.getVar("BBMULTICONFIG") or "").split() for config in multiconfig: if config[0].isdigit(): bb.fatal("Multiconfig name '%s' is invalid as multiconfigs cannot start with a digit" % config) - mcdata = self.parseConfigurationFiles(self.prefiles, self.postfiles, config) - bb.event.fire(bb.event.ConfigParsed(), mcdata) - self.mcdata[config] = mcdata - data_hash.update(mcdata.get_hash().encode('utf-8')) + parsed_mcdata = self.parseConfigurationFiles(self.prefiles, self.postfiles, config) + bb.event.fire(bb.event.ConfigParsed(), parsed_mcdata) + mcdata[config] = parsed_mcdata + data_hash.update(parsed_mcdata.get_hash().encode('utf-8')) if multiconfig: - bb.event.fire(bb.event.MultiConfigParsed(self.mcdata), self.data) + bb.event.fire(bb.event.MultiConfigParsed(mcdata), self.data) self.data_hash = data_hash.hexdigest() - except (SyntaxError, bb.BBHandledException): - raise bb.BBHandledException() except bb.data_smart.ExpansionError as e: logger.error(str(e)) raise bb.BBHandledException() - except Exception: - logger.exception("Error parsing configuration files") - raise bb.BBHandledException() + bb.codeparser.update_module_dependencies(self.data) # Handle obsolete variable names d = self.data @@ -330,17 +319,23 @@ class CookerDataBuilder(object): if issues: raise bb.BBHandledException() + for mc in mcdata: + mcdata[mc].renameVar("__depends", "__base_depends") + mcdata[mc].setVar("__bbclasstype", "recipe") + # Create a copy so we can reset at a later date when UIs disconnect - self.origdata = self.data - self.data = bb.data.createCopy(self.origdata) - self.mcdata[''] = self.data + self.mcorigdata = mcdata + for mc in mcdata: + self.mcdata[mc] = bb.data.createCopy(mcdata[mc]) + self.data = self.mcdata[''] def reset(self): # We may not have run parseBaseConfiguration() yet - if not hasattr(self, 'origdata'): + if not hasattr(self, 'mcorigdata'): return - self.data = bb.data.createCopy(self.origdata) - self.mcdata[''] = self.data + for mc in self.mcorigdata: + self.mcdata[mc] = bb.data.createCopy(self.mcorigdata[mc]) + self.data = self.mcdata[''] def _findLayerConf(self, data): return findConfigFile("bblayers.conf", data) @@ -355,12 +350,17 @@ class CookerDataBuilder(object): layerconf = self._findLayerConf(data) if layerconf: - parselog.debug(2, "Found bblayers.conf (%s)", layerconf) + parselog.debug2("Found bblayers.conf (%s)", layerconf) # By definition bblayers.conf is in conf/ of TOPDIR. # We may have been called with cwd somewhere else so reset TOPDIR data.setVar("TOPDIR", os.path.dirname(os.path.dirname(layerconf))) data = parse_config_file(layerconf, data) + if not data.getVar("BB_CACHEDIR"): + data.setVar("BB_CACHEDIR", "${TOPDIR}/cache") + + bb.codeparser.parser_cache_init(data.getVar("BB_CACHEDIR")) + layers = (data.getVar('BBLAYERS') or "").split() broken_layers = [] @@ -382,8 +382,10 @@ class CookerDataBuilder(object): parselog.critical("Please check BBLAYERS in %s" % (layerconf)) raise bb.BBHandledException() + layerseries = None + compat_entries = {} for layer in layers: - parselog.debug(2, "Adding layer %s", layer) + parselog.debug2("Adding layer %s", layer) if 'HOME' in approved and '~' in layer: layer = os.path.expanduser(layer) if layer.endswith('/'): @@ -394,8 +396,27 @@ class CookerDataBuilder(object): data.expandVarref('LAYERDIR') data.expandVarref('LAYERDIR_RE') + # Sadly we can't have nice things. + # Some layers think they're going to be 'clever' and copy the values from + # another layer, e.g. using ${LAYERSERIES_COMPAT_core}. The whole point of + # this mechanism is to make it clear which releases a layer supports and + # show when a layer master branch is bitrotting and is unmaintained. + # We therefore avoid people doing this here. + collections = (data.getVar('BBFILE_COLLECTIONS') or "").split() + for c in collections: + compat_entry = data.getVar("LAYERSERIES_COMPAT_%s" % c) + if compat_entry: + compat_entries[c] = set(compat_entry.split()) + data.delVar("LAYERSERIES_COMPAT_%s" % c) + if not layerseries: + layerseries = set((data.getVar("LAYERSERIES_CORENAMES") or "").split()) + if layerseries: + data.delVar("LAYERSERIES_CORENAMES") + data.delVar('LAYERDIR_RE') data.delVar('LAYERDIR') + for c in compat_entries: + data.setVar("LAYERSERIES_COMPAT_%s" % c, " ".join(sorted(compat_entries[c]))) bbfiles_dynamic = (data.getVar('BBFILES_DYNAMIC') or "").split() collections = (data.getVar('BBFILE_COLLECTIONS') or "").split() @@ -414,13 +435,15 @@ class CookerDataBuilder(object): if invalid: bb.fatal("BBFILES_DYNAMIC entries must be of the form {!}<collection name>:<filename pattern>, not:\n %s" % "\n ".join(invalid)) - layerseries = set((data.getVar("LAYERSERIES_CORENAMES") or "").split()) collections_tmp = collections[:] for c in collections: collections_tmp.remove(c) if c in collections_tmp: bb.fatal("Found duplicated BBFILE_COLLECTIONS '%s', check bblayers.conf or layer.conf to fix it." % c) - compat = set((data.getVar("LAYERSERIES_COMPAT_%s" % c) or "").split()) + + compat = set() + if c in compat_entries: + compat = compat_entries[c] if compat and not layerseries: bb.fatal("No core layer found to work with layer '%s'. Missing entry in bblayers.conf?" % c) if compat and not (compat & layerseries): @@ -429,16 +452,21 @@ class CookerDataBuilder(object): elif not compat and not data.getVar("BB_WORKERCONTEXT"): bb.warn("Layer %s should set LAYERSERIES_COMPAT_%s in its conf/layer.conf file to list the core layer names it is compatible with." % (c, c)) + data.setVar("LAYERSERIES_CORENAMES", " ".join(sorted(layerseries))) + if not data.getVar("BBPATH"): msg = "The BBPATH variable is not set" if not layerconf: msg += (" and bitbake did not find a conf/bblayers.conf file in" " the expected location.\nMaybe you accidentally" " invoked bitbake from the wrong directory?") - raise SystemExit(msg) + bb.fatal(msg) if not data.getVar("TOPDIR"): data.setVar("TOPDIR", os.path.abspath(os.getcwd())) + if not data.getVar("BB_CACHEDIR"): + data.setVar("BB_CACHEDIR", "${TOPDIR}/cache") + bb.codeparser.parser_cache_init(data.getVar("BB_CACHEDIR")) data = parse_config_file(os.path.join("conf", "bitbake.conf"), data) @@ -465,3 +493,54 @@ class CookerDataBuilder(object): return data + @staticmethod + def _parse_recipe(bb_data, bbfile, appends, mc, layername): + bb_data.setVar("__BBMULTICONFIG", mc) + bb_data.setVar("FILE_LAYERNAME", layername) + + bbfile_loc = os.path.abspath(os.path.dirname(bbfile)) + bb.parse.cached_mtime_noerror(bbfile_loc) + + if appends: + bb_data.setVar('__BBAPPEND', " ".join(appends)) + + return bb.parse.handle(bbfile, bb_data) + + def parseRecipeVariants(self, bbfile, appends, virtonly=False, mc=None, layername=None): + """ + Load and parse one .bb build file + Return the data and whether parsing resulted in the file being skipped + """ + + if virtonly: + (bbfile, virtual, mc) = bb.cache.virtualfn2realfn(bbfile) + bb_data = self.mcdata[mc].createCopy() + bb_data.setVar("__ONLYFINALISE", virtual or "default") + return self._parse_recipe(bb_data, bbfile, appends, mc, layername) + + if mc is not None: + bb_data = self.mcdata[mc].createCopy() + return self._parse_recipe(bb_data, bbfile, appends, mc, layername) + + bb_data = self.data.createCopy() + datastores = self._parse_recipe(bb_data, bbfile, appends, '', layername) + + for mc in self.mcdata: + if not mc: + continue + bb_data = self.mcdata[mc].createCopy() + newstores = self._parse_recipe(bb_data, bbfile, appends, mc, layername) + for ns in newstores: + datastores["mc:%s:%s" % (mc, ns)] = newstores[ns] + + return datastores + + def parseRecipe(self, virtualfn, appends, layername): + """ + Return a complete set of data for fn. + To do this, we need to parse the file. + """ + logger.debug("Parsing %s (full)" % virtualfn) + (fn, virtual, mc) = bb.cache.virtualfn2realfn(virtualfn) + datastores = self.parseRecipeVariants(virtualfn, appends, virtonly=True, layername=layername) + return datastores[virtual] |