1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 6 """Results object and results formatters for checkdeps tool.""" 7 8 9 class DependencyViolation(object): 10 """A single dependency violation.""" 11 12 def __init__(self, include_path, violated_rule, rules): 13 # The include or import path that is in violation of a rule. 14 self.include_path = include_path 15 16 # The violated rule. 17 self.violated_rule = violated_rule 18 19 # The set of rules containing self.violated_rule. 20 self.rules = rules 21 22 23 class DependeeStatus(object): 24 """Results object for a dependee file.""" 25 26 def __init__(self, dependee_path): 27 # Path of the file whose nonconforming dependencies are listed in 28 # self.violations. 29 self.dependee_path = dependee_path 30 31 # List of DependencyViolation objects that apply to the dependee 32 # file. May be empty. 33 self.violations = [] 34 35 def AddViolation(self, violation): 36 """Adds a violation.""" 37 self.violations.append(violation) 38 39 def HasViolations(self): 40 """Returns True if this dependee is violating one or more rules.""" 41 return not not self.violations 42 43 44 class ResultsFormatter(object): 45 """Base class for results formatters.""" 46 47 def AddError(self, dependee_status): 48 """Add a formatted result to |self.results| for |dependee_status|, 49 which is guaranteed to return True for 50 |dependee_status.HasViolations|. 51 """ 52 raise NotImplementedError() 53 54 def GetResults(self): 55 """Returns the results. May be overridden e.g. to process the 56 results that have been accumulated. 57 """ 58 raise NotImplementedError() 59 60 def PrintResults(self): 61 """Prints the results to stdout.""" 62 raise NotImplementedError() 63 64 65 class NormalResultsFormatter(ResultsFormatter): 66 """A results formatting object that produces the classical, 67 detailed, human-readable output of the checkdeps tool. 68 """ 69 70 def __init__(self, verbose): 71 self.results = [] 72 self.verbose = verbose 73 74 def AddError(self, dependee_status): 75 lines = [] 76 lines.append('\nERROR in %s' % dependee_status.dependee_path) 77 for violation in dependee_status.violations: 78 lines.append(self.FormatViolation(violation, self.verbose)) 79 self.results.append('\n'.join(lines)) 80 81 @staticmethod 82 def FormatViolation(violation, verbose=False): 83 lines = [] 84 if verbose: 85 lines.append(' For %s' % violation.rules) 86 lines.append( 87 ' Illegal include: "%s"\n Because of %s' % 88 (violation.include_path, str(violation.violated_rule))) 89 return '\n'.join(lines) 90 91 def GetResults(self): 92 return self.results 93 94 def PrintResults(self): 95 for result in self.results: 96 print result 97 if self.results: 98 print '\nFAILED\n' 99 100 101 class TemporaryRulesFormatter(ResultsFormatter): 102 """A results formatter that produces a single line per nonconforming 103 include. The combined output is suitable for directly pasting into a 104 DEPS file as a list of temporary-allow rules. 105 """ 106 107 def __init__(self): 108 self.violations = set() 109 110 def AddError(self, dependee_status): 111 for violation in dependee_status.violations: 112 self.violations.add(violation.include_path) 113 114 def GetResults(self): 115 return [' "!%s",' % path for path in sorted(self.violations)] 116 117 def PrintResults(self): 118 for result in self.GetResults(): 119 print result 120 121 122 class CountViolationsFormatter(ResultsFormatter): 123 """A results formatter that produces a number, the count of #include 124 statements that are in violation of the dependency rules. 125 126 Note that you normally want to instantiate DepsChecker with 127 ignore_temp_rules=True when you use this formatter. 128 """ 129 130 def __init__(self): 131 self.count = 0 132 133 def AddError(self, dependee_status): 134 self.count += len(dependee_status.violations) 135 136 def GetResults(self): 137 return '%d' % self.count 138 139 def PrintResults(self): 140 print self.count 141