diff options
-rw-r--r-- | bitbake/lib/bb/tinfoil.py | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/bitbake/lib/bb/tinfoil.py b/bitbake/lib/bb/tinfoil.py index 456cbf80be..30d6c9af3e 100644 --- a/bitbake/lib/bb/tinfoil.py +++ b/bitbake/lib/bb/tinfoil.py | |||
@@ -217,6 +217,82 @@ class TinfoilCookerAdapter: | |||
217 | return self.tinfoil.find_best_provider(pn) | 217 | return self.tinfoil.find_best_provider(pn) |
218 | 218 | ||
219 | 219 | ||
220 | class TinfoilRecipeInfo: | ||
221 | """ | ||
222 | Provides a convenient representation of the cached information for a single recipe. | ||
223 | Some attributes are set on construction, others are read on-demand (which internally | ||
224 | may result in a remote procedure call to the bitbake server the first time). | ||
225 | Note that only information which is cached is available through this object - if | ||
226 | you need other variable values you will need to parse the recipe using | ||
227 | Tinfoil.parse_recipe(). | ||
228 | """ | ||
229 | def __init__(self, recipecache, d, pn, fn, fns): | ||
230 | self._recipecache = recipecache | ||
231 | self._d = d | ||
232 | self.pn = pn | ||
233 | self.fn = fn | ||
234 | self.fns = fns | ||
235 | self.inherit_files = recipecache.inherits[fn] | ||
236 | self.depends = recipecache.deps[fn] | ||
237 | (self.pe, self.pv, self.pr) = recipecache.pkg_pepvpr[fn] | ||
238 | self._cached_packages = None | ||
239 | self._cached_rprovides = None | ||
240 | self._cached_packages_dynamic = None | ||
241 | |||
242 | def __getattr__(self, name): | ||
243 | if name == 'alternates': | ||
244 | return [x for x in self.fns if x != self.fn] | ||
245 | elif name == 'rdepends': | ||
246 | return self._recipecache.rundeps[self.fn] | ||
247 | elif name == 'rrecommends': | ||
248 | return self._recipecache.runrecs[self.fn] | ||
249 | elif name == 'provides': | ||
250 | return self._recipecache.fn_provides[self.fn] | ||
251 | elif name == 'packages': | ||
252 | if self._cached_packages is None: | ||
253 | self._cached_packages = [] | ||
254 | for pkg, fns in self._recipecache.packages.items(): | ||
255 | if self.fn in fns: | ||
256 | self._cached_packages.append(pkg) | ||
257 | return self._cached_packages | ||
258 | elif name == 'packages_dynamic': | ||
259 | if self._cached_packages_dynamic is None: | ||
260 | self._cached_packages_dynamic = [] | ||
261 | for pkg, fns in self._recipecache.packages_dynamic.items(): | ||
262 | if self.fn in fns: | ||
263 | self._cached_packages_dynamic.append(pkg) | ||
264 | return self._cached_packages_dynamic | ||
265 | elif name == 'rprovides': | ||
266 | if self._cached_rprovides is None: | ||
267 | self._cached_rprovides = [] | ||
268 | for pkg, fns in self._recipecache.rproviders.items(): | ||
269 | if self.fn in fns: | ||
270 | self._cached_rprovides.append(pkg) | ||
271 | return self._cached_rprovides | ||
272 | else: | ||
273 | raise AttributeError("%s instance has no attribute '%s'" % (self.__class__.__name__, name)) | ||
274 | def inherits(self, only_recipe=False): | ||
275 | """ | ||
276 | Get the inherited classes for a recipe. Returns the class names only. | ||
277 | Parameters: | ||
278 | only_recipe: True to return only the classes inherited by the recipe | ||
279 | itself, False to return all classes inherited within | ||
280 | the context for the recipe (which includes globally | ||
281 | inherited classes). | ||
282 | """ | ||
283 | if only_recipe: | ||
284 | global_inherit = [x for x in (self._d.getVar('BBINCLUDED') or '').split() if x.endswith('.bbclass')] | ||
285 | else: | ||
286 | global_inherit = [] | ||
287 | for clsfile in self.inherit_files: | ||
288 | if only_recipe and clsfile in global_inherit: | ||
289 | continue | ||
290 | clsname = os.path.splitext(os.path.basename(clsfile))[0] | ||
291 | yield clsname | ||
292 | def __str__(self): | ||
293 | return '%s' % self.pn | ||
294 | |||
295 | |||
220 | class Tinfoil: | 296 | class Tinfoil: |
221 | 297 | ||
222 | def __init__(self, output=sys.stdout, tracking=False, setup_logging=True): | 298 | def __init__(self, output=sys.stdout, tracking=False, setup_logging=True): |
@@ -401,6 +477,72 @@ class Tinfoil: | |||
401 | def get_file_appends(self, fn): | 477 | def get_file_appends(self, fn): |
402 | return self.run_command('getFileAppends', fn) | 478 | return self.run_command('getFileAppends', fn) |
403 | 479 | ||
480 | def all_recipes(self, mc='', sort=True): | ||
481 | """ | ||
482 | Enable iterating over all recipes in the current configuration. | ||
483 | Returns an iterator over TinfoilRecipeInfo objects created on demand. | ||
484 | Parameters: | ||
485 | mc: The multiconfig, default of '' uses the main configuration. | ||
486 | sort: True to sort recipes alphabetically (default), False otherwise | ||
487 | """ | ||
488 | recipecache = self.cooker.recipecaches[mc] | ||
489 | if sort: | ||
490 | recipes = sorted(recipecache.pkg_pn.items()) | ||
491 | else: | ||
492 | recipes = recipecache.pkg_pn.items() | ||
493 | for pn, fns in recipes: | ||
494 | prov = self.find_best_provider(pn) | ||
495 | recipe = TinfoilRecipeInfo(recipecache, | ||
496 | self.config_data, | ||
497 | pn=pn, | ||
498 | fn=prov[3], | ||
499 | fns=fns) | ||
500 | yield recipe | ||
501 | |||
502 | def all_recipe_files(self, mc='', variants=True, preferred_only=False): | ||
503 | """ | ||
504 | Enable iterating over all recipe files in the current configuration. | ||
505 | Returns an iterator over file paths. | ||
506 | Parameters: | ||
507 | mc: The multiconfig, default of '' uses the main configuration. | ||
508 | variants: True to include variants of recipes created through | ||
509 | BBCLASSEXTEND (default) or False to exclude them | ||
510 | preferred_only: True to include only the preferred recipe where | ||
511 | multiple exist providing the same PN, False to list | ||
512 | all recipes | ||
513 | """ | ||
514 | recipecache = self.cooker.recipecaches[mc] | ||
515 | if preferred_only: | ||
516 | files = [] | ||
517 | for pn in recipecache.pkg_pn.keys(): | ||
518 | prov = self.find_best_provider(pn) | ||
519 | files.append(prov[3]) | ||
520 | else: | ||
521 | files = recipecache.pkg_fn.keys() | ||
522 | for fn in sorted(files): | ||
523 | if not variants and fn.startswith('virtual:'): | ||
524 | continue | ||
525 | yield fn | ||
526 | |||
527 | |||
528 | def get_recipe_info(self, pn, mc=''): | ||
529 | """ | ||
530 | Get information on a specific recipe in the current configuration by name (PN). | ||
531 | Returns a TinfoilRecipeInfo object created on demand. | ||
532 | Parameters: | ||
533 | mc: The multiconfig, default of '' uses the main configuration. | ||
534 | """ | ||
535 | recipecache = self.cooker.recipecaches[mc] | ||
536 | prov = self.find_best_provider(pn) | ||
537 | fn = prov[3] | ||
538 | actual_pn = recipecache.pkg_fn[fn] | ||
539 | recipe = TinfoilRecipeInfo(recipecache, | ||
540 | self.config_data, | ||
541 | pn=actual_pn, | ||
542 | fn=fn, | ||
543 | fns=recipecache.pkg_pn[actual_pn]) | ||
544 | return recipe | ||
545 | |||
404 | def parse_recipe(self, pn): | 546 | def parse_recipe(self, pn): |
405 | """ | 547 | """ |
406 | Parse the specified recipe and return a datastore object | 548 | Parse the specified recipe and return a datastore object |