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