Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Unified Diff: PRESUBMIT.py

Issue 1784373002: Include isolate.py in data for Android unit tests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: review comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | PRESUBMIT_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: PRESUBMIT.py
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 10f7ac06318b6b0854812c46a50ea6b27b99979e..aee7722223b6bc150c5dd6a2a3abe31f1223027c 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -297,6 +297,12 @@ _VALID_OS_MACROS = (
)
+_PYDEPS_FILES = (
+ 'build/android/test_runner.pydeps',
+ 'build/secondary/tools/swarming_client/isolate.pydeps',
+)
+
+
def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
"""Attempts to prevent use of functions intended only for testing in
non-testing code. For now this is just a best-effort implementation
@@ -1497,6 +1503,104 @@ def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
return results
+class PydepsChecker(object):
+ def __init__(self, input_api):
+ self._file_cache = {}
+ self._input_api = input_api
+
+ def _LoadFile(self, path):
+ """Returns the list of paths within a .pydeps file relative to //."""
+ if path not in self._file_cache:
+ with open(path) as f:
+ self._file_cache[path] = f.read()
+ return self._file_cache[path]
+
+ def _ComputeNormalizedPydepsEntries(self, pydeps_path):
+ """Returns an interable of paths within the .pydep, relativized to //."""
+ os_path = self._input_api.os_path
+ pydeps_dir = os_path.dirname(pydeps_path)
+ entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
+ if not l.startswith('*'))
+ return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
+
+ def _CreateFilesToPydepsMap(self):
+ """Returns a map of local_path -> list_of_pydeps."""
+ ret = {}
+ for pydep_local_path in _PYDEPS_FILES:
+ for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
+ ret.setdefault(path, []).append(pydep_local_path)
+ return ret
+
+ def ComputeAffectedPydeps(self):
+ """Returns an iterable of .pydeps files that might need regenerating."""
+ affected_pydeps = set()
+ file_to_pydeps_map = None
+ for f in self._input_api.AffectedFiles(include_deletes=True):
+ local_path = f.LocalPath()
+ if local_path == 'DEPS':
+ return _PYDEPS_FILES
+ elif local_path.endswith('.pydeps'):
+ if local_path in _PYDEPS_FILES:
+ affected_pydeps.add(local_path)
+ elif local_path.endswith('.py'):
+ if file_to_pydeps_map is None:
+ file_to_pydeps_map = self._CreateFilesToPydepsMap()
+ affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
+ return affected_pydeps
+
+ def DetermineIfStale(self, pydeps_path):
+ """Runs print_python_deps.py to see if the files is stale."""
+ old_pydeps_data = self._LoadFile(pydeps_path)
+
+ m = self._input_api.re.search(r'# target: //(.*)', old_pydeps_data)
+ if not m:
+ return ['COULD NOT FIND .pydeps TARGET']
+ target = m.group(1)
+ m = self._input_api.re.search(r'# root: //(.*)', old_pydeps_data)
+ if not m:
+ return ['COULD NOT FIND .pydeps ROOT']
+ root = m.group(1) or '.'
+
+ cmd = ['build/print_python_deps.py', '--root', root, target]
+ new_pydeps_data = self._input_api.subprocess.check_output(cmd)
+ if old_pydeps_data != new_pydeps_data:
+ return cmd[:-1] + ['--output', pydeps_path] + cmd[-1:]
+
+
+def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
+ """Checks if a .pydeps file needs to be regenerated."""
+ results = []
+ # First, check for new / deleted .pydeps.
+ for f in input_api.AffectedFiles(include_deletes=True):
+ if f.LocalPath().endswith('.pydeps'):
+ if f.Action() == 'D' and f.LocalPath() in _PYDEPS_FILES:
+ results.append(output_api.PresubmitError(
+ 'Please update _PYDEPS_FILES within //PRESUBMIT.py to remove %s' %
+ f.LocalPath()))
+ elif f.Action() != 'D' and f.LocalPath() not in _PYDEPS_FILES:
+ results.append(output_api.PresubmitError(
+ 'Please update _PYDEPS_FILES within //PRESUBMIT.py to include %s' %
+ f.LocalPath()))
+
+ if results:
+ return results
+
+ checker = checker_for_tests or PydepsChecker(input_api)
+
+ for pydep_path in checker.ComputeAffectedPydeps():
+ try:
+ cmd = checker.DetermineIfStale(pydep_path)
+ if cmd:
+ results.append(output_api.PresubmitError(
+ 'File is stale: %s\nTo regenerate, run:\n%s' % (pydep_path,
+ ' '.join(cmd))))
+ except input_api.subprocess.CalledProcessError as error:
+ return [output_api.PresubmitError('Error running ' + ' '.join(error.cmd),
+ long_text=error.output)]
+
+ return results
+
+
def _CheckForCopyrightedCode(input_api, output_api):
"""Verifies that newly added code doesn't contain copyrighted material
and is properly licensed under the standard Chromium license.
@@ -1650,6 +1754,7 @@ def _AndroidSpecificOnUploadChecks(input_api, output_api):
results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
results.extend(_CheckAndroidToastUsage(input_api, output_api))
+ results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
return results
« no previous file with comments | « no previous file | PRESUBMIT_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698