From e5e3fb23a2c5d8e40e4f751d804d9ea6fc3bfd2f Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Tue, 11 Jan 2011 15:29:58 -0800 Subject: bbvars.py: add a script to look for undocumented variables bbvars.py will compare recipes in meta directories with documentation files and report on variables that don't appear to be documented. It reports the number of times a variable is used as well as any doctags present in the documentation config file. The output of this is intended to aid in determining where documentation may be lacking, but it is not perfect, and does generate some false positives. An experienced eye and careful attention to count and doctag should be applied to the results. $ ./bbvars.py -d ../../documentation/poky-ref-manual/poky-ref-manual.html -m ../../meta -t ../../meta/conf/documentation.conf -T | head -n 10 Found 1413 undocumented bb variables (out of 1578): VARIABLE COUNT DOCTAG =================================================== BUILD_ARCH 4 The name of the building architecture. E.g. i686. BUILD_CC_ARCH 2 FIXME BUILD_PREFIX 4 FIXME BUILD_SYS 13 FIXME BUILD_VENDOR 2 FIXME CACHE 1 The directory holding the cache of the metadata. COMPATIBLE_HOST 19 A regular expression which matches the HOST_SYS names supported by the package/file. Failure to match will cause the file to be skipped by the parser. Signed-off-by: Darren Hart CC: Richard Purdie --- scripts/contrib/bbvars.py | 186 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100755 scripts/contrib/bbvars.py (limited to 'scripts') diff --git a/scripts/contrib/bbvars.py b/scripts/contrib/bbvars.py new file mode 100755 index 000000000..0896d6444 --- /dev/null +++ b/scripts/contrib/bbvars.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# Copyright (C) Darren Hart , 2010 + + +import sys +import getopt +import os +import os.path +import re + +def usage(): + print 'Usage: %s -d FILENAME [-d FILENAME]* -m METADIR [-m MATADIR]*' % os.path.basename(sys.argv[0]) + print ' -d FILENAME documentation file to search' + print ' -h, --help display this help and exit' + print ' -m METADIR meta directory to search for recipes' + print ' -t FILENAME documentation config file (for doc tags)' + print ' -T Only display variables with doc tags (requires -t)' + +def recipe_bbvars(recipe): + ''' Return a unique set of every bbvar encountered in the recipe ''' + prog = re.compile("[A-Z_]+") + vset = set() + try: + r = open(recipe) + except IOError as (errno, strerror): + print 'WARNING: Failed to open recipe ', recipe + print strerror + + for line in r: + # Strip any comments from the line + line = line.rsplit('#')[0] + vset = vset.union(set(prog.findall(line))) + r.close() + + bbvars = {} + for v in vset: + bbvars[v] = 1 + + return bbvars + +def collect_bbvars(metadir): + ''' Walk the metadir and collect the bbvars from each recipe found ''' + bbvars = {} + for root,dirs,files in os.walk(metadir): + for name in files: + if name.find(".bb") >= 0: + for key in recipe_bbvars(os.path.join(root,name)).iterkeys(): + if bbvars.has_key(key): + bbvars[key] = bbvars[key] + 1 + else: + bbvars[key] = 1 + return bbvars + +def bbvar_is_documented(var, docfiles): + prog = re.compile(".*($|[^A-Z_])%s([^A-Z_]|$)" % (var)) + for doc in docfiles: + try: + f = open(doc) + except IOError as (errno, strerror): + print 'WARNING: Failed to open doc ', doc + print strerror + for line in f: + if prog.match(line): + return True + f.close() + return False + +def bbvar_doctag(var, docconf): + prog = re.compile('^%s\[doc\] *= *"(.*)"' % (var)) + if docconf == "": + return "?" + + try: + f = open(docconf) + except IOError as (errno, strerror): + return strerror + + for line in f: + m = prog.search(line) + if m: + return m.group(1) + + f.close() + return "" + +def main(): + docfiles = [] + metadirs = [] + bbvars = {} + undocumented = [] + docconf = "" + onlydoctags = False + + # Collect and validate input + try: + opts, args = getopt.getopt(sys.argv[1:], "d:hm:t:T", ["help"]) + except getopt.GetoptError, 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 == '-m': + if os.path.isdir(a): + metadirs.append(a) + else: + print 'ERROR: meta directory %s is not a directory' % (a) + sys.exit(4) + 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 len(metadirs) == 0: + print 'ERROR: no metadir specified' + usage() + sys.exit(6) + + if onlydoctags and docconf == "": + print 'ERROR: no docconf specified' + usage() + sys.exit(7) + + # Collect all the variable names from the recipes in the metadirs + for m in metadirs: + for key,cnt in collect_bbvars(m).iteritems(): + if bbvars.has_key(key): + bbvars[key] = bbvars[key] + cnt + else: + bbvars[key] = cnt + + # Check each var for documentation + varlen = 0 + for v in bbvars.iterkeys(): + if len(v) > varlen: + varlen = len(v) + if not bbvar_is_documented(v, docfiles): + 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%s' % (str("VARIABLE").ljust(varlen), str("COUNT").ljust(6), 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%s' % (v.ljust(varlen), str(bbvars[v]).ljust(6), doctag) + + +if __name__ == "__main__": + main() -- cgit v1.2.3