OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Top-level presubmit script for Chromium. | 5 """Top-level presubmit script for Chromium. |
6 | 6 |
7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts | 7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts |
8 for more details about the presubmit API built into depot_tools. | 8 for more details about the presubmit API built into depot_tools. |
9 """ | 9 """ |
10 | 10 |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 'OS_NACL_NONSFI', | 290 'OS_NACL_NONSFI', |
291 'OS_NACL_SFI', | 291 'OS_NACL_SFI', |
292 'OS_OPENBSD', | 292 'OS_OPENBSD', |
293 'OS_POSIX', | 293 'OS_POSIX', |
294 'OS_QNX', | 294 'OS_QNX', |
295 'OS_SOLARIS', | 295 'OS_SOLARIS', |
296 'OS_WIN', | 296 'OS_WIN', |
297 ) | 297 ) |
298 | 298 |
299 | 299 |
| 300 _PYDEPS_FILES = ( |
| 301 'build/android/test_runner.pydeps', |
| 302 'build/secondary/tools/swarming_client/isolate.pydeps', |
| 303 ) |
| 304 |
| 305 |
300 def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api): | 306 def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api): |
301 """Attempts to prevent use of functions intended only for testing in | 307 """Attempts to prevent use of functions intended only for testing in |
302 non-testing code. For now this is just a best-effort implementation | 308 non-testing code. For now this is just a best-effort implementation |
303 that ignores header files and may have some false positives. A | 309 that ignores header files and may have some false positives. A |
304 better implementation would probably need a proper C++ parser. | 310 better implementation would probably need a proper C++ parser. |
305 """ | 311 """ |
306 # We only scan .cc files and the like, as the declaration of | 312 # We only scan .cc files and the like, as the declaration of |
307 # for-testing functions in header files are hard to distinguish from | 313 # for-testing functions in header files are hard to distinguish from |
308 # calls to such functions without a proper C++ parser. | 314 # calls to such functions without a proper C++ parser. |
309 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS | 315 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS |
(...skipping 1180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1490 results = [] | 1496 results = [] |
1491 if errors: | 1497 if errors: |
1492 results.append(output_api.PresubmitError( | 1498 results.append(output_api.PresubmitError( |
1493 'MDPI assets should be placed in /res/drawable-mdpi/ or ' | 1499 'MDPI assets should be placed in /res/drawable-mdpi/ or ' |
1494 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and' | 1500 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and' |
1495 '/res/drawable-ldrtl/.\n' | 1501 '/res/drawable-ldrtl/.\n' |
1496 'Contact newt@chromium.org if you have questions.', errors)) | 1502 'Contact newt@chromium.org if you have questions.', errors)) |
1497 return results | 1503 return results |
1498 | 1504 |
1499 | 1505 |
| 1506 class PydepsChecker(object): |
| 1507 def __init__(self, input_api): |
| 1508 self._file_cache = {} |
| 1509 self._input_api = input_api |
| 1510 |
| 1511 def _LoadFile(self, path): |
| 1512 """Returns the list of paths within a .pydeps file relative to //.""" |
| 1513 if path not in self._file_cache: |
| 1514 with open(path) as f: |
| 1515 self._file_cache[path] = f.read() |
| 1516 return self._file_cache[path] |
| 1517 |
| 1518 def _ComputeNormalizedPydepsEntries(self, pydeps_path): |
| 1519 """Returns an interable of paths within the .pydep, relativized to //.""" |
| 1520 os_path = self._input_api.os_path |
| 1521 pydeps_dir = os_path.dirname(pydeps_path) |
| 1522 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines() |
| 1523 if not l.startswith('*')) |
| 1524 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries) |
| 1525 |
| 1526 def _CreateFilesToPydepsMap(self): |
| 1527 """Returns a map of local_path -> list_of_pydeps.""" |
| 1528 ret = {} |
| 1529 for pydep_local_path in _PYDEPS_FILES: |
| 1530 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path): |
| 1531 ret.setdefault(path, []).append(pydep_local_path) |
| 1532 return ret |
| 1533 |
| 1534 def ComputeAffectedPydeps(self): |
| 1535 """Returns an iterable of .pydeps files that might need regenerating.""" |
| 1536 affected_pydeps = set() |
| 1537 file_to_pydeps_map = None |
| 1538 for f in self._input_api.AffectedFiles(include_deletes=True): |
| 1539 local_path = f.LocalPath() |
| 1540 if local_path == 'DEPS': |
| 1541 return _PYDEPS_FILES |
| 1542 elif local_path.endswith('.pydeps'): |
| 1543 if local_path in _PYDEPS_FILES: |
| 1544 affected_pydeps.add(local_path) |
| 1545 elif local_path.endswith('.py'): |
| 1546 if file_to_pydeps_map is None: |
| 1547 file_to_pydeps_map = self._CreateFilesToPydepsMap() |
| 1548 affected_pydeps.update(file_to_pydeps_map.get(local_path, ())) |
| 1549 return affected_pydeps |
| 1550 |
| 1551 def DetermineIfStale(self, pydeps_path): |
| 1552 """Runs print_python_deps.py to see if the files is stale.""" |
| 1553 old_pydeps_data = self._LoadFile(pydeps_path) |
| 1554 |
| 1555 m = self._input_api.re.search(r'# target: //(.*)', old_pydeps_data) |
| 1556 if not m: |
| 1557 return ['COULD NOT FIND .pydeps TARGET'] |
| 1558 target = m.group(1) |
| 1559 m = self._input_api.re.search(r'# root: //(.*)', old_pydeps_data) |
| 1560 if not m: |
| 1561 return ['COULD NOT FIND .pydeps ROOT'] |
| 1562 root = m.group(1) or '.' |
| 1563 |
| 1564 cmd = ['build/print_python_deps.py', '--root', root, target] |
| 1565 new_pydeps_data = self._input_api.subprocess.check_output(cmd) |
| 1566 if old_pydeps_data != new_pydeps_data: |
| 1567 return cmd[:-1] + ['--output', pydeps_path] + cmd[-1:] |
| 1568 |
| 1569 |
| 1570 def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None): |
| 1571 """Checks if a .pydeps file needs to be regenerated.""" |
| 1572 results = [] |
| 1573 # First, check for new / deleted .pydeps. |
| 1574 for f in input_api.AffectedFiles(include_deletes=True): |
| 1575 if f.LocalPath().endswith('.pydeps'): |
| 1576 if f.Action() == 'D' and f.LocalPath() in _PYDEPS_FILES: |
| 1577 results.append(output_api.PresubmitError( |
| 1578 'Please update _PYDEPS_FILES within //PRESUBMIT.py to remove %s' % |
| 1579 f.LocalPath())) |
| 1580 elif f.Action() != 'D' and f.LocalPath() not in _PYDEPS_FILES: |
| 1581 results.append(output_api.PresubmitError( |
| 1582 'Please update _PYDEPS_FILES within //PRESUBMIT.py to include %s' % |
| 1583 f.LocalPath())) |
| 1584 |
| 1585 if results: |
| 1586 return results |
| 1587 |
| 1588 checker = checker_for_tests or PydepsChecker(input_api) |
| 1589 |
| 1590 for pydep_path in checker.ComputeAffectedPydeps(): |
| 1591 try: |
| 1592 cmd = checker.DetermineIfStale(pydep_path) |
| 1593 if cmd: |
| 1594 results.append(output_api.PresubmitError( |
| 1595 'File is stale: %s\nTo regenerate, run:\n%s' % (pydep_path, |
| 1596 ' '.join(cmd)))) |
| 1597 except input_api.subprocess.CalledProcessError as error: |
| 1598 return [output_api.PresubmitError('Error running ' + ' '.join(error.cmd), |
| 1599 long_text=error.output)] |
| 1600 |
| 1601 return results |
| 1602 |
| 1603 |
1500 def _CheckForCopyrightedCode(input_api, output_api): | 1604 def _CheckForCopyrightedCode(input_api, output_api): |
1501 """Verifies that newly added code doesn't contain copyrighted material | 1605 """Verifies that newly added code doesn't contain copyrighted material |
1502 and is properly licensed under the standard Chromium license. | 1606 and is properly licensed under the standard Chromium license. |
1503 | 1607 |
1504 As there can be false positives, we maintain a whitelist file. This check | 1608 As there can be false positives, we maintain a whitelist file. This check |
1505 also verifies that the whitelist file is up to date. | 1609 also verifies that the whitelist file is up to date. |
1506 """ | 1610 """ |
1507 import sys | 1611 import sys |
1508 original_sys_path = sys.path | 1612 original_sys_path = sys.path |
1509 try: | 1613 try: |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1643 (fpath.LocalPath(), lnum, deprecated, replacement))) | 1747 (fpath.LocalPath(), lnum, deprecated, replacement))) |
1644 return results | 1748 return results |
1645 | 1749 |
1646 | 1750 |
1647 def _AndroidSpecificOnUploadChecks(input_api, output_api): | 1751 def _AndroidSpecificOnUploadChecks(input_api, output_api): |
1648 """Groups checks that target android code.""" | 1752 """Groups checks that target android code.""" |
1649 results = [] | 1753 results = [] |
1650 results.extend(_CheckAndroidCrLogUsage(input_api, output_api)) | 1754 results.extend(_CheckAndroidCrLogUsage(input_api, output_api)) |
1651 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api)) | 1755 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api)) |
1652 results.extend(_CheckAndroidToastUsage(input_api, output_api)) | 1756 results.extend(_CheckAndroidToastUsage(input_api, output_api)) |
| 1757 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api)) |
1653 return results | 1758 return results |
1654 | 1759 |
1655 | 1760 |
1656 def _CommonChecks(input_api, output_api): | 1761 def _CommonChecks(input_api, output_api): |
1657 """Checks common to both upload and commit.""" | 1762 """Checks common to both upload and commit.""" |
1658 results = [] | 1763 results = [] |
1659 results.extend(input_api.canned_checks.PanProjectChecks( | 1764 results.extend(input_api.canned_checks.PanProjectChecks( |
1660 input_api, output_api, | 1765 input_api, output_api, |
1661 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS)) | 1766 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS)) |
1662 results.extend(_CheckAuthorizedAuthor(input_api, output_api)) | 1767 results.extend(_CheckAuthorizedAuthor(input_api, output_api)) |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1974 results.extend(input_api.canned_checks.CheckTreeIsOpen( | 2079 results.extend(input_api.canned_checks.CheckTreeIsOpen( |
1975 input_api, | 2080 input_api, |
1976 output_api, | 2081 output_api, |
1977 json_url='http://chromium-status.appspot.com/current?format=json')) | 2082 json_url='http://chromium-status.appspot.com/current?format=json')) |
1978 | 2083 |
1979 results.extend(input_api.canned_checks.CheckChangeHasBugField( | 2084 results.extend(input_api.canned_checks.CheckChangeHasBugField( |
1980 input_api, output_api)) | 2085 input_api, output_api)) |
1981 results.extend(input_api.canned_checks.CheckChangeHasDescription( | 2086 results.extend(input_api.canned_checks.CheckChangeHasDescription( |
1982 input_api, output_api)) | 2087 input_api, output_api)) |
1983 return results | 2088 return results |
OLD | NEW |