blob: 090133600b6722eb258971c7f8d480b658addb56 [file] [log] [blame]
#!/usr/bin/env python3
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright (C) Darren Hart <dvhart@linux.intel.com>, 2010
import sys
import getopt
import os
import os.path
import re
# Set up sys.path to let us import tinfoil
scripts_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
lib_path = scripts_path + '/lib'
sys.path.insert(0, lib_path)
import scriptpath
scriptpath.add_bitbake_lib_path()
import bb.tinfoil
def usage():
print('Usage: %s -d FILENAME [-d FILENAME]*' % os.path.basename(sys.argv[0]))
print(' -d FILENAME documentation file to search')
print(' -h, --help display this help and exit')
print(' -t FILENAME documentation config file (for doc tags)')
print(' -T Only display variables with doc tags (requires -t)')
def bbvar_is_documented(var, documented_vars):
''' Check if variable (var) is in the list of documented variables(documented_vars) '''
if var in documented_vars:
return True
else:
return False
def collect_documented_vars(docfiles):
''' Walk the docfiles and collect the documented variables '''
documented_vars = []
prog = re.compile(".*($|[^A-Z_])<glossentry id=\'var-")
var_prog = re.compile('<glossentry id=\'var-(.*)\'>')
for d in docfiles:
with open(d) as f:
documented_vars += var_prog.findall(f.read())
return documented_vars
def bbvar_doctag(var, docconf):
prog = re.compile('^%s\[doc\] *= *"(.*)"' % (var))
if docconf == "":
return "?"
try:
f = open(docconf)
except IOError as err:
return err.args[1]
for line in f:
m = prog.search(line)
if m:
return m.group(1)
f.close()
return ""
def main():
docfiles = []
bbvars = set()
undocumented = []
docconf = ""
onlydoctags = False
# Collect and validate input
try:
opts, args = getopt.getopt(sys.argv[1:], "d:hm:t:T", ["help"])
except getopt.GetoptError as err:
print('%s' % str(err))
usage()
sys.exit(2)
for o, a in opts:
if o in ('-h', '--help'):
usage()
sys.exit(0)
elif o == '-d':
if os.path.isfile(a):
docfiles.append(a)
else:
print('ERROR: documentation file %s is not a regular file' % a)
sys.exit(3)
elif o == "-t":
if os.path.isfile(a):
docconf = a
elif o == "-T":
onlydoctags = True
else:
assert False, "unhandled option"
if len(docfiles) == 0:
print('ERROR: no docfile specified')
usage()
sys.exit(5)
if onlydoctags and docconf == "":
print('ERROR: no docconf specified')
usage()
sys.exit(7)
prog = re.compile("^[^a-z]*$")
with bb.tinfoil.Tinfoil() as tinfoil:
tinfoil.prepare(config_only=False)
parser = bb.codeparser.PythonParser('parser', None)
datastore = tinfoil.config_data
def bbvars_update(data):
if prog.match(data):
bbvars.add(data)
if tinfoil.config_data.getVarFlag(data, 'python'):
try:
parser.parse_python(tinfoil.config_data.getVar(data))
except bb.data_smart.ExpansionError:
pass
for var in parser.references:
if prog.match(var):
bbvars.add(var)
else:
try:
expandedVar = datastore.expandWithRefs(datastore.getVar(data, False), data)
for var in expandedVar.references:
if prog.match(var):
bbvars.add(var)
except bb.data_smart.ExpansionError:
pass
# Use tinfoil to collect all the variable names globally
for data in datastore:
bbvars_update(data)
# Collect variables from all recipes
for recipe in tinfoil.all_recipe_files(variants=False):
print("Checking %s" % recipe)
for data in tinfoil.parse_recipe_file(recipe):
bbvars_update(data)
documented_vars = collect_documented_vars(docfiles)
# Check each var for documentation
varlen = 0
for v in bbvars:
if len(v) > varlen:
varlen = len(v)
if not bbvar_is_documented(v, documented_vars):
undocumented.append(v)
undocumented.sort()
varlen = varlen + 1
# Report all undocumented variables
print('Found %d undocumented bb variables (out of %d):' % (len(undocumented), len(bbvars)))
header = '%s%s' % (str("VARIABLE").ljust(varlen), str("DOCTAG").ljust(7))
print(header)
print(str("").ljust(len(header), '='))
for v in undocumented:
doctag = bbvar_doctag(v, docconf)
if not onlydoctags or not doctag == "":
print('%s%s' % (v.ljust(varlen), doctag))
if __name__ == "__main__":
main()