diff options
Diffstat (limited to 'bitbake/lib/bb/cookerdata.py')
| -rw-r--r-- | bitbake/lib/bb/cookerdata.py | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/bitbake/lib/bb/cookerdata.py b/bitbake/lib/bb/cookerdata.py new file mode 100644 index 0000000000..b9b9e16675 --- /dev/null +++ b/bitbake/lib/bb/cookerdata.py | |||
| @@ -0,0 +1,305 @@ | |||
| 1 | #!/usr/bin/env python | ||
| 2 | # ex:ts=4:sw=4:sts=4:et | ||
| 3 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 4 | # | ||
| 5 | # Copyright (C) 2003, 2004 Chris Larson | ||
| 6 | # Copyright (C) 2003, 2004 Phil Blundell | ||
| 7 | # Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer | ||
| 8 | # Copyright (C) 2005 Holger Hans Peter Freyther | ||
| 9 | # Copyright (C) 2005 ROAD GmbH | ||
| 10 | # Copyright (C) 2006 Richard Purdie | ||
| 11 | # | ||
| 12 | # This program is free software; you can redistribute it and/or modify | ||
| 13 | # it under the terms of the GNU General Public License version 2 as | ||
| 14 | # published by the Free Software Foundation. | ||
| 15 | # | ||
| 16 | # This program is distributed in the hope that it will be useful, | ||
| 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | # GNU General Public License for more details. | ||
| 20 | # | ||
| 21 | # You should have received a copy of the GNU General Public License along | ||
| 22 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 23 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 24 | |||
| 25 | import os, sys | ||
| 26 | from functools import wraps | ||
| 27 | import logging | ||
| 28 | import bb | ||
| 29 | from bb import data | ||
| 30 | import bb.parse | ||
| 31 | |||
| 32 | logger = logging.getLogger("BitBake") | ||
| 33 | parselog = logging.getLogger("BitBake.Parsing") | ||
| 34 | |||
| 35 | class ConfigParameters(object): | ||
| 36 | def __init__(self): | ||
| 37 | self.options, targets = self.parseCommandLine() | ||
| 38 | self.environment = self.parseEnvironment() | ||
| 39 | |||
| 40 | self.options.pkgs_to_build = targets or [] | ||
| 41 | |||
| 42 | self.options.tracking = False | ||
| 43 | if hasattr(self.options, "show_environment") and self.options.show_environment: | ||
| 44 | self.options.tracking = True | ||
| 45 | |||
| 46 | for key, val in self.options.__dict__.items(): | ||
| 47 | setattr(self, key, val) | ||
| 48 | |||
| 49 | def parseCommandLine(self): | ||
| 50 | raise Exception("Caller must implement commandline option parsing") | ||
| 51 | |||
| 52 | def parseEnvironment(self): | ||
| 53 | return os.environ.copy() | ||
| 54 | |||
| 55 | def updateFromServer(self, server): | ||
| 56 | if not self.options.cmd: | ||
| 57 | defaulttask, error = server.runCommand(["getVariable", "BB_DEFAULT_TASK"]) | ||
| 58 | if error: | ||
| 59 | raise Exception("Unable to get the value of BB_DEFAULT_TASK from the server: %s" % error) | ||
| 60 | self.options.cmd = defaulttask or "build" | ||
| 61 | _, error = server.runCommand(["setConfig", "cmd", self.options.cmd]) | ||
| 62 | if error: | ||
| 63 | raise Exception("Unable to set configuration option 'cmd' on the server: %s" % error) | ||
| 64 | |||
| 65 | if not self.options.pkgs_to_build: | ||
| 66 | bbpkgs, error = server.runCommand(["getVariable", "BBPKGS"]) | ||
| 67 | if error: | ||
| 68 | raise Exception("Unable to get the value of BBPKGS from the server: %s" % error) | ||
| 69 | if bbpkgs: | ||
| 70 | self.options.pkgs_to_build.extend(bbpkgs.split()) | ||
| 71 | |||
| 72 | def parseActions(self): | ||
| 73 | # Parse any commandline into actions | ||
| 74 | action = {'action':None, 'msg':None} | ||
| 75 | if self.options.show_environment: | ||
| 76 | if 'world' in self.options.pkgs_to_build: | ||
| 77 | action['msg'] = "'world' is not a valid target for --environment." | ||
| 78 | elif 'universe' in self.options.pkgs_to_build: | ||
| 79 | action['msg'] = "'universe' is not a valid target for --environment." | ||
| 80 | elif len(self.options.pkgs_to_build) > 1: | ||
| 81 | action['msg'] = "Only one target can be used with the --environment option." | ||
| 82 | elif self.options.buildfile and len(self.options.pkgs_to_build) > 0: | ||
| 83 | action['msg'] = "No target should be used with the --environment and --buildfile options." | ||
| 84 | elif len(self.options.pkgs_to_build) > 0: | ||
| 85 | action['action'] = ["showEnvironmentTarget", self.options.pkgs_to_build] | ||
| 86 | else: | ||
| 87 | action['action'] = ["showEnvironment", self.options.buildfile] | ||
| 88 | elif self.options.buildfile is not None: | ||
| 89 | action['action'] = ["buildFile", self.options.buildfile, self.options.cmd] | ||
| 90 | elif self.options.revisions_changed: | ||
| 91 | action['action'] = ["compareRevisions"] | ||
| 92 | elif self.options.show_versions: | ||
| 93 | action['action'] = ["showVersions"] | ||
| 94 | elif self.options.parse_only: | ||
| 95 | action['action'] = ["parseFiles"] | ||
| 96 | elif self.options.dot_graph: | ||
| 97 | if self.options.pkgs_to_build: | ||
| 98 | action['action'] = ["generateDotGraph", self.options.pkgs_to_build, self.options.cmd] | ||
| 99 | else: | ||
| 100 | action['msg'] = "Please specify a package name for dependency graph generation." | ||
| 101 | else: | ||
| 102 | if self.options.pkgs_to_build: | ||
| 103 | action['action'] = ["buildTargets", self.options.pkgs_to_build, self.options.cmd] | ||
| 104 | else: | ||
| 105 | #action['msg'] = "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information." | ||
| 106 | action = None | ||
| 107 | self.options.initialaction = action | ||
| 108 | return action | ||
| 109 | |||
| 110 | class CookerConfiguration(object): | ||
| 111 | """ | ||
| 112 | Manages build options and configurations for one run | ||
| 113 | """ | ||
| 114 | |||
| 115 | def __init__(self): | ||
| 116 | self.debug_domains = [] | ||
| 117 | self.extra_assume_provided = [] | ||
| 118 | self.prefile = [] | ||
| 119 | self.postfile = [] | ||
| 120 | self.debug = 0 | ||
| 121 | self.cmd = None | ||
| 122 | self.abort = True | ||
| 123 | self.force = False | ||
| 124 | self.profile = False | ||
| 125 | self.nosetscene = False | ||
| 126 | self.invalidate_stamp = False | ||
| 127 | self.dump_signatures = [] | ||
| 128 | self.dry_run = False | ||
| 129 | self.tracking = False | ||
| 130 | self.interface = [] | ||
| 131 | |||
| 132 | self.env = {} | ||
| 133 | |||
| 134 | def setConfigParameters(self, parameters): | ||
| 135 | for key in self.__dict__.keys(): | ||
| 136 | if key in parameters.options.__dict__: | ||
| 137 | setattr(self, key, parameters.options.__dict__[key]) | ||
| 138 | self.env = parameters.environment.copy() | ||
| 139 | self.tracking = parameters.tracking | ||
| 140 | |||
| 141 | def setServerRegIdleCallback(self, srcb): | ||
| 142 | self.server_register_idlecallback = srcb | ||
| 143 | |||
| 144 | def __getstate__(self): | ||
| 145 | state = {} | ||
| 146 | for key in self.__dict__.keys(): | ||
| 147 | if key == "server_register_idlecallback": | ||
| 148 | state[key] = None | ||
| 149 | else: | ||
| 150 | state[key] = getattr(self, key) | ||
| 151 | return state | ||
| 152 | |||
| 153 | def __setstate__(self,state): | ||
| 154 | for k in state: | ||
| 155 | setattr(self, k, state[k]) | ||
| 156 | |||
| 157 | |||
| 158 | def catch_parse_error(func): | ||
| 159 | """Exception handling bits for our parsing""" | ||
| 160 | @wraps(func) | ||
| 161 | def wrapped(fn, *args): | ||
| 162 | try: | ||
| 163 | return func(fn, *args) | ||
| 164 | except (IOError, bb.parse.ParseError, bb.data_smart.ExpansionError) as exc: | ||
| 165 | import traceback | ||
| 166 | parselog.critical( traceback.format_exc()) | ||
| 167 | parselog.critical("Unable to parse %s: %s" % (fn, exc)) | ||
| 168 | sys.exit(1) | ||
| 169 | return wrapped | ||
| 170 | |||
| 171 | @catch_parse_error | ||
| 172 | def parse_config_file(fn, data, include=True): | ||
| 173 | return bb.parse.handle(fn, data, include) | ||
| 174 | |||
| 175 | @catch_parse_error | ||
| 176 | def _inherit(bbclass, data): | ||
| 177 | bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data) | ||
| 178 | return data | ||
| 179 | |||
| 180 | def findConfigFile(configfile, data): | ||
| 181 | search = [] | ||
| 182 | bbpath = data.getVar("BBPATH", True) | ||
| 183 | if bbpath: | ||
| 184 | for i in bbpath.split(":"): | ||
| 185 | search.append(os.path.join(i, "conf", configfile)) | ||
| 186 | path = os.getcwd() | ||
| 187 | while path != "/": | ||
| 188 | search.append(os.path.join(path, "conf", configfile)) | ||
| 189 | path, _ = os.path.split(path) | ||
| 190 | |||
| 191 | for i in search: | ||
| 192 | if os.path.exists(i): | ||
| 193 | return i | ||
| 194 | |||
| 195 | return None | ||
| 196 | |||
| 197 | class CookerDataBuilder(object): | ||
| 198 | |||
| 199 | def __init__(self, cookercfg, worker = False): | ||
| 200 | |||
| 201 | self.prefiles = cookercfg.prefile | ||
| 202 | self.postfiles = cookercfg.postfile | ||
| 203 | self.tracking = cookercfg.tracking | ||
| 204 | |||
| 205 | bb.utils.set_context(bb.utils.clean_context()) | ||
| 206 | bb.event.set_class_handlers(bb.event.clean_class_handlers()) | ||
| 207 | self.data = bb.data.init() | ||
| 208 | if self.tracking: | ||
| 209 | self.data.enableTracking() | ||
| 210 | |||
| 211 | # Keep a datastore of the initial environment variables and their | ||
| 212 | # values from when BitBake was launched to enable child processes | ||
| 213 | # to use environment variables which have been cleaned from the | ||
| 214 | # BitBake processes env | ||
| 215 | self.savedenv = bb.data.init() | ||
| 216 | for k in cookercfg.env: | ||
| 217 | self.savedenv.setVar(k, cookercfg.env[k]) | ||
| 218 | |||
| 219 | filtered_keys = bb.utils.approved_variables() | ||
| 220 | bb.data.inheritFromOS(self.data, self.savedenv, filtered_keys) | ||
| 221 | self.data.setVar("BB_ORIGENV", self.savedenv) | ||
| 222 | |||
| 223 | if worker: | ||
| 224 | self.data.setVar("BB_WORKERCONTEXT", "1") | ||
| 225 | |||
| 226 | def parseBaseConfiguration(self): | ||
| 227 | try: | ||
| 228 | self.parseConfigurationFiles(self.prefiles, self.postfiles) | ||
| 229 | except SyntaxError: | ||
| 230 | sys.exit(1) | ||
| 231 | except Exception: | ||
| 232 | logger.exception("Error parsing configuration files") | ||
| 233 | sys.exit(1) | ||
| 234 | |||
| 235 | def _findLayerConf(self, data): | ||
| 236 | return findConfigFile("bblayers.conf", data) | ||
| 237 | |||
| 238 | def parseConfigurationFiles(self, prefiles, postfiles): | ||
| 239 | data = self.data | ||
| 240 | bb.parse.init_parser(data) | ||
| 241 | |||
| 242 | # Parse files for loading *before* bitbake.conf and any includes | ||
| 243 | for f in prefiles: | ||
| 244 | data = parse_config_file(f, data) | ||
| 245 | |||
| 246 | layerconf = self._findLayerConf(data) | ||
| 247 | if layerconf: | ||
| 248 | parselog.debug(2, "Found bblayers.conf (%s)", layerconf) | ||
| 249 | # By definition bblayers.conf is in conf/ of TOPDIR. | ||
| 250 | # We may have been called with cwd somewhere else so reset TOPDIR | ||
| 251 | data.setVar("TOPDIR", os.path.dirname(os.path.dirname(layerconf))) | ||
| 252 | data = parse_config_file(layerconf, data) | ||
| 253 | |||
| 254 | layers = (data.getVar('BBLAYERS', True) or "").split() | ||
| 255 | |||
| 256 | data = bb.data.createCopy(data) | ||
| 257 | for layer in layers: | ||
| 258 | parselog.debug(2, "Adding layer %s", layer) | ||
| 259 | data.setVar('LAYERDIR', layer) | ||
| 260 | data = parse_config_file(os.path.join(layer, "conf", "layer.conf"), data) | ||
| 261 | data.expandVarref('LAYERDIR') | ||
| 262 | |||
| 263 | data.delVar('LAYERDIR') | ||
| 264 | |||
| 265 | if not data.getVar("BBPATH", True): | ||
| 266 | msg = "The BBPATH variable is not set" | ||
| 267 | if not layerconf: | ||
| 268 | msg += (" and bitbake did not find a conf/bblayers.conf file in" | ||
| 269 | " the expected location.\nMaybe you accidentally" | ||
| 270 | " invoked bitbake from the wrong directory?") | ||
| 271 | raise SystemExit(msg) | ||
| 272 | |||
| 273 | data = parse_config_file(os.path.join("conf", "bitbake.conf"), data) | ||
| 274 | |||
| 275 | # Parse files for loading *after* bitbake.conf and any includes | ||
| 276 | for p in postfiles: | ||
| 277 | data = parse_config_file(p, data) | ||
| 278 | |||
| 279 | # Handle any INHERITs and inherit the base class | ||
| 280 | bbclasses = ["base"] + (data.getVar('INHERIT', True) or "").split() | ||
| 281 | for bbclass in bbclasses: | ||
| 282 | data = _inherit(bbclass, data) | ||
| 283 | |||
| 284 | # Nomally we only register event handlers at the end of parsing .bb files | ||
| 285 | # We register any handlers we've found so far here... | ||
| 286 | for var in data.getVar('__BBHANDLERS') or []: | ||
| 287 | bb.event.register(var, data.getVar(var), (data.getVarFlag(var, "eventmask", True) or "").split()) | ||
| 288 | |||
| 289 | if data.getVar("BB_WORKERCONTEXT", False) is None: | ||
| 290 | bb.fetch.fetcher_init(data) | ||
| 291 | bb.codeparser.parser_cache_init(data) | ||
| 292 | bb.event.fire(bb.event.ConfigParsed(), data) | ||
| 293 | |||
| 294 | if data.getVar("BB_INVALIDCONF") is True: | ||
| 295 | data.setVar("BB_INVALIDCONF", False) | ||
| 296 | self.parseConfigurationFiles(self.prefiles, self.postfiles) | ||
| 297 | return | ||
| 298 | |||
| 299 | bb.parse.init_parser(data) | ||
| 300 | data.setVar('BBINCLUDED',bb.parse.get_file_depends(data)) | ||
| 301 | self.data = data | ||
| 302 | self.data_hash = data.get_hash() | ||
| 303 | |||
| 304 | |||
| 305 | |||
