1#!/usr/bin/env python3 2 3# Copyright (C) 2013 Wind River Systems, Inc. 4# Copyright (C) 2014 Intel Corporation 5# 6# SPDX-License-Identifier: GPL-2.0-or-later 7# 8# - list available recipes which have PACKAGECONFIG flags 9# - list available PACKAGECONFIG flags and all affected recipes 10# - list all recipes and PACKAGECONFIG information 11 12import sys 13import optparse 14import os 15 16 17scripts_path = os.path.abspath(os.path.dirname(os.path.abspath(sys.argv[0]))) 18lib_path = os.path.abspath(scripts_path + '/../lib') 19sys.path = sys.path + [lib_path] 20 21import scriptpath 22 23# For importing the following modules 24bitbakepath = scriptpath.add_bitbake_lib_path() 25if not bitbakepath: 26 sys.stderr.write("Unable to find bitbake by searching parent directory of this script or PATH\n") 27 sys.exit(1) 28 29import bb.cooker 30import bb.providers 31import bb.tinfoil 32 33def get_fnlist(bbhandler, pkg_pn, preferred): 34 ''' Get all recipe file names ''' 35 if preferred: 36 (latest_versions, preferred_versions, required_versions) = bb.providers.findProviders(bbhandler.config_data, bbhandler.cooker.recipecaches[''], pkg_pn) 37 38 fn_list = [] 39 for pn in sorted(pkg_pn): 40 if preferred: 41 fn_list.append(preferred_versions[pn][1]) 42 else: 43 fn_list.extend(pkg_pn[pn]) 44 45 return fn_list 46 47def get_recipesdata(bbhandler, preferred): 48 ''' Get data of all available recipes which have PACKAGECONFIG flags ''' 49 pkg_pn = bbhandler.cooker.recipecaches[''].pkg_pn 50 51 data_dict = {} 52 for fn in get_fnlist(bbhandler, pkg_pn, preferred): 53 data = bbhandler.parse_recipe_file(fn) 54 flags = data.getVarFlags("PACKAGECONFIG") 55 flags.pop('doc', None) 56 if flags: 57 data_dict[fn] = data 58 59 return data_dict 60 61def collect_pkgs(data_dict): 62 ''' Collect available pkgs in which have PACKAGECONFIG flags ''' 63 # pkg_dict = {'pkg1': ['flag1', 'flag2',...]} 64 pkg_dict = {} 65 for fn in data_dict: 66 pkgconfigflags = data_dict[fn].getVarFlags("PACKAGECONFIG") 67 pkgconfigflags.pop('doc', None) 68 pkgname = data_dict[fn].getVar("PN") 69 pkg_dict[pkgname] = sorted(pkgconfigflags.keys()) 70 71 return pkg_dict 72 73def collect_flags(pkg_dict): 74 ''' Collect available PACKAGECONFIG flags and all affected pkgs ''' 75 # flag_dict = {'flag': ['pkg1', 'pkg2',...]} 76 flag_dict = {} 77 for pkgname, flaglist in pkg_dict.items(): 78 for flag in flaglist: 79 if flag in flag_dict: 80 flag_dict[flag].append(pkgname) 81 else: 82 flag_dict[flag] = [pkgname] 83 84 return flag_dict 85 86def display_pkgs(pkg_dict): 87 ''' Display available pkgs which have PACKAGECONFIG flags ''' 88 pkgname_len = len("RECIPE NAME") + 1 89 for pkgname in pkg_dict: 90 if pkgname_len < len(pkgname): 91 pkgname_len = len(pkgname) 92 pkgname_len += 1 93 94 header = '%-*s%s' % (pkgname_len, str("RECIPE NAME"), str("PACKAGECONFIG FLAGS")) 95 print(header) 96 print(str("").ljust(len(header), '=')) 97 for pkgname in sorted(pkg_dict): 98 print('%-*s%s' % (pkgname_len, pkgname, ' '.join(pkg_dict[pkgname]))) 99 100 101def display_flags(flag_dict): 102 ''' Display available PACKAGECONFIG flags and all affected pkgs ''' 103 flag_len = len("PACKAGECONFIG FLAG") + 5 104 105 header = '%-*s%s' % (flag_len, str("PACKAGECONFIG FLAG"), str("RECIPE NAMES")) 106 print(header) 107 print(str("").ljust(len(header), '=')) 108 109 for flag in sorted(flag_dict): 110 print('%-*s%s' % (flag_len, flag, ' '.join(sorted(flag_dict[flag])))) 111 112def display_all(data_dict): 113 ''' Display all pkgs and PACKAGECONFIG information ''' 114 print(str("").ljust(50, '=')) 115 for fn in data_dict: 116 print('%s' % data_dict[fn].getVar("P")) 117 print(fn) 118 packageconfig = data_dict[fn].getVar("PACKAGECONFIG") or '' 119 if packageconfig.strip() == '': 120 packageconfig = 'None' 121 print('PACKAGECONFIG %s' % packageconfig) 122 123 for flag,flag_val in data_dict[fn].getVarFlags("PACKAGECONFIG").items(): 124 if flag == "doc": 125 continue 126 print('PACKAGECONFIG[%s] %s' % (flag, flag_val)) 127 print('') 128 129def main(): 130 pkg_dict = {} 131 flag_dict = {} 132 133 # Collect and validate input 134 parser = optparse.OptionParser( 135 description = "Lists recipes and PACKAGECONFIG flags. Without -a or -f, recipes and their available PACKAGECONFIG flags are listed.", 136 usage = """ 137 %prog [options]""") 138 139 parser.add_option("-f", "--flags", 140 help = "list available PACKAGECONFIG flags and affected recipes", 141 action="store_const", dest="listtype", const="flags", default="recipes") 142 parser.add_option("-a", "--all", 143 help = "list all recipes and PACKAGECONFIG information", 144 action="store_const", dest="listtype", const="all") 145 parser.add_option("-p", "--preferred-only", 146 help = "where multiple recipe versions are available, list only the preferred version", 147 action="store_true", dest="preferred", default=False) 148 149 options, args = parser.parse_args(sys.argv) 150 151 with bb.tinfoil.Tinfoil() as bbhandler: 152 bbhandler.prepare() 153 print("Gathering recipe data...") 154 data_dict = get_recipesdata(bbhandler, options.preferred) 155 156 if options.listtype == 'flags': 157 pkg_dict = collect_pkgs(data_dict) 158 flag_dict = collect_flags(pkg_dict) 159 display_flags(flag_dict) 160 elif options.listtype == 'recipes': 161 pkg_dict = collect_pkgs(data_dict) 162 display_pkgs(pkg_dict) 163 elif options.listtype == 'all': 164 display_all(data_dict) 165 166if __name__ == "__main__": 167 main() 168