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