OLD | NEW |
| (Empty) |
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 import json | |
10 | |
11 | |
12 class DependencyViolation(object): | |
13 """A single dependency violation.""" | |
14 | |
15 def __init__(self, include_path, violated_rule, rules): | |
16 # The include or import path that is in violation of a rule. | |
17 self.include_path = include_path | |
18 | |
19 # The violated rule. | |
20 self.violated_rule = violated_rule | |
21 | |
22 # The set of rules containing self.violated_rule. | |
23 self.rules = rules | |
24 | |
25 | |
26 class DependeeStatus(object): | |
27 """Results object for a dependee file.""" | |
28 | |
29 def __init__(self, dependee_path): | |
30 # Path of the file whose nonconforming dependencies are listed in | |
31 # self.violations. | |
32 self.dependee_path = dependee_path | |
33 | |
34 # List of DependencyViolation objects that apply to the dependee | |
35 # file. May be empty. | |
36 self.violations = [] | |
37 | |
38 def AddViolation(self, violation): | |
39 """Adds a violation.""" | |
40 self.violations.append(violation) | |
41 | |
42 def HasViolations(self): | |
43 """Returns True if this dependee is violating one or more rules.""" | |
44 return not not self.violations | |
45 | |
46 | |
47 class ResultsFormatter(object): | |
48 """Base class for results formatters.""" | |
49 | |
50 def AddError(self, dependee_status): | |
51 """Add a formatted result to |self.results| for |dependee_status|, | |
52 which is guaranteed to return True for | |
53 |dependee_status.HasViolations|. | |
54 """ | |
55 raise NotImplementedError() | |
56 | |
57 def GetResults(self): | |
58 """Returns the results. May be overridden e.g. to process the | |
59 results that have been accumulated. | |
60 """ | |
61 raise NotImplementedError() | |
62 | |
63 def PrintResults(self): | |
64 """Prints the results to stdout.""" | |
65 raise NotImplementedError() | |
66 | |
67 | |
68 class NormalResultsFormatter(ResultsFormatter): | |
69 """A results formatting object that produces the classical, | |
70 detailed, human-readable output of the checkdeps tool. | |
71 """ | |
72 | |
73 def __init__(self, verbose): | |
74 self.results = [] | |
75 self.verbose = verbose | |
76 | |
77 def AddError(self, dependee_status): | |
78 lines = [] | |
79 lines.append('\nERROR in %s' % dependee_status.dependee_path) | |
80 for violation in dependee_status.violations: | |
81 lines.append(self.FormatViolation(violation, self.verbose)) | |
82 self.results.append('\n'.join(lines)) | |
83 | |
84 @staticmethod | |
85 def FormatViolation(violation, verbose=False): | |
86 lines = [] | |
87 if verbose: | |
88 lines.append(' For %s' % violation.rules) | |
89 lines.append( | |
90 ' Illegal include: "%s"\n Because of %s' % | |
91 (violation.include_path, str(violation.violated_rule))) | |
92 return '\n'.join(lines) | |
93 | |
94 def GetResults(self): | |
95 return self.results | |
96 | |
97 def PrintResults(self): | |
98 for result in self.results: | |
99 print result | |
100 if self.results: | |
101 print '\nFAILED\n' | |
102 | |
103 | |
104 class JSONResultsFormatter(ResultsFormatter): | |
105 """A results formatter that outputs results to a file as JSON.""" | |
106 | |
107 def __init__(self, output_path, wrapped_formatter=None): | |
108 self.output_path = output_path | |
109 self.wrapped_formatter = wrapped_formatter | |
110 | |
111 self.results = [] | |
112 | |
113 def AddError(self, dependee_status): | |
114 self.results.append({ | |
115 'dependee_path': dependee_status.dependee_path, | |
116 'violations': [{ | |
117 'include_path': violation.include_path, | |
118 'violated_rule': violation.violated_rule.AsDependencyTuple(), | |
119 } for violation in dependee_status.violations] | |
120 }) | |
121 | |
122 if self.wrapped_formatter: | |
123 self.wrapped_formatter.AddError(dependee_status) | |
124 | |
125 def GetResults(self): | |
126 with open(self.output_path, 'w') as f: | |
127 f.write(json.dumps(self.results)) | |
128 | |
129 return self.results | |
130 | |
131 def PrintResults(self): | |
132 if self.wrapped_formatter: | |
133 self.wrapped_formatter.PrintResults() | |
134 return | |
135 | |
136 print self.results | |
137 | |
138 | |
139 class TemporaryRulesFormatter(ResultsFormatter): | |
140 """A results formatter that produces a single line per nonconforming | |
141 include. The combined output is suitable for directly pasting into a | |
142 DEPS file as a list of temporary-allow rules. | |
143 """ | |
144 | |
145 def __init__(self): | |
146 self.violations = set() | |
147 | |
148 def AddError(self, dependee_status): | |
149 for violation in dependee_status.violations: | |
150 self.violations.add(violation.include_path) | |
151 | |
152 def GetResults(self): | |
153 return [' "!%s",' % path for path in sorted(self.violations)] | |
154 | |
155 def PrintResults(self): | |
156 for result in self.GetResults(): | |
157 print result | |
158 | |
159 | |
160 class CountViolationsFormatter(ResultsFormatter): | |
161 """A results formatter that produces a number, the count of #include | |
162 statements that are in violation of the dependency rules. | |
163 | |
164 Note that you normally want to instantiate DepsChecker with | |
165 ignore_temp_rules=True when you use this formatter. | |
166 """ | |
167 | |
168 def __init__(self): | |
169 self.count = 0 | |
170 | |
171 def AddError(self, dependee_status): | |
172 self.count += len(dependee_status.violations) | |
173 | |
174 def GetResults(self): | |
175 return '%d' % self.count | |
176 | |
177 def PrintResults(self): | |
178 print self.count | |
OLD | NEW |