blob: 090133600b6722eb258971c7f8d480b658addb56 [file] [log] [blame]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001#!/usr/bin/env python3
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002#
Brad Bishopc342db32019-05-15 21:57:59 -04003# SPDX-License-Identifier: GPL-2.0-or-later
Patrick Williamsc124f4f2015-09-15 14:41:29 -05004#
5# Copyright (C) Darren Hart <dvhart@linux.intel.com>, 2010
6
7
8import sys
9import getopt
10import os
11import os.path
12import re
13
Brad Bishop316dfdd2018-06-25 12:45:53 -040014# 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
Patrick Williamsc124f4f2015-09-15 14:41:29 -050022def usage():
Brad Bishop316dfdd2018-06-25 12:45:53 -040023 print('Usage: %s -d FILENAME [-d FILENAME]*' % os.path.basename(sys.argv[0]))
Patrick Williamsc0f7c042017-02-23 20:41:17 -060024 print(' -d FILENAME documentation file to search')
25 print(' -h, --help display this help and exit')
Patrick Williamsc0f7c042017-02-23 20:41:17 -060026 print(' -t FILENAME documentation config file (for doc tags)')
27 print(' -T Only display variables with doc tags (requires -t)')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028
Brad Bishop316dfdd2018-06-25 12:45:53 -040029def 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
Patrick Williamsc124f4f2015-09-15 14:41:29 -050035
Brad Bishop316dfdd2018-06-25 12:45:53 -040036def collect_documented_vars(docfiles):
37 ''' Walk the docfiles and collect the documented variables '''
38 documented_vars = []
39 prog = re.compile(".*($|[^A-Z_])<glossentry id=\'var-")
40 var_prog = re.compile('<glossentry id=\'var-(.*)\'>')
41 for d in docfiles:
42 with open(d) as f:
43 documented_vars += var_prog.findall(f.read())
Patrick Williamsc124f4f2015-09-15 14:41:29 -050044
Brad Bishop316dfdd2018-06-25 12:45:53 -040045 return documented_vars
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046
47def bbvar_doctag(var, docconf):
48 prog = re.compile('^%s\[doc\] *= *"(.*)"' % (var))
49 if docconf == "":
50 return "?"
51
52 try:
53 f = open(docconf)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060054 except IOError as err:
55 return err.args[1]
Patrick Williamsc124f4f2015-09-15 14:41:29 -050056
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 = []
Brad Bishop316dfdd2018-06-25 12:45:53 -040067 bbvars = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050068 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"])
Patrick Williamsc0f7c042017-02-23 20:41:17 -060075 except getopt.GetoptError as err:
76 print('%s' % str(err))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050077 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:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060088 print('ERROR: documentation file %s is not a regular file' % a)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050089 sys.exit(3)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050090 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:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060099 print('ERROR: no docfile specified')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500100 usage()
101 sys.exit(5)
102
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500103 if onlydoctags and docconf == "":
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600104 print('ERROR: no docconf specified')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500105 usage()
106 sys.exit(7)
107
Brad Bishop316dfdd2018-06-25 12:45:53 -0400108 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)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125 else:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400126 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)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500145
146 # Check each var for documentation
147 varlen = 0
Brad Bishop316dfdd2018-06-25 12:45:53 -0400148 for v in bbvars:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500149 if len(v) > varlen:
150 varlen = len(v)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400151 if not bbvar_is_documented(v, documented_vars):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500152 undocumented.append(v)
153 undocumented.sort()
154 varlen = varlen + 1
155
156 # Report all undocumented variables
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600157 print('Found %d undocumented bb variables (out of %d):' % (len(undocumented), len(bbvars)))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400158 header = '%s%s' % (str("VARIABLE").ljust(varlen), str("DOCTAG").ljust(7))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600159 print(header)
160 print(str("").ljust(len(header), '='))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500161 for v in undocumented:
162 doctag = bbvar_doctag(v, docconf)
163 if not onlydoctags or not doctag == "":
Brad Bishop316dfdd2018-06-25 12:45:53 -0400164 print('%s%s' % (v.ljust(varlen), doctag))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500165
166
167if __name__ == "__main__":
168 main()