[email protected] | ca8d1984 | 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] | ca8d1984 | 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] | ca8d1984 | 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] | ca8d1984 | 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] | b4971ce | 2009-03-05 16:14:55 | [diff] [blame] | 45 | # TODO(maruel): max_cols is temporarily disabled. Reenable once the source |
| 46 | # tree is in better shape. |
| 47 | return LocalChecks(input_api, output_api, max_cols=0) |
[email protected] | ca8d1984 | 2009-02-19 16:33:12 | [diff] [blame] | 48 | |
| 49 | |
| 50 | def CheckChangeOnCommit(input_api, output_api): |
[email protected] | b4971ce | 2009-03-05 16:14:55 | [diff] [blame] | 51 | # TODO(maruel): max_cols is temporarily disabled. Reenable once the source |
| 52 | # tree is in better shape. |
| 53 | return (LocalChecks(input_api, output_api, max_cols=0) + |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame] | 54 | input_api.canned_checks.CheckDoNotSubmit(input_api, output_api)) |
[email protected] | ca8d1984 | 2009-02-19 16:33:12 | [diff] [blame] | 55 | |
| 56 | |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame] | 57 | def LocalChecks(input_api, output_api, max_cols=80): |
| 58 | """Reports an error if for any source file in SOURCE_FILE_EXTENSIONS: |
| 59 | - uses CR (or CRLF) |
| 60 | - contains a TAB |
| 61 | - has a line that ends with whitespace |
| 62 | - contains a line >|max_cols| cols unless |max_cols| is 0. |
[email protected] | 2fcccc7 | 2009-03-10 13:55:09 | [diff] [blame] | 63 | - File does not end in a newline, or ends in more than one. |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame] | 64 | |
| 65 | Note that the whole file is checked, not only the changes. |
[email protected] | ca8d1984 | 2009-02-19 16:33:12 | [diff] [blame] | 66 | """ |
[email protected] | db24f36 | 2009-03-10 17:13:42 | [diff] [blame] | 67 | C_SOURCE_FILE_EXTENSIONS = ('.c', '.cc', '.cpp', '.h', '.inl') |
[email protected] | ca8d1984 | 2009-02-19 16:33:12 | [diff] [blame] | 68 | cr_files = [] |
[email protected] | 2fcccc7 | 2009-03-10 13:55:09 | [diff] [blame] | 69 | eof_files = [] |
[email protected] | ca8d1984 | 2009-02-19 16:33:12 | [diff] [blame] | 70 | results = [] |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame] | 71 | excluded_paths = [input_api.re.compile(x) for x in EXCLUDED_PATHS] |
[email protected] | 93372117 | 2009-03-13 04:35:37 | [diff] [blame^] | 72 | files = input_api.AffectedFiles(include_deletes=False) |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame] | 73 | for f in files: |
[email protected] | ca8d1984 | 2009-02-19 16:33:12 | [diff] [blame] | 74 | path = f.LocalPath() |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame] | 75 | root, ext = input_api.os_path.splitext(path) |
| 76 | # Look for unsupported extensions. |
| 77 | if not ext in SOURCE_FILE_EXTENSIONS: |
| 78 | continue |
| 79 | # Look for excluded paths. |
| 80 | found = False |
| 81 | for item in excluded_paths: |
| 82 | if item.match(path): |
| 83 | found = True |
| 84 | break |
| 85 | if found: |
| 86 | continue |
| 87 | |
| 88 | # Need to read the file ourselves since AffectedFile.NewContents() |
| 89 | # will normalize line endings. |
| 90 | contents = _ReadFile(path) |
| 91 | if '\r' in contents: |
| 92 | cr_files.append(path) |
| 93 | |
[email protected] | 2fcccc7 | 2009-03-10 13:55:09 | [diff] [blame] | 94 | # Check that the file ends in one and only one newline character. |
| 95 | if len(contents) > 0 and (contents[-1:] != "\n" or contents[-2:-1] == "\n"): |
| 96 | eof_files.append(path) |
| 97 | |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame] | 98 | local_errors = [] |
| 99 | # Remove EOL character. |
| 100 | lines = contents.splitlines() |
| 101 | line_num = 1 |
| 102 | for line in lines: |
| 103 | if line.endswith(' '): |
| 104 | local_errors.append(output_api.PresubmitError( |
| 105 | '%s, line %s ends with whitespaces.' % |
| 106 | (path, line_num))) |
[email protected] | db24f36 | 2009-03-10 17:13:42 | [diff] [blame] | 107 | # Accept lines with http://, https:// and C #define/#pragma/#include to |
| 108 | # exceed the max_cols rule. |
| 109 | if (max_cols and |
| 110 | len(line) > max_cols and |
| 111 | not 'http://' in line and |
| 112 | not 'https://' in line and |
| 113 | not (line[0] == '#' and ext in C_SOURCE_FILE_EXTENSIONS)): |
[email protected] | 3347870 | 2009-03-05 14:03:14 | [diff] [blame] | 114 | local_errors.append(output_api.PresubmitError( |
| 115 | '%s, line %s has %s chars, please reduce to %d chars.' % |
| 116 | (path, line_num, len(line), max_cols))) |
| 117 | if '\t' in line: |
| 118 | local_errors.append(output_api.PresubmitError( |
| 119 | "%s, line %s contains a tab character." % |
| 120 | (path, line_num))) |
| 121 | line_num += 1 |
| 122 | # Just show the first 5 errors. |
| 123 | if len(local_errors) == 6: |
| 124 | local_errors.pop() |
| 125 | local_errors.append(output_api.PresubmitError("... and more.")) |
| 126 | break |
| 127 | results.extend(local_errors) |
| 128 | |
[email protected] | ca8d1984 | 2009-02-19 16:33:12 | [diff] [blame] | 129 | if cr_files: |
| 130 | results.append(output_api.PresubmitError( |
| 131 | 'Found CR (or CRLF) line ending in these files, please use only LF:', |
| 132 | items=cr_files)) |
[email protected] | 2fcccc7 | 2009-03-10 13:55:09 | [diff] [blame] | 133 | if eof_files: |
| 134 | results.append(output_api.PresubmitError( |
| 135 | 'These files should end in one (and only one) newline character:', |
| 136 | items=eof_files)) |
[email protected] | ca8d1984 | 2009-02-19 16:33:12 | [diff] [blame] | 137 | return results |