"Fossies" - the Fresh Open Source Software Archive

Member "tor-0.4.1.6/scripts/maint/practracker/problem.py" (10 Jun 2019, 5929 Bytes) of package /linux/misc/tor-0.4.1.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "problem.py" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.4.1.6_vs_0.4.2.4-rc.

    1 """
    2 In this file we define a ProblemVault class where we store all the
    3 exceptions and all the problems we find with the code.
    4 
    5 The ProblemVault is capable of registering problems and also figuring out if a
    6 problem is worse than a registered exception so that it only warns when things
    7 get worse.
    8 """
    9 
   10 from __future__ import print_function
   11 
   12 import os.path
   13 import re
   14 import sys
   15 
   16 class ProblemVault(object):
   17     """
   18     Singleton where we store the various new problems we
   19     found in the code, and also the old problems we read from the exception
   20     file.
   21     """
   22     def __init__(self, exception_fname=None):
   23         # Exception dictionary: { problem.key() : Problem object }
   24         self.exceptions = {}
   25 
   26         if exception_fname == None:
   27             return
   28 
   29         try:
   30             with open(exception_fname, 'r') as exception_f:
   31                 self.register_exceptions(exception_f)
   32         except IOError:
   33             print("No exception file provided", file=sys.stderr)
   34 
   35     def register_exceptions(self, exception_file):
   36         # Register exceptions
   37         for lineno, line in enumerate(exception_file, 1):
   38             try:
   39                 problem = get_old_problem_from_exception_str(line)
   40             except ValueError as v:
   41                 print("Exception file line {} not recognized: {}"
   42                       .format(lineno,v),
   43                       file=sys.stderr)
   44                 continue
   45 
   46             if problem is None:
   47                 continue
   48 
   49             # Fail if we see dup exceptions. There is really no reason to have dup exceptions.
   50             if problem.key() in self.exceptions:
   51                 print("Duplicate exceptions lines found in exception file:\n\t{}\n\t{}\nAborting...".format(problem, self.exceptions[problem.key()]),
   52                       file=sys.stderr)
   53                 sys.exit(1)
   54 
   55             self.exceptions[problem.key()] = problem
   56             #print "Registering exception: %s" % problem
   57 
   58     def register_problem(self, problem):
   59         """
   60         Register this problem to the problem value. Return True if it was a new
   61         problem or it worsens an already existing problem.
   62         """
   63         # This is a new problem, print it
   64         if problem.key() not in self.exceptions:
   65             print(problem)
   66             return True
   67 
   68         # If it's an old problem, we don't warn if the situation got better
   69         # (e.g. we went from 4k LoC to 3k LoC), but we do warn if the
   70         # situation worsened (e.g. we went from 60 includes to 80).
   71         if problem.is_worse_than(self.exceptions[problem.key()]):
   72             print(problem)
   73             return True
   74 
   75         return False
   76 
   77 class Problem(object):
   78     """
   79     A generic problem in our source code. See the subclasses below for the
   80     specific problems we are trying to tackle.
   81     """
   82     def __init__(self, problem_type, problem_location, metric_value):
   83         self.problem_location = problem_location
   84         self.metric_value = int(metric_value)
   85         self.problem_type = problem_type
   86 
   87     def is_worse_than(self, other_problem):
   88         """Return True if this is a worse problem than other_problem"""
   89         if self.metric_value > other_problem.metric_value:
   90             return True
   91         return False
   92 
   93     def key(self):
   94         """Generate a unique key that describes this problem that can be used as a dictionary key"""
   95         # Problem location is a filesystem path, so we need to normalize this
   96         # across platforms otherwise same paths are not gonna match.
   97         canonical_location = os.path.normcase(self.problem_location)
   98         return "%s:%s" % (canonical_location, self.problem_type)
   99 
  100     def __str__(self):
  101         return "problem %s %s %s" % (self.problem_type, self.problem_location, self.metric_value)
  102 
  103 class FileSizeProblem(Problem):
  104     """
  105     Denotes a problem with the size of a .c file.
  106 
  107     The 'problem_location' is the filesystem path of the .c file, and the
  108     'metric_value' is the number of lines in the .c file.
  109     """
  110     def __init__(self, problem_location, metric_value):
  111         super(FileSizeProblem, self).__init__("file-size", problem_location, metric_value)
  112 
  113 class IncludeCountProblem(Problem):
  114     """
  115     Denotes a problem with the number of #includes in a .c file.
  116 
  117     The 'problem_location' is the filesystem path of the .c file, and the
  118     'metric_value' is the number of #includes in the .c file.
  119     """
  120     def __init__(self, problem_location, metric_value):
  121         super(IncludeCountProblem, self).__init__("include-count", problem_location, metric_value)
  122 
  123 class FunctionSizeProblem(Problem):
  124     """
  125     Denotes a problem with a size of a function in a .c file.
  126 
  127     The 'problem_location' is "<path>:<function>()" where <path> is the
  128     filesystem path of the .c file and <function> is the name of the offending
  129     function.
  130 
  131     The 'metric_value' is the size of the offending function in lines.
  132     """
  133     def __init__(self, problem_location, metric_value):
  134         super(FunctionSizeProblem, self).__init__("function-size", problem_location, metric_value)
  135 
  136 comment_re = re.compile(r'#.*$')
  137 
  138 def get_old_problem_from_exception_str(exception_str):
  139     orig_str = exception_str
  140     exception_str = comment_re.sub("", exception_str)
  141     fields = exception_str.split()
  142     if len(fields) == 0:
  143         # empty line or comment
  144         return None
  145     elif len(fields) == 4:
  146         # valid line
  147         _, problem_type, problem_location, metric_value = fields
  148     else:
  149         raise ValueError("Misformatted line {!r}".format(orig_str))
  150 
  151     if problem_type == "file-size":
  152         return FileSizeProblem(problem_location, metric_value)
  153     elif problem_type == "include-count":
  154         return IncludeCountProblem(problem_location, metric_value)
  155     elif problem_type == "function-size":
  156         return FunctionSizeProblem(problem_location, metric_value)
  157     else:
  158         raise ValueError("Unknown exception type {!r}".format(orig_str))