[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | """Top-level presubmit script for Chromium. |
| 7 | |
| 8 | See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for |
| 9 | details on the presubmit API built into gcl. |
| 10 | """ |
| 11 | |
[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 12 | # Files with these extensions will be considered source files |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame^] | 13 | SOURCE_FILE_EXTENSIONS = [ |
| 14 | '.c', '.cc', '.cpp', '.h', '.m', '.mm', '.py', '.mk', '.am', '.json', |
| 15 | ] |
| 16 | EXCLUDED_PATHS = [ |
| 17 | r"breakpad[\\\/].*", |
| 18 | r"chrome[\\\/]Debug[\\\/].*", |
| 19 | r"chrome[\\\/]Hammer[\\\/].*", |
| 20 | r"chrome[\\\/]Release[\\\/].*", |
| 21 | r"xcodebuild[\\\/].*", |
| 22 | r"skia[\\\/].*", |
| 23 | r".*third_party[\\\/].*", |
| 24 | r"v8[\\\/].*", |
| 25 | ] |
[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 26 | |
| 27 | def ReadFile(path): |
| 28 | """Given a path, returns the full contents of the file. |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame^] | 29 | |
[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 30 | Reads files in binary format. |
| 31 | """ |
| 32 | fo = open(path, 'rb') |
| 33 | try: |
| 34 | contents = fo.read() |
| 35 | finally: |
| 36 | fo.close() |
| 37 | return contents |
| 38 | |
| 39 | |
| 40 | # Seam for unit testing |
| 41 | _ReadFile = ReadFile |
| 42 | |
| 43 | |
| 44 | def CheckChangeOnUpload(input_api, output_api): |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame^] | 45 | return LocalChecks(input_api, output_api) |
[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 46 | |
| 47 | |
| 48 | def CheckChangeOnCommit(input_api, output_api): |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame^] | 49 | return (LocalChecks(input_api, output_api) + |
| 50 | input_api.canned_checks.CheckDoNotSubmit(input_api, output_api)) |
[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 51 | |
| 52 | |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame^] | 53 | def LocalChecks(input_api, output_api, max_cols=80): |
| 54 | """Reports an error if for any source file in SOURCE_FILE_EXTENSIONS: |
| 55 | - uses CR (or CRLF) |
| 56 | - contains a TAB |
| 57 | - has a line that ends with whitespace |
| 58 | - contains a line >|max_cols| cols unless |max_cols| is 0. |
| 59 | |
| 60 | Note that the whole file is checked, not only the changes. |
[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 61 | """ |
| 62 | cr_files = [] |
[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 63 | results = [] |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame^] | 64 | excluded_paths = [input_api.re.compile(x) for x in EXCLUDED_PATHS] |
| 65 | files = input_api.AffectedFiles() |
| 66 | for f in files: |
[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 67 | path = f.LocalPath() |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame^] | 68 | root, ext = input_api.os_path.splitext(path) |
| 69 | # Look for unsupported extensions. |
| 70 | if not ext in SOURCE_FILE_EXTENSIONS: |
| 71 | continue |
| 72 | # Look for excluded paths. |
| 73 | found = False |
| 74 | for item in excluded_paths: |
| 75 | if item.match(path): |
| 76 | found = True |
| 77 | break |
| 78 | if found: |
| 79 | continue |
| 80 | |
| 81 | # Need to read the file ourselves since AffectedFile.NewContents() |
| 82 | # will normalize line endings. |
| 83 | contents = _ReadFile(path) |
| 84 | if '\r' in contents: |
| 85 | cr_files.append(path) |
| 86 | |
| 87 | local_errors = [] |
| 88 | # Remove EOL character. |
| 89 | lines = contents.splitlines() |
| 90 | line_num = 1 |
| 91 | for line in lines: |
| 92 | if line.endswith(' '): |
| 93 | local_errors.append(output_api.PresubmitError( |
| 94 | '%s, line %s ends with whitespaces.' % |
| 95 | (path, line_num))) |
| 96 | # Accept lines with http:// to exceed the max_cols rule. |
| 97 | if max_cols and len(line) > max_cols and not 'http://' in line: |
| 98 | local_errors.append(output_api.PresubmitError( |
| 99 | '%s, line %s has %s chars, please reduce to %d chars.' % |
| 100 | (path, line_num, len(line), max_cols))) |
| 101 | if '\t' in line: |
| 102 | local_errors.append(output_api.PresubmitError( |
| 103 | "%s, line %s contains a tab character." % |
| 104 | (path, line_num))) |
| 105 | line_num += 1 |
| 106 | # Just show the first 5 errors. |
| 107 | if len(local_errors) == 6: |
| 108 | local_errors.pop() |
| 109 | local_errors.append(output_api.PresubmitError("... and more.")) |
| 110 | break |
| 111 | results.extend(local_errors) |
| 112 | |
[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 113 | if cr_files: |
| 114 | results.append(output_api.PresubmitError( |
| 115 | 'Found CR (or CRLF) line ending in these files, please use only LF:', |
| 116 | items=cr_files)) |
[email protected] | ca8d198 | 2009-02-19 16:33:12 | [diff] [blame] | 117 | return results |