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