| #!/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 <dvhart@linux.intel.com>, 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() |