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