PageRenderTime 59ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/Utilities/Doxygen/mcdoc.py

https://github.com/paniwani/ITK
Python | 171 lines | 167 code | 3 blank | 1 comment | 0 complexity | c3b79e35d035494ad773c285b65e61b5 MD5 | raw file
  1. #!/usr/bin/env python
  2. import sys, os, re, glob, cStringIO
  3. def usage():
  4. print >> sys.stderr, """usage: mdoc.py set group file [files...]
  5. Add the tag "\\ingroup group" to all the doxygen comment with a \\class
  6. tag in it.
  7. usage: mdoc.py check group file [files...]
  8. Check that the tag "\\ingroup group" is in all the doxygen comment with a \\class
  9. tag in it. If the tag is not there, a warning is displayed with the file name, the
  10. line number and the class name. The return value is 0 when all the doxygen comments
  11. have the tag, and 1 when at least one doxygen comment don't have it.
  12. usage: mdoc.py massive-set [ITK-source]
  13. Add the tag "\\ingroup module" to all the headers in ITK, where 'module' is the
  14. module name of the header.
  15. usage: mdoc.py massive-check [ITK-source]
  16. Check that all the headers in ITK have their module name in their \\ingroup tag.
  17. As for 'check', a warning is displayed if the tag is missing and 1 is returned.
  18. """
  19. def setGroup( fname, group ):
  20. # print >> sys.stderr, "Processing", fname
  21. f = open( fname, "r" )
  22. out = cStringIO.StringIO()
  23. # load everything in memory
  24. fcontent = f.read()
  25. f.close()
  26. # now parse all the doxygen fields
  27. last = 0
  28. for m in re.finditer(r"/\*\*(.*?)\*/", fcontent, re.DOTALL):
  29. # write what is before the doxygen field to the output
  30. out.write(fcontent[last:m.start(1)])
  31. last = m.end(1)
  32. dcontent = m.group(1)
  33. # we don't care about doxygen fields not about a class
  34. if r"\class" in dcontent and dcontent != " \class classname ":
  35. # do we have a line with the expected content?
  36. if re.search(r"\ingroup .*"+group+"( |$)", dcontent, re.MULTILINE):
  37. # yes - just keep the content unchanged
  38. out.write(dcontent)
  39. else:
  40. # add the expected group
  41. if "\n" in dcontent:
  42. # this is a multiline content. Find the indent
  43. indent = re.search("( *)(\*|$)", dcontent).group(1)
  44. lastLine = dcontent.splitlines()[-1]
  45. if re.match(r'^ *$', lastLine):
  46. out.write(dcontent+"* \\ingroup "+group+"\n"+indent)
  47. else:
  48. out.write(dcontent.rstrip()+"\n"+indent+"* \\ingroup "+group+"\n"+indent)
  49. else:
  50. out.write(dcontent+" \\ingroup "+group+" ")
  51. else:
  52. out.write(dcontent)
  53. out.write(fcontent[last:])
  54. # we can save the content to the original file
  55. f = open( fname, "w" )
  56. f.write( out.getvalue() )
  57. f.close()
  58. def checkGroup( fname, group ):
  59. # print >> sys.stderr, "Checking", fname
  60. f = open( fname, "r" )
  61. # load everything in memory
  62. fcontent = f.read()
  63. f.close()
  64. # now parse all the doxygen fields
  65. ret = 0
  66. for m in re.finditer(r"/\*\*(.*?)\*/", fcontent, re.DOTALL):
  67. dcontent = m.group(1)
  68. # we don't care about doxygen fields not about a class
  69. if r"\class" in dcontent and dcontent != " \class classname ":
  70. # do we have a line with the expected content?
  71. if not re.search(r"\ingroup .*"+group+"( |$)", dcontent, re.MULTILINE):
  72. # get class name and the line for debug output
  73. cname = re.search(r"\class +([^ ]*)", dcontent).group(1).strip()
  74. line = len(fcontent[:m.start(1)].splitlines())
  75. print >> sys.stderr, r'%s:%s: error: "\ingroup %s" not set in class %s.' % (fname, line, group, cname)
  76. ret = 1
  77. return ret
  78. def main():
  79. # first arg is the command
  80. command = sys.argv[1]
  81. if command == "set":
  82. if len(sys.argv) < 4:
  83. usage()
  84. return 1
  85. # second arg is the module name, and the rest are the files to process
  86. module = sys.argv[2]
  87. files = sys.argv[3:]
  88. for fname in files:
  89. setGroup(fname, module)
  90. return 0
  91. elif command == "massive-set":
  92. if len(sys.argv) < 2:
  93. usage()
  94. return 1
  95. if len(sys.argv) >= 3:
  96. d = sys.argv[2]
  97. else:
  98. d = sys.path[0]+"/../.."
  99. cmm = os.path.abspath(d+"/*/*/*/itk-module.cmake")
  100. for fname in glob.glob(cmm):
  101. f = file(fname, "r")
  102. mcontent = f.read()
  103. f.close()
  104. module = re.search(r"itk_module\(([^ )]+)", mcontent).group(1)
  105. dname = os.path.dirname(fname)
  106. for fname2 in glob.glob(dname+"/include/*.h"):
  107. setGroup(fname2, module)
  108. return 0
  109. elif command == "check":
  110. if len(sys.argv) < 4:
  111. usage()
  112. return 1
  113. # second arg is the module name, and the rest are the files to process
  114. module = sys.argv[2]
  115. files = sys.argv[3:]
  116. ret = 0
  117. count = 0
  118. for fname in files:
  119. if os.path.isdir(fname):
  120. for fname2 in glob.glob(fname+"/*.h"):
  121. count += 1
  122. ret = max( ret, checkGroup(fname2, module) )
  123. else:
  124. count += 1
  125. ret = max( ret, checkGroup(fname, module) )
  126. print >> sys.stderr, count, "headers checked."
  127. return ret
  128. elif command == "massive-check":
  129. if len(sys.argv) < 2:
  130. usage()
  131. return 1
  132. if len(sys.argv) >= 3:
  133. d = sys.argv[2]
  134. else:
  135. d = sys.path[0]+"/../.."
  136. cmm = os.path.abspath(d+"/*/*/*/itk-module.cmake")
  137. ret = 0
  138. count = 0
  139. for fname in glob.glob(cmm):
  140. f = file(fname, "r")
  141. mcontent = f.read()
  142. f.close()
  143. module = re.search(r"itk_module\(([^ )]+)", mcontent).group(1)
  144. dname = os.path.dirname(fname)
  145. for fname2 in glob.glob(dname+"/include/*.h"):
  146. count += 1
  147. ret = max( ret, checkGroup(fname2, module) )
  148. print >> sys.stderr, count, "headers checked."
  149. return ret
  150. else:
  151. print >> sys.stderr, "Unknown command", command
  152. usage()
  153. return 1
  154. if __name__ == "__main__":
  155. ret = main()
  156. sys.exit(ret)