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 |
