def CountViolations(self, skip_tests): deps_checker = checkdeps.DepsChecker(self.checkout_root, ignore_temp_rules=True, skip_tests=skip_tests) deps_checker.results_formatter = results.CountViolationsFormatter() deps_checker.CheckDirectory(os.path.join('chrome', 'browser')) return int(deps_checker.results_formatter.GetResults())
def CheckUnwantedDependencies(input_api, output_api): """Runs checkdeps on #include statements added in this change. Breaking - rules is an error, breaking ! rules is a warning. """ # Copied from Chromium's src/PRESUBMIT.py. # We need to wait until we have an input_api object and use this # roundabout construct to import checkdeps because this file is # eval-ed and thus doesn't have __file__. checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps') if not os.path.exists(checkdeps_path): return [ output_api.PresubmitError( 'Cannot find checkdeps at %s\nHave you run "gclient sync" to ' 'download all the DEPS entries?' % checkdeps_path) ] with _AddToPath(checkdeps_path): import checkdeps from cpp_checker import CppChecker from rules import Rule added_includes = [] for f in input_api.AffectedFiles(): if not CppChecker.IsCppFile(f.LocalPath()): continue changed_lines = [line for _, line in f.ChangedContents()] added_includes.append([f.LocalPath(), changed_lines]) deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath()) error_descriptions = [] warning_descriptions = [] for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes( added_includes): description_with_path = '%s\n %s' % (path, rule_description) if rule_type == Rule.DISALLOW: error_descriptions.append(description_with_path) else: warning_descriptions.append(description_with_path) results = [] if error_descriptions: results.append( output_api.PresubmitError( 'You added one or more #includes that violate checkdeps rules.\n' 'Check that the DEPS files in these locations contain valid rules.\n' 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for ' 'more details about checkdeps.', error_descriptions)) if warning_descriptions: results.append( output_api.PresubmitPromptOrNotify( 'You added one or more #includes of files that are temporarily\n' 'allowed but being removed. Can you avoid introducing the\n' '#include? See relevant DEPS file(s) for details and contacts.\n' 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for ' 'more details about checkdeps.', warning_descriptions)) return results
def _CheckDeps(input_api, output_api): results = [] import sys original_sys_path = sys.path try: sys.path = sys.path + [input_api.os_path.join( input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')] import checkdeps from cpp_checker import CppChecker from rules import Rule finally: sys.path = original_sys_path added_includes = [] for f in input_api.AffectedFiles(): if CppChecker.IsCppFile(f.LocalPath()): changed_lines = [line for _, line in f.ChangedContents()] added_includes.append([f.AbsoluteLocalPath(), changed_lines]) deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath()) violations = deps_checker.CheckAddedCppIncludes(added_includes) for path, rule_type, rule_description in violations: relpath = input_api.os_path.relpath(path, input_api.PresubmitLocalPath()) error_description = '%s\n %s' % (relpath, rule_description) if rule_type == Rule.DISALLOW: results.append(output_api.PresubmitError(error_description)) else: results.append(output_api.PresubmitPromptWarning(error_description)) return results
def _CheckUnwantedDependencies(input_api, output_api): """Runs checkdeps on #include statements added in this change. Breaking - rules is an error, breaking ! rules is a warning. """ # We need to wait until we have an input_api object and use this # roundabout construct to import checkdeps because this file is # eval-ed and thus doesn't have __file__. original_sys_path = sys.path try: sys.path = sys.path + [ input_api.os_path.realpath( input_api.os_path.join(input_api.PresubmitLocalPath(), '..', '..', 'buildtools', 'checkdeps')) ] import checkdeps from cpp_checker import CppChecker from rules import Rule finally: # Restore sys.path to what it was before. sys.path = original_sys_path added_includes = [] for f in input_api.AffectedFiles(): if not CppChecker.IsCppFile(f.LocalPath()): continue changed_lines = [line for line_num, line in f.ChangedContents()] added_includes.append([f.LocalPath(), changed_lines]) deps_checker = checkdeps.DepsChecker( input_api.os_path.join(input_api.PresubmitLocalPath())) error_descriptions = [] warning_descriptions = [] for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes( added_includes): description_with_path = '%s\n %s' % (path, rule_description) if rule_type == Rule.DISALLOW: error_descriptions.append(description_with_path) else: warning_descriptions.append(description_with_path) results = [] if error_descriptions: results.append( output_api.PresubmitError( 'You added one or more #includes that violate checkdeps rules.', error_descriptions)) if warning_descriptions: results.append( output_api.PresubmitPromptOrNotify( 'You added one or more #includes of files that are temporarily\n' 'allowed but being removed. Can you avoid introducing the\n' '#include? See relevant DEPS file(s) for details and contacts.', warning_descriptions)) return results
def _CheckDeps(input_api, output_api): results = [] import sys original_sys_path = sys.path try: sys.path = sys.path + [ input_api.os_path.join(input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps') ] import checkdeps from cpp_checker import CppChecker from rules import Rule finally: sys.path = original_sys_path deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath()) deps_checker.CheckDirectory(input_api.PresubmitLocalPath()) deps_results = deps_checker.results_formatter.GetResults() for violation in deps_results: results.append(output_api.PresubmitError(violation)) return results
def _CheckUnwantedDependencies(input_api, output_api): """Runs checkdeps on #include statements added in this change. Breaking - rules is an error, breaking ! rules is a warning. """ # We need to wait until we have an input_api object and use this # roundabout construct to import checkdeps because this file is # eval-ed and thus doesn't have __file__. original_sys_path = sys.path try: sys.path = sys.path + [ input_api.os_path.join(input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps') ] import checkdeps from cpp_checker import CppChecker from rules import Rule finally: # Restore sys.path to what it was before. sys.path = original_sys_path def _FilesImpactedByDepsChange(files): all_files = [f.AbsoluteLocalPath() for f in files] deps_files = [p for p in all_files if IsDepsFile(p)] impacted_files = union( [_CollectImpactedFiles(path) for path in deps_files]) impacted_file_objs = [ImpactedFile(path) for path in impacted_files] return impacted_file_objs def IsDepsFile(p): return os.path.isfile(p) and os.path.basename(p) == 'DEPS' def union(list_of_lists): """Ensure no duplicates""" return set(sum(list_of_lists, [])) def _CollectImpactedFiles(deps_file): # TODO(liviurau): Do not walk paths twice. Then we have no duplicates. # Higher level DEPS changes may dominate lower level DEPS changes. # TODO(liviurau): Check if DEPS changed in the right way. # 'include_rules' impact c++ files but 'vars' or 'deps' do not. # Maybe we just eval both old and new DEPS content and check # if the list are the same. result = [] parent_dir = os.path.dirname(deps_file) for relative_f in input_api.change.AllFiles(parent_dir): abs_f = os.path.join(parent_dir, relative_f) if CppChecker.IsCppFile(abs_f): result.append(abs_f) return result class ImpactedFile(object): """Duck type version of AffectedFile needed to check files under directories where a DEPS file changed. Extend the interface along the line of AffectedFile if you need it for other checks.""" def __init__(self, path): self._path = path def LocalPath(self): path = self._path.replace(os.sep, '/') return os.path.normpath(path) def ChangedContents(self): with open(self._path) as f: # TODO(liviurau): read only '#include' lines lines = f.readlines() return enumerate(lines, start=1) def _FilterDuplicates(impacted_files, affected_files): """"We include all impacted files but exclude affected files that are also impacted. Files impacted by DEPS changes take precedence before files affected by direct changes.""" result = impacted_files[:] only_paths = set([imf.LocalPath() for imf in impacted_files]) for af in affected_files: if not af.LocalPath() in only_paths: result.append(af) return result added_includes = [] affected_files = input_api.AffectedFiles() impacted_by_deps = _FilesImpactedByDepsChange(affected_files) for f in _FilterDuplicates(impacted_by_deps, affected_files): if not CppChecker.IsCppFile(f.LocalPath()): continue changed_lines = [line for line_num, line in f.ChangedContents()] added_includes.append([f.LocalPath(), changed_lines]) deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath()) error_descriptions = [] warning_descriptions = [] for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes( added_includes): description_with_path = '%s\n %s' % (path, rule_description) if rule_type == Rule.DISALLOW: error_descriptions.append(description_with_path) else: warning_descriptions.append(description_with_path) results = [] if error_descriptions: results.append( output_api.PresubmitError( 'You added one or more #includes that violate checkdeps rules.', error_descriptions)) if warning_descriptions: results.append( output_api.PresubmitPromptOrNotify( 'You added one or more #includes of files that are temporarily\n' 'allowed but being removed. Can you avoid introducing the\n' '#include? See relevant DEPS file(s) for details and contacts.', warning_descriptions)) return results
def setUp(self): self.deps_checker = checkdeps.DepsChecker( being_tested=True, base_directory=os.path.join(os.path.dirname(__file__), os.path.pardir))
def testBadBaseDirectoryNotCheckoutRoot(self): # This assumes git. It's not a valid test if buildtools is fetched via svn. with self.assertRaises(builddeps.DepsBuilderError): checkdeps.DepsChecker(being_tested=True, base_directory=os.path.dirname(__file__))
def setUp(self): self.deps_checker = checkdeps.DepsChecker(being_tested=True)