#!/usr/bin/env python # This script has subcommands which operate against your bitbake layers, either # displaying useful information, or acting against them. # Currently, it only provides a show_appends command, which shows you what # bbappends are in effect, and warns you if you have appends which are not being # utilized. import cmd import logging import os.path import sys bindir = os.path.dirname(__file__) topdir = os.path.dirname(bindir) sys.path[0:0] = [os.path.join(topdir, 'lib')] import bb.cache import bb.cooker import bb.providers from bb.cooker import state from bb.server import none logger = logging.getLogger('BitBake') default_cmd = 'show_appends' def main(args): logging.basicConfig(format='%(levelname)s: %(message)s') bb.utils.clean_environment() cmds = Commands() if args: cmds.onecmd(' '.join(args)) else: cmds.onecmd(default_cmd) return cmds.returncode class Commands(cmd.Cmd): def __init__(self): cmd.Cmd.__init__(self) self.returncode = 0 self.config = Config(parse_only=True) self.cooker = bb.cooker.BBCooker(self.config, bb.server.none) self.config_data = self.cooker.configuration.data bb.providers.logger.setLevel(logging.ERROR) self.prepare_cooker() def prepare_cooker(self): sys.stderr.write("Parsing recipes..") logger.setLevel(logging.ERROR) try: while self.cooker.state in (state.initial, state.parsing): self.cooker.updateCache() except KeyboardInterrupt: self.cooker.shutdown() self.cooker.updateCache() sys.exit(2) logger.setLevel(logging.INFO) sys.stderr.write("done.\n") self.cooker_data = self.cooker.status self.cooker_data.appends = self.cooker.appendlist def do_show_layers(self, args): logger.info(str(self.config_data.getVar('BBLAYERS', True))) def do_show_appends(self, args): if not self.cooker_data.appends: logger.info('No append files found') return logger.info('State of append files:') for pn in self.cooker_data.pkg_pn: self.show_appends_for_pn(pn) self.show_appends_with_no_recipes() def show_appends_for_pn(self, pn): filenames = self.cooker_data.pkg_pn[pn] best = bb.providers.findBestProvider(pn, self.cooker.configuration.data, self.cooker_data, self.cooker_data.pkg_pn) best_filename = os.path.basename(best[3]) appended, missing = self.get_appends_for_files(filenames) if appended: for basename, appends in appended: logger.info('%s:', basename) for append in appends: logger.info(' %s', append) if best_filename in missing: logger.warn('%s: missing append for preferred version', best_filename) self.returncode |= 1 def get_appends_for_files(self, filenames): appended, notappended = set(), set() for filename in filenames: _, cls = bb.cache.Cache.virtualfn2realfn(filename) if cls: continue basename = os.path.basename(filename) appends = self.cooker_data.appends.get(basename) if appends: appended.add((basename, frozenset(appends))) else: notappended.add(basename) return appended, notappended def show_appends_with_no_recipes(self): recipes = set(os.path.basename(f) for f in self.cooker_data.pkg_fn.iterkeys()) appended_recipes = self.cooker_data.appends.iterkeys() appends_without_recipes = [self.cooker_data.appends[recipe] for recipe in appended_recipes if recipe not in recipes] if appends_without_recipes: appendlines = (' %s' % append for appends in appends_without_recipes for append in appends) logger.warn('No recipes available for:\n%s', '\n'.join(appendlines)) self.returncode |= 4 def do_EOF(self, line): return True class Config(object): def __init__(self, **options): self.pkgs_to_build = [] self.debug_domains = [] self.extra_assume_provided = [] self.file = [] self.debug = 0 self.__dict__.update(options) def __getattr__(self, attribute): try: return super(Config, self).__getattribute__(attribute) except AttributeError: return None if __name__ == '__main__': sys.exit(main(sys.argv[1:]) or 0)