diff options
Diffstat (limited to 'bitbake/lib/bb/cookerdata.py')
-rw-r--r-- | bitbake/lib/bb/cookerdata.py | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/bitbake/lib/bb/cookerdata.py b/bitbake/lib/bb/cookerdata.py new file mode 100644 index 0000000000..e640ed0f35 --- /dev/null +++ b/bitbake/lib/bb/cookerdata.py | |||
@@ -0,0 +1,304 @@ | |||
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 = False | ||
128 | self.dry_run = False | ||
129 | self.tracking = False | ||
130 | |||
131 | self.env = {} | ||
132 | |||
133 | def setConfigParameters(self, parameters): | ||
134 | for key in self.__dict__.keys(): | ||
135 | if key in parameters.options.__dict__: | ||
136 | setattr(self, key, parameters.options.__dict__[key]) | ||
137 | self.env = parameters.environment.copy() | ||
138 | self.tracking = parameters.tracking | ||
139 | |||
140 | def setServerRegIdleCallback(self, srcb): | ||
141 | self.server_register_idlecallback = srcb | ||
142 | |||
143 | def __getstate__(self): | ||
144 | state = {} | ||
145 | for key in self.__dict__.keys(): | ||
146 | if key == "server_register_idlecallback": | ||
147 | state[key] = None | ||
148 | else: | ||
149 | state[key] = getattr(self, key) | ||
150 | return state | ||
151 | |||
152 | def __setstate__(self,state): | ||
153 | for k in state: | ||
154 | setattr(self, k, state[k]) | ||
155 | |||
156 | |||
157 | def catch_parse_error(func): | ||
158 | """Exception handling bits for our parsing""" | ||
159 | @wraps(func) | ||
160 | def wrapped(fn, *args): | ||
161 | try: | ||
162 | return func(fn, *args) | ||
163 | except (IOError, bb.parse.ParseError, bb.data_smart.ExpansionError) as exc: | ||
164 | import traceback | ||
165 | parselog.critical( traceback.format_exc()) | ||
166 | parselog.critical("Unable to parse %s: %s" % (fn, exc)) | ||
167 | sys.exit(1) | ||
168 | return wrapped | ||
169 | |||
170 | @catch_parse_error | ||
171 | def parse_config_file(fn, data, include=True): | ||
172 | return bb.parse.handle(fn, data, include) | ||
173 | |||
174 | @catch_parse_error | ||
175 | def _inherit(bbclass, data): | ||
176 | bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data) | ||
177 | return data | ||
178 | |||
179 | def findConfigFile(configfile, data): | ||
180 | search = [] | ||
181 | bbpath = data.getVar("BBPATH", True) | ||
182 | if bbpath: | ||
183 | for i in bbpath.split(":"): | ||
184 | search.append(os.path.join(i, "conf", configfile)) | ||
185 | path = os.getcwd() | ||
186 | while path != "/": | ||
187 | search.append(os.path.join(path, "conf", configfile)) | ||
188 | path, _ = os.path.split(path) | ||
189 | |||
190 | for i in search: | ||
191 | if os.path.exists(i): | ||
192 | return i | ||
193 | |||
194 | return None | ||
195 | |||
196 | class CookerDataBuilder(object): | ||
197 | |||
198 | def __init__(self, cookercfg, worker = False): | ||
199 | |||
200 | self.prefiles = cookercfg.prefile | ||
201 | self.postfiles = cookercfg.postfile | ||
202 | self.tracking = cookercfg.tracking | ||
203 | |||
204 | bb.utils.set_context(bb.utils.clean_context()) | ||
205 | bb.event.set_class_handlers(bb.event.clean_class_handlers()) | ||
206 | self.data = bb.data.init() | ||
207 | if self.tracking: | ||
208 | self.data.enableTracking() | ||
209 | |||
210 | # Keep a datastore of the initial environment variables and their | ||
211 | # values from when BitBake was launched to enable child processes | ||
212 | # to use environment variables which have been cleaned from the | ||
213 | # BitBake processes env | ||
214 | self.savedenv = bb.data.init() | ||
215 | for k in cookercfg.env: | ||
216 | self.savedenv.setVar(k, cookercfg.env[k]) | ||
217 | |||
218 | filtered_keys = bb.utils.approved_variables() | ||
219 | bb.data.inheritFromOS(self.data, self.savedenv, filtered_keys) | ||
220 | self.data.setVar("BB_ORIGENV", self.savedenv) | ||
221 | |||
222 | if worker: | ||
223 | self.data.setVar("BB_WORKERCONTEXT", "1") | ||
224 | |||
225 | def parseBaseConfiguration(self): | ||
226 | try: | ||
227 | self.parseConfigurationFiles(self.prefiles, self.postfiles) | ||
228 | except SyntaxError: | ||
229 | sys.exit(1) | ||
230 | except Exception: | ||
231 | logger.exception("Error parsing configuration files") | ||
232 | sys.exit(1) | ||
233 | |||
234 | def _findLayerConf(self, data): | ||
235 | return findConfigFile("bblayers.conf", data) | ||
236 | |||
237 | def parseConfigurationFiles(self, prefiles, postfiles): | ||
238 | data = self.data | ||
239 | bb.parse.init_parser(data) | ||
240 | |||
241 | # Parse files for loading *before* bitbake.conf and any includes | ||
242 | for f in prefiles: | ||
243 | data = parse_config_file(f, data) | ||
244 | |||
245 | layerconf = self._findLayerConf(data) | ||
246 | if layerconf: | ||
247 | parselog.debug(2, "Found bblayers.conf (%s)", layerconf) | ||
248 | # By definition bblayers.conf is in conf/ of TOPDIR. | ||
249 | # We may have been called with cwd somewhere else so reset TOPDIR | ||
250 | data.setVar("TOPDIR", os.path.dirname(os.path.dirname(layerconf))) | ||
251 | data = parse_config_file(layerconf, data) | ||
252 | |||
253 | layers = (data.getVar('BBLAYERS', True) or "").split() | ||
254 | |||
255 | data = bb.data.createCopy(data) | ||
256 | for layer in layers: | ||
257 | parselog.debug(2, "Adding layer %s", layer) | ||
258 | data.setVar('LAYERDIR', layer) | ||
259 | data = parse_config_file(os.path.join(layer, "conf", "layer.conf"), data) | ||
260 | data.expandVarref('LAYERDIR') | ||
261 | |||
262 | data.delVar('LAYERDIR') | ||
263 | |||
264 | if not data.getVar("BBPATH", True): | ||
265 | msg = "The BBPATH variable is not set" | ||
266 | if not layerconf: | ||
267 | msg += (" and bitbake did not find a conf/bblayers.conf file in" | ||
268 | " the expected location.\nMaybe you accidentally" | ||
269 | " invoked bitbake from the wrong directory?") | ||
270 | raise SystemExit(msg) | ||
271 | |||
272 | data = parse_config_file(os.path.join("conf", "bitbake.conf"), data) | ||
273 | |||
274 | # Parse files for loading *after* bitbake.conf and any includes | ||
275 | for p in postfiles: | ||
276 | data = parse_config_file(p, data) | ||
277 | |||
278 | # Handle any INHERITs and inherit the base class | ||
279 | bbclasses = ["base"] + (data.getVar('INHERIT', True) or "").split() | ||
280 | for bbclass in bbclasses: | ||
281 | data = _inherit(bbclass, data) | ||
282 | |||
283 | # Nomally we only register event handlers at the end of parsing .bb files | ||
284 | # We register any handlers we've found so far here... | ||
285 | for var in data.getVar('__BBHANDLERS') or []: | ||
286 | bb.event.register(var, data.getVar(var), (data.getVarFlag(var, "eventmask", True) or "").split()) | ||
287 | |||
288 | if data.getVar("BB_WORKERCONTEXT", False) is None: | ||
289 | bb.fetch.fetcher_init(data) | ||
290 | bb.codeparser.parser_cache_init(data) | ||
291 | bb.event.fire(bb.event.ConfigParsed(), data) | ||
292 | |||
293 | if data.getVar("BB_INVALIDCONF") is True: | ||
294 | data.setVar("BB_INVALIDCONF", False) | ||
295 | self.parseConfigurationFiles(self.prefiles, self.postfiles) | ||
296 | return | ||
297 | |||
298 | bb.parse.init_parser(data) | ||
299 | data.setVar('BBINCLUDED',bb.parse.get_file_depends(data)) | ||
300 | self.data = data | ||
301 | self.data_hash = data.get_hash() | ||
302 | |||
303 | |||
304 | |||