1#!/usr/bin/env python3 2# 3# SPDX-License-Identifier: GPL-2.0-or-later 4# 5# Copyright (C) Darren Hart <dvhart@linux.intel.com>, 2010 6 7 8import sys 9import getopt 10import os 11import os.path 12import re 13 14# Set up sys.path to let us import tinfoil 15scripts_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 16lib_path = scripts_path + '/lib' 17sys.path.insert(0, lib_path) 18import scriptpath 19scriptpath.add_bitbake_lib_path() 20import bb.tinfoil 21 22def usage(): 23 print('Usage: %s -d FILENAME [-d FILENAME]*' % os.path.basename(sys.argv[0])) 24 print(' -d FILENAME documentation file to search') 25 print(' -h, --help display this help and exit') 26 print(' -t FILENAME documentation config file (for doc tags)') 27 print(' -T Only display variables with doc tags (requires -t)') 28 29def bbvar_is_documented(var, documented_vars): 30 ''' Check if variable (var) is in the list of documented variables(documented_vars) ''' 31 if var in documented_vars: 32 return True 33 else: 34 return False 35 36def collect_documented_vars(docfiles): 37 ''' Walk the docfiles and collect the documented variables ''' 38 documented_vars = [] 39 prog = re.compile(r".*($|[^A-Z_])<glossentry id=\'var-") 40 var_prog = re.compile(r'<glossentry id=\'var-(.*)\'>') 41 for d in docfiles: 42 with open(d) as f: 43 documented_vars += var_prog.findall(f.read()) 44 45 return documented_vars 46 47def bbvar_doctag(var, docconf): 48 prog = re.compile(r'^%s\[doc\] *= *"(.*)"' % (var)) 49 if docconf == "": 50 return "?" 51 52 try: 53 f = open(docconf) 54 except IOError as err: 55 return err.args[1] 56 57 for line in f: 58 m = prog.search(line) 59 if m: 60 return m.group(1) 61 62 f.close() 63 return "" 64 65def main(): 66 docfiles = [] 67 bbvars = set() 68 undocumented = [] 69 docconf = "" 70 onlydoctags = False 71 72 # Collect and validate input 73 try: 74 opts, args = getopt.getopt(sys.argv[1:], "d:hm:t:T", ["help"]) 75 except getopt.GetoptError as err: 76 print('%s' % str(err)) 77 usage() 78 sys.exit(2) 79 80 for o, a in opts: 81 if o in ('-h', '--help'): 82 usage() 83 sys.exit(0) 84 elif o == '-d': 85 if os.path.isfile(a): 86 docfiles.append(a) 87 else: 88 print('ERROR: documentation file %s is not a regular file' % a) 89 sys.exit(3) 90 elif o == "-t": 91 if os.path.isfile(a): 92 docconf = a 93 elif o == "-T": 94 onlydoctags = True 95 else: 96 assert False, "unhandled option" 97 98 if len(docfiles) == 0: 99 print('ERROR: no docfile specified') 100 usage() 101 sys.exit(5) 102 103 if onlydoctags and docconf == "": 104 print('ERROR: no docconf specified') 105 usage() 106 sys.exit(7) 107 108 prog = re.compile("^[^a-z]*$") 109 with bb.tinfoil.Tinfoil() as tinfoil: 110 tinfoil.prepare(config_only=False) 111 parser = bb.codeparser.PythonParser('parser', None) 112 datastore = tinfoil.config_data 113 114 def bbvars_update(data): 115 if prog.match(data): 116 bbvars.add(data) 117 if tinfoil.config_data.getVarFlag(data, 'python'): 118 try: 119 parser.parse_python(tinfoil.config_data.getVar(data)) 120 except bb.data_smart.ExpansionError: 121 pass 122 for var in parser.references: 123 if prog.match(var): 124 bbvars.add(var) 125 else: 126 try: 127 expandedVar = datastore.expandWithRefs(datastore.getVar(data, False), data) 128 for var in expandedVar.references: 129 if prog.match(var): 130 bbvars.add(var) 131 except bb.data_smart.ExpansionError: 132 pass 133 134 # Use tinfoil to collect all the variable names globally 135 for data in datastore: 136 bbvars_update(data) 137 138 # Collect variables from all recipes 139 for recipe in tinfoil.all_recipe_files(variants=False): 140 print("Checking %s" % recipe) 141 for data in tinfoil.parse_recipe_file(recipe): 142 bbvars_update(data) 143 144 documented_vars = collect_documented_vars(docfiles) 145 146 # Check each var for documentation 147 varlen = 0 148 for v in bbvars: 149 if len(v) > varlen: 150 varlen = len(v) 151 if not bbvar_is_documented(v, documented_vars): 152 undocumented.append(v) 153 undocumented.sort() 154 varlen = varlen + 1 155 156 # Report all undocumented variables 157 print('Found %d undocumented bb variables (out of %d):' % (len(undocumented), len(bbvars))) 158 header = '%s%s' % (str("VARIABLE").ljust(varlen), str("DOCTAG").ljust(7)) 159 print(header) 160 print(str("").ljust(len(header), '=')) 161 for v in undocumented: 162 doctag = bbvar_doctag(v, docconf) 163 if not onlydoctags or not doctag == "": 164 print('%s%s' % (v.ljust(varlen), doctag)) 165 166 167if __name__ == "__main__": 168 main() 169