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