|  | @@ -13,9 +13,9 @@ practracker.py should be run with its second argument pointing to the Tor
 | 
	
		
			
				|  |  |  top-level source directory like this:
 | 
	
		
			
				|  |  |    $ python3 ./scripts/maint/practracker/practracker.py .
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -The exceptions file is meant to be initialized once with the current state of
 | 
	
		
			
				|  |  | -the source code and then get saved in the repository for ever after:
 | 
	
		
			
				|  |  | -  $ python3 ./scripts/maint/practracker/practracker.py . > ./scripts/maint/practracker/exceptions.txt
 | 
	
		
			
				|  |  | +To regenerate the exceptions file so that it allows all current
 | 
	
		
			
				|  |  | +problems in the Tor source, use the --regen flag:
 | 
	
		
			
				|  |  | +  $ python3 --regen ./scripts/maint/practracker/practracker.py .
 | 
	
		
			
				|  |  |  """
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  from __future__ import print_function
 | 
	
	
		
			
				|  | @@ -120,14 +120,59 @@ def consider_metrics_for_file(fname, f):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      return found_new_issues
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -def main():
 | 
	
		
			
				|  |  | -    if (len(sys.argv) != 2):
 | 
	
		
			
				|  |  | -        print("Usage:\n\t$ practracker.py <tor topdir>\n\t(e.g. $ practracker.py ~/tor/)")
 | 
	
		
			
				|  |  | -        return
 | 
	
		
			
				|  |  | +HEADER="""\
 | 
	
		
			
				|  |  | +# Welcome to the exceptions file for Tor's best-practices tracker!
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# Each line of this file represents a single violation of Tor's best
 | 
	
		
			
				|  |  | +# practices -- typically, a violation that we had before practracker.py
 | 
	
		
			
				|  |  | +# first existed.
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# There are three kinds of problems that we recognize right now:
 | 
	
		
			
				|  |  | +#   function-size -- a function of more than {MAX_FUNCTION_SIZE} lines.
 | 
	
		
			
				|  |  | +#   file-size -- a file of more than {MAX_FILE_SIZE} lines.
 | 
	
		
			
				|  |  | +#   include-count -- a file with more than {MAX_INCLUDE_COUNT} #includes.
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# Each line below represents a single exception that practracker should
 | 
	
		
			
				|  |  | +# _ignore_. Each line has four parts:
 | 
	
		
			
				|  |  | +#  1. The word "problem".
 | 
	
		
			
				|  |  | +#  2. The kind of problem.
 | 
	
		
			
				|  |  | +#  3. The location of the problem: either a filename, or a
 | 
	
		
			
				|  |  | +#     filename:functionname pair.
 | 
	
		
			
				|  |  | +#  4. The magnitude of the problem to ignore.
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# So for example, consider this line:
 | 
	
		
			
				|  |  | +#    problem file-size /src/core/or/connection_or.c 3200
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# It tells practracker to allow the mentioned file to be up to 3200 lines
 | 
	
		
			
				|  |  | +# long, even though ordinarily it would warn about any file with more than
 | 
	
		
			
				|  |  | +# {MAX_FILE_SIZE} lines.
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# You can either edit this file by hand, or regenerate it completely by
 | 
	
		
			
				|  |  | +# running `make practracker-regen`.
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# Remember: It is better to fix the problem than to add a new exception!
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +""".format(**globals())
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +def main(argv):
 | 
	
		
			
				|  |  | +    import argparse
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    progname = argv[0]
 | 
	
		
			
				|  |  | +    parser = argparse.ArgumentParser(prog=progname)
 | 
	
		
			
				|  |  | +    parser.add_argument("--regen", action="store_true",
 | 
	
		
			
				|  |  | +                        help="Regenerate the exceptions file")
 | 
	
		
			
				|  |  | +    parser.add_argument("--exceptions",
 | 
	
		
			
				|  |  | +                        help="Override the location for the exceptions file")
 | 
	
		
			
				|  |  | +    parser.add_argument("topdir", default=".", nargs="?",
 | 
	
		
			
				|  |  | +                        help="Top-level directory for the tor source")
 | 
	
		
			
				|  |  | +    args = parser.parse_args(argv[1:])
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      global TOR_TOPDIR
 | 
	
		
			
				|  |  | -    TOR_TOPDIR = sys.argv[1]
 | 
	
		
			
				|  |  | -    exceptions_file = os.path.join(TOR_TOPDIR, "scripts/maint/practracker", EXCEPTIONS_FNAME)
 | 
	
		
			
				|  |  | +    TOR_TOPDIR = args.topdir
 | 
	
		
			
				|  |  | +    if args.exceptions:
 | 
	
		
			
				|  |  | +        exceptions_file = args.exceptions
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +        exceptions_file = os.path.join(TOR_TOPDIR, "scripts/maint/practracker", EXCEPTIONS_FNAME)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      # 1) Get all the .c files we care about
 | 
	
		
			
				|  |  |      files_list = util.get_tor_c_files(TOR_TOPDIR)
 | 
	
	
		
			
				|  | @@ -135,13 +180,26 @@ def main():
 | 
	
		
			
				|  |  |      # 2) Initialize problem vault and load an optional exceptions file so that
 | 
	
		
			
				|  |  |      # we don't warn about the past
 | 
	
		
			
				|  |  |      global ProblemVault
 | 
	
		
			
				|  |  | -    ProblemVault = problem.ProblemVault(exceptions_file)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if args.regen:
 | 
	
		
			
				|  |  | +        tmpname = exceptions_file + ".tmp"
 | 
	
		
			
				|  |  | +        tmpfile = open(tmpname, "w")
 | 
	
		
			
				|  |  | +        sys.stdout = tmpfile
 | 
	
		
			
				|  |  | +        sys.stdout.write(HEADER)
 | 
	
		
			
				|  |  | +        ProblemVault = problem.ProblemVault()
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +        ProblemVault = problem.ProblemVault(exceptions_file)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      # 3) Go through all the files and report problems if they are not exceptions
 | 
	
		
			
				|  |  |      found_new_issues = consider_all_metrics(files_list)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    if args.regen:
 | 
	
		
			
				|  |  | +        tmpfile.close()
 | 
	
		
			
				|  |  | +        os.rename(tmpname, exceptions_file)
 | 
	
		
			
				|  |  | +        sys.exit(0)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      # If new issues were found, try to give out some advice to the developer on how to resolve it.
 | 
	
		
			
				|  |  | -    if (found_new_issues):
 | 
	
		
			
				|  |  | +    if found_new_issues and not args.regen:
 | 
	
		
			
				|  |  |          new_issues_str = """\
 | 
	
		
			
				|  |  |  FAILURE: practracker found new problems in the code: see warnings above.
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -155,4 +213,4 @@ See doc/HACKING/HelpfulTools.md for more information on using practracker.\
 | 
	
		
			
				|  |  |      sys.exit(found_new_issues)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  if __name__ == '__main__':
 | 
	
		
			
				|  |  | -    main()
 | 
	
		
			
				|  |  | +    main(sys.argv)
 |