| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 1 | #!/usr/bin/env python3 | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 2 |  | 
 | 3 | # This program is free software; you can redistribute it and/or modify | 
 | 4 | # it under the terms of the GNU General Public License as published by | 
 | 5 | # the Free Software Foundation; either version 2 of the License, or | 
 | 6 | # (at your option) any later version. | 
 | 7 | # | 
 | 8 | # This program is distributed in the hope that it will be useful, | 
 | 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 11 | # GNU General Public License for more details. | 
 | 12 | # | 
 | 13 | # You should have received a copy of the GNU General Public License | 
 | 14 | # along with this program; if not, write to the Free Software | 
 | 15 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 
 | 16 | # | 
 | 17 | # Copyright (C) Darren Hart <dvhart@linux.intel.com>, 2010 | 
 | 18 |  | 
 | 19 |  | 
 | 20 | import sys | 
 | 21 | import getopt | 
 | 22 | import os | 
 | 23 | import os.path | 
 | 24 | import re | 
 | 25 |  | 
 | 26 | def usage(): | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 27 |     print('Usage: %s -d FILENAME [-d FILENAME]* -m METADIR [-m MATADIR]*' % os.path.basename(sys.argv[0])) | 
 | 28 |     print('  -d FILENAME         documentation file to search') | 
 | 29 |     print('  -h, --help          display this help and exit') | 
 | 30 |     print('  -m METADIR          meta directory to search for recipes') | 
 | 31 |     print('  -t FILENAME         documentation config file (for doc tags)') | 
 | 32 |     print('  -T                  Only display variables with doc tags (requires -t)') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 33 |  | 
 | 34 | def recipe_bbvars(recipe): | 
 | 35 |     ''' Return a unique set of every bbvar encountered in the recipe ''' | 
 | 36 |     prog = re.compile("[A-Z_]+") | 
 | 37 |     vset = set() | 
 | 38 |     try: | 
 | 39 |         r = open(recipe) | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 40 |     except IOError as err: | 
 | 41 |         print('WARNING: Failed to open recipe ', recipe) | 
 | 42 |         print(err.args[1]) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 43 |  | 
 | 44 |     for line in r: | 
 | 45 |         # Strip any comments from the line | 
 | 46 |         line = line.rsplit('#')[0] | 
 | 47 |         vset = vset.union(set(prog.findall(line))) | 
 | 48 |     r.close() | 
 | 49 |  | 
 | 50 |     bbvars = {} | 
 | 51 |     for v in vset: | 
 | 52 |         bbvars[v] = 1 | 
 | 53 |  | 
 | 54 |     return bbvars | 
 | 55 |  | 
 | 56 | def collect_bbvars(metadir): | 
 | 57 |     ''' Walk the metadir and collect the bbvars from each recipe found ''' | 
 | 58 |     bbvars = {} | 
 | 59 |     for root,dirs,files in os.walk(metadir): | 
 | 60 |         for name in files: | 
 | 61 |             if name.find(".bb") >= 0: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 62 |                 for key in recipe_bbvars(os.path.join(root,name)).keys(): | 
 | 63 |                     if key in bbvars: | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 64 |                         bbvars[key] = bbvars[key] + 1 | 
 | 65 |                     else: | 
 | 66 |                         bbvars[key] = 1 | 
 | 67 |     return bbvars | 
 | 68 |  | 
 | 69 | def bbvar_is_documented(var, docfiles): | 
 | 70 |     prog = re.compile(".*($|[^A-Z_])%s([^A-Z_]|$)" % (var)) | 
 | 71 |     for doc in docfiles: | 
 | 72 |         try: | 
 | 73 |             f = open(doc) | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 74 |         except IOError as err: | 
 | 75 |             print('WARNING: Failed to open doc ', doc) | 
 | 76 |             print(err.args[1]) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 77 |         for line in f: | 
 | 78 |             if prog.match(line): | 
 | 79 |                 return True | 
 | 80 |         f.close() | 
 | 81 |     return False | 
 | 82 |  | 
 | 83 | def bbvar_doctag(var, docconf): | 
 | 84 |     prog = re.compile('^%s\[doc\] *= *"(.*)"' % (var)) | 
 | 85 |     if docconf == "": | 
 | 86 |         return "?" | 
 | 87 |  | 
 | 88 |     try: | 
 | 89 |         f = open(docconf) | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 90 |     except IOError as err: | 
 | 91 |         return err.args[1] | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 92 |  | 
 | 93 |     for line in f: | 
 | 94 |         m = prog.search(line) | 
 | 95 |         if m: | 
 | 96 |             return m.group(1) | 
 | 97 |  | 
 | 98 |     f.close() | 
 | 99 |     return "" | 
 | 100 |  | 
 | 101 | def main(): | 
 | 102 |     docfiles = [] | 
 | 103 |     metadirs = [] | 
 | 104 |     bbvars = {} | 
 | 105 |     undocumented = [] | 
 | 106 |     docconf = "" | 
 | 107 |     onlydoctags = False | 
 | 108 |  | 
 | 109 |     # Collect and validate input | 
 | 110 |     try: | 
 | 111 |         opts, args = getopt.getopt(sys.argv[1:], "d:hm:t:T", ["help"]) | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 112 |     except getopt.GetoptError as err: | 
 | 113 |         print('%s' % str(err)) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 114 |         usage() | 
 | 115 |         sys.exit(2) | 
 | 116 |  | 
 | 117 |     for o, a in opts: | 
 | 118 |         if o in ('-h', '--help'): | 
 | 119 |             usage() | 
 | 120 |             sys.exit(0) | 
 | 121 |         elif o == '-d': | 
 | 122 |             if os.path.isfile(a): | 
 | 123 |                 docfiles.append(a) | 
 | 124 |             else: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 125 |                 print('ERROR: documentation file %s is not a regular file' % a) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 126 |                 sys.exit(3) | 
 | 127 |         elif o == '-m': | 
 | 128 |             if os.path.isdir(a): | 
 | 129 |                 metadirs.append(a) | 
 | 130 |             else: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 131 |                 print('ERROR: meta directory %s is not a directory' % a) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 132 |                 sys.exit(4) | 
 | 133 |         elif o == "-t": | 
 | 134 |             if os.path.isfile(a): | 
 | 135 |                 docconf = a | 
 | 136 |         elif o == "-T": | 
 | 137 |             onlydoctags = True | 
 | 138 |         else: | 
 | 139 |             assert False, "unhandled option" | 
 | 140 |  | 
 | 141 |     if len(docfiles) == 0: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 142 |         print('ERROR: no docfile specified') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 143 |         usage() | 
 | 144 |         sys.exit(5) | 
 | 145 |  | 
 | 146 |     if len(metadirs) == 0: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 147 |         print('ERROR: no metadir specified') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 148 |         usage() | 
 | 149 |         sys.exit(6) | 
 | 150 |  | 
 | 151 |     if onlydoctags and docconf == "": | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 152 |         print('ERROR: no docconf specified') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 153 |         usage() | 
 | 154 |         sys.exit(7) | 
 | 155 |  | 
 | 156 |     # Collect all the variable names from the recipes in the metadirs | 
 | 157 |     for m in metadirs: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 158 |         for key,cnt in collect_bbvars(m).items(): | 
 | 159 |             if key in bbvars: | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 160 |                 bbvars[key] = bbvars[key] + cnt | 
 | 161 |             else: | 
 | 162 |                 bbvars[key] = cnt | 
 | 163 |  | 
 | 164 |     # Check each var for documentation | 
 | 165 |     varlen = 0 | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 166 |     for v in bbvars.keys(): | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 167 |         if len(v) > varlen: | 
 | 168 |             varlen = len(v) | 
 | 169 |         if not bbvar_is_documented(v, docfiles): | 
 | 170 |             undocumented.append(v) | 
 | 171 |     undocumented.sort() | 
 | 172 |     varlen = varlen + 1 | 
 | 173 |  | 
 | 174 |     # Report all undocumented variables | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 175 |     print('Found %d undocumented bb variables (out of %d):' % (len(undocumented), len(bbvars))) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 176 |     header = '%s%s%s' % (str("VARIABLE").ljust(varlen), str("COUNT").ljust(6), str("DOCTAG").ljust(7)) | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 177 |     print(header) | 
 | 178 |     print(str("").ljust(len(header), '=')) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 179 |     for v in undocumented: | 
 | 180 |         doctag = bbvar_doctag(v, docconf) | 
 | 181 |         if not onlydoctags or not doctag == "": | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 182 |             print('%s%s%s' % (v.ljust(varlen), str(bbvars[v]).ljust(6), doctag)) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 183 |  | 
 | 184 |  | 
 | 185 | if __name__ == "__main__": | 
 | 186 |     main() |