practracker.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #!/usr/bin/python
  2. """
  3. Tor code best-practices tracker
  4. Go through the various .c files and collect metrics about them. If the metrics
  5. violate some of our best practices and they are not found in the optional
  6. exceptions file ("./exceptions.txt"), then log a problem about them.
  7. The exceptions file is meant to be initialized with the current state of the
  8. source code as follows: ./practracker.py > ./exceptions.txt
  9. We currently do metrics about file size, function size and number of includes.
  10. TODO:
  11. - How is this tool supposed to be used? How should the exception file work?
  12. How should the UI work? Does it need special exit codes?
  13. - Fix the function_length function so that practracker_tests.py passes.
  14. """
  15. import os, sys
  16. import metrics
  17. import util
  18. import problem
  19. # We don't want to run metrics for unittests, automatically-generated C files,
  20. # external libraries or git leftovers.
  21. EXCLUDE_SOURCE_DIRS = ["/src/test/", "/src/trunnel/", "/src/ext/", "/.git/"]
  22. # Where the Tor source code is
  23. TOR_TOPDIR = "../../../"
  24. # An optional exceptions_file
  25. EXCEPTIONS_FILE = "./exceptions.txt"
  26. # Recommended file size
  27. MAX_FILE_SIZE = 3000 # lines
  28. # Recommended function size
  29. MAX_FUNCTION_SIZE = 100 # lines
  30. # Recommended number of #includes
  31. MAX_INCLUDE_COUNT = 50
  32. #######################################################
  33. ProblemVault = None
  34. #######################################################
  35. def consider_file_size(fname, f):
  36. file_size = metrics.file_len(f)
  37. if file_size > MAX_FILE_SIZE:
  38. v = problem.FileSizeProblem(fname, file_size)
  39. ProblemVault.register_problem(v)
  40. def consider_includes(fname, f):
  41. include_count = metrics.get_include_count(f)
  42. if include_count > MAX_INCLUDE_COUNT:
  43. v = problem.IncludeCountProblem(fname, include_count)
  44. ProblemVault.register_problem(v)
  45. def consider_function_size(fname, f):
  46. for name, lines in metrics.function_lines(f):
  47. # Don't worry about functions within our limits
  48. if lines <= MAX_FUNCTION_SIZE:
  49. continue
  50. # That's a big function! Issue a problem!
  51. canonical_function_name = "%s:%s()" % (fname,name)
  52. v = problem.FunctionSizeProblem(canonical_function_name, lines)
  53. ProblemVault.register_problem(v)
  54. #######################################################
  55. def consider_all_metrics(files_list):
  56. """Consider metrics for all files"""
  57. for fname in files_list:
  58. with open(fname, 'r') as f:
  59. consider_metrics_for_file(fname, f)
  60. def consider_metrics_for_file(fname, f):
  61. """
  62. Get metrics for file with filename 'fname' and file descriptor 'f'.
  63. """
  64. # Get file length
  65. consider_file_size(fname, f)
  66. # Consider number of #includes
  67. f.seek(0)
  68. consider_includes(fname, f)
  69. # Get function length
  70. f.seek(0)
  71. consider_function_size(fname, f)
  72. def main():
  73. global ProblemVault
  74. # 1) Get all the .c files we care about
  75. files_list = util.get_tor_c_files(TOR_TOPDIR, EXCLUDE_SOURCE_DIRS)
  76. # 2) Initialize problem vault and load an optional exceptions file so that
  77. # we don't warn about the past
  78. try:
  79. with open(EXCEPTIONS_FILE, 'r') as exception_f:
  80. ProblemVault = problem.ProblemVault(exception_f)
  81. except IOError:
  82. print "No exception file provided"
  83. ProblemVault = problem.ProblemVault(None)
  84. # 3) Go through all the files and report problems if they are not exceptions
  85. consider_all_metrics(files_list)
  86. if __name__ == '__main__':
  87. main()