bbvars.py 5.5 KB

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