| #!/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(r".*($|[^A-Z_])<glossentry id=\'var-") |
| var_prog = re.compile(r'<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(r'^%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() |