15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Results object and results formatters for checkdeps tool.""" 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import json 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DependencyViolation(object): 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A single dependency violation.""" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, include_path, violated_rule, rules): 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The include or import path that is in violation of a rule. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.include_path = include_path 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The violated rule. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.violated_rule = violated_rule 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The set of rules containing self.violated_rule. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.rules = rules 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DependeeStatus(object): 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Results object for a dependee file.""" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, dependee_path): 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Path of the file whose nonconforming dependencies are listed in 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # self.violations. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.dependee_path = dependee_path 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # List of DependencyViolation objects that apply to the dependee 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # file. May be empty. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.violations = [] 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AddViolation(self, violation): 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Adds a violation.""" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.violations.append(violation) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def HasViolations(self): 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns True if this dependee is violating one or more rules.""" 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return not not self.violations 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ResultsFormatter(object): 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Base class for results formatters.""" 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AddError(self, dependee_status): 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Add a formatted result to |self.results| for |dependee_status|, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) which is guaranteed to return True for 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) |dependee_status.HasViolations|. 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError() 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetResults(self): 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns the results. May be overridden e.g. to process the 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results that have been accumulated. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError() 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def PrintResults(self): 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Prints the results to stdout.""" 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError() 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NormalResultsFormatter(ResultsFormatter): 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A results formatting object that produces the classical, 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) detailed, human-readable output of the checkdeps tool. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, verbose): 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.results = [] 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.verbose = verbose 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AddError(self, dependee_status): 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines = [] 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines.append('\nERROR in %s' % dependee_status.dependee_path) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for violation in dependee_status.violations: 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines.append(self.FormatViolation(violation, self.verbose)) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.results.append('\n'.join(lines)) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @staticmethod 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def FormatViolation(violation, verbose=False): 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines = [] 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if verbose: 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines.append(' For %s' % violation.rules) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines.append( 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ' Illegal include: "%s"\n Because of %s' % 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (violation.include_path, str(violation.violated_rule))) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '\n'.join(lines) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetResults(self): 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.results 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def PrintResults(self): 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for result in self.results: 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print result 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.results: 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '\nFAILED\n' 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class JSONResultsFormatter(ResultsFormatter): 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) """A results formatter that outputs results to a file as JSON.""" 106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def __init__(self, output_path, wrapped_formatter=None): 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.output_path = output_path 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.wrapped_formatter = wrapped_formatter 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.results = [] 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def AddError(self, dependee_status): 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.results.append({ 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 'dependee_path': dependee_status.dependee_path, 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 'violations': [{ 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 'include_path': violation.include_path, 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 'violated_rule': violation.violated_rule.AsDependencyTuple(), 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } for violation in dependee_status.violations] 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) }) 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if self.wrapped_formatter: 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.wrapped_formatter.AddError(dependee_status) 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def GetResults(self): 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) with open(self.output_path, 'w') as f: 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) f.write(json.dumps(self.results)) 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return self.results 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def PrintResults(self): 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if self.wrapped_formatter: 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.wrapped_formatter.PrintResults() 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) print self.results 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TemporaryRulesFormatter(ResultsFormatter): 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A results formatter that produces a single line per nonconforming 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) include. The combined output is suitable for directly pasting into a 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEPS file as a list of temporary-allow rules. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.violations = set() 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AddError(self, dependee_status): 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for violation in dependee_status.violations: 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.violations.add(violation.include_path) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetResults(self): 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [' "!%s",' % path for path in sorted(self.violations)] 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def PrintResults(self): 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for result in self.GetResults(): 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print result 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CountViolationsFormatter(ResultsFormatter): 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A results formatter that produces a number, the count of #include 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) statements that are in violation of the dependency rules. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Note that you normally want to instantiate DepsChecker with 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ignore_temp_rules=True when you use this formatter. 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.count = 0 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AddError(self, dependee_status): 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.count += len(dependee_status.violations) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetResults(self): 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '%d' % self.count 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def PrintResults(self): 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print self.count 179