Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / PRESUBMIT.py
1 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Top-level presubmit script for Blink.
6
7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
8 for more details about the presubmit API built into gcl.
9 """
10
11 import sys
12
13
14 _EXCLUDED_PATHS = ()
15
16
17 def _CheckForVersionControlConflictsInFile(input_api, f):
18     pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
19     errors = []
20     for line_num, line in f.ChangedContents():
21         if pattern.match(line):
22             errors.append('    %s:%d %s' % (f.LocalPath(), line_num, line))
23     return errors
24
25
26 def _CheckForVersionControlConflicts(input_api, output_api):
27     """Usually this is not intentional and will cause a compile failure."""
28     errors = []
29     for f in input_api.AffectedFiles():
30         errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
31
32     results = []
33     if errors:
34         results.append(output_api.PresubmitError(
35             'Version control conflict markers found, please resolve.', errors))
36     return results
37
38
39 def _CheckWatchlist(input_api, output_api):
40     """Check that the WATCHLIST file parses correctly."""
41     errors = []
42     for f in input_api.AffectedFiles():
43         if f.LocalPath() != 'WATCHLISTS':
44             continue
45         import StringIO
46         import logging
47         import watchlists
48
49         log_buffer = StringIO.StringIO()
50         log_handler = logging.StreamHandler(log_buffer)
51         log_handler.setFormatter(
52             logging.Formatter('%(levelname)s: %(message)s'))
53         logger = logging.getLogger()
54         logger.addHandler(log_handler)
55
56         wl = watchlists.Watchlists(input_api.change.RepositoryRoot())
57
58         logger.removeHandler(log_handler)
59         log_handler.flush()
60         log_buffer.flush()
61
62         if log_buffer.getvalue():
63             errors.append(output_api.PresubmitError(
64                 'Cannot parse WATCHLISTS file, please resolve.',
65                 log_buffer.getvalue().splitlines()))
66     return errors
67
68
69 def _CommonChecks(input_api, output_api):
70     """Checks common to both upload and commit."""
71     # We should figure out what license checks we actually want to use.
72     license_header = r'.*'
73
74     results = []
75     results.extend(input_api.canned_checks.PanProjectChecks(
76         input_api, output_api, excluded_paths=_EXCLUDED_PATHS,
77         maxlen=800, license_header=license_header))
78     results.extend(_CheckForVersionControlConflicts(input_api, output_api))
79     results.extend(_CheckPatchFiles(input_api, output_api))
80     results.extend(_CheckTestExpectations(input_api, output_api))
81     results.extend(_CheckUnwantedDependencies(input_api, output_api))
82     results.extend(_CheckChromiumPlatformMacros(input_api, output_api))
83     results.extend(_CheckWatchlist(input_api, output_api))
84     results.extend(_CheckFilePermissions(input_api, output_api))
85     return results
86
87
88 def _CheckSubversionConfig(input_api, output_api):
89   """Verifies the subversion config file is correctly setup.
90
91   Checks that autoprops are enabled, returns an error otherwise.
92   """
93   join = input_api.os_path.join
94   if input_api.platform == 'win32':
95     appdata = input_api.environ.get('APPDATA', '')
96     if not appdata:
97       return [output_api.PresubmitError('%APPDATA% is not configured.')]
98     path = join(appdata, 'Subversion', 'config')
99   else:
100     home = input_api.environ.get('HOME', '')
101     if not home:
102       return [output_api.PresubmitError('$HOME is not configured.')]
103     path = join(home, '.subversion', 'config')
104
105   error_msg = (
106       'Please look at http://dev.chromium.org/developers/coding-style to\n'
107       'configure your subversion configuration file. This enables automatic\n'
108       'properties to simplify the project maintenance.\n'
109       'Pro-tip: just download and install\n'
110       'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
111
112   try:
113     lines = open(path, 'r').read().splitlines()
114     # Make sure auto-props is enabled and check for 2 Chromium standard
115     # auto-prop.
116     if (not '*.cc = svn:eol-style=LF' in lines or
117         not '*.pdf = svn:mime-type=application/pdf' in lines or
118         not 'enable-auto-props = yes' in lines):
119       return [
120           output_api.PresubmitNotifyResult(
121               'It looks like you have not configured your subversion config '
122               'file or it is not up-to-date.\n' + error_msg)
123       ]
124   except (OSError, IOError):
125     return [
126         output_api.PresubmitNotifyResult(
127             'Can\'t find your subversion config file.\n' + error_msg)
128     ]
129   return []
130
131
132 def _CheckPatchFiles(input_api, output_api):
133   problems = [f.LocalPath() for f in input_api.AffectedFiles()
134       if f.LocalPath().endswith(('.orig', '.rej'))]
135   if problems:
136     return [output_api.PresubmitError(
137         "Don't commit .rej and .orig files.", problems)]
138   else:
139     return []
140
141
142 def _CheckTestExpectations(input_api, output_api):
143     local_paths = [f.LocalPath() for f in input_api.AffectedFiles()]
144     if any(path.startswith('LayoutTests') for path in local_paths):
145         lint_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
146             'Tools', 'Scripts', 'lint-test-expectations')
147         _, errs = input_api.subprocess.Popen(
148             [input_api.python_executable, lint_path],
149             stdout=input_api.subprocess.PIPE,
150             stderr=input_api.subprocess.PIPE).communicate()
151         if not errs:
152             return [output_api.PresubmitError(
153                 "lint-test-expectations failed "
154                 "to produce output; check by hand. ")]
155         if errs.strip() != 'Lint succeeded.':
156             return [output_api.PresubmitError(errs)]
157     return []
158
159
160 def _CheckStyle(input_api, output_api):
161     style_checker_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
162         'Tools', 'Scripts', 'check-webkit-style')
163     args = ([input_api.python_executable, style_checker_path, '--diff-files']
164         + [f.LocalPath() for f in input_api.AffectedFiles()])
165     results = []
166
167     try:
168         child = input_api.subprocess.Popen(args,
169                                            stderr=input_api.subprocess.PIPE)
170         _, stderrdata = child.communicate()
171         if child.returncode != 0:
172             results.append(output_api.PresubmitError(
173                 'check-webkit-style failed', [stderrdata]))
174     except Exception as e:
175         results.append(output_api.PresubmitNotifyResult(
176             'Could not run check-webkit-style', [str(e)]))
177
178     return results
179
180
181 def _CheckUnwantedDependencies(input_api, output_api):
182     """Runs checkdeps on #include statements added in this
183     change. Breaking - rules is an error, breaking ! rules is a
184     warning.
185     """
186     # We need to wait until we have an input_api object and use this
187     # roundabout construct to import checkdeps because this file is
188     # eval-ed and thus doesn't have __file__.
189     original_sys_path = sys.path
190     try:
191         sys.path = sys.path + [input_api.os_path.realpath(input_api.os_path.join(
192                 input_api.PresubmitLocalPath(), '..', '..', 'tools', 'checkdeps'))]
193         import checkdeps
194         from cpp_checker import CppChecker
195         from rules import Rule
196     finally:
197         # Restore sys.path to what it was before.
198         sys.path = original_sys_path
199
200     added_includes = []
201     for f in input_api.AffectedFiles():
202         if not CppChecker.IsCppFile(f.LocalPath()):
203             continue
204
205         changed_lines = [line for line_num, line in f.ChangedContents()]
206         added_includes.append([f.LocalPath(), changed_lines])
207
208     deps_checker = checkdeps.DepsChecker(
209         input_api.os_path.join(input_api.PresubmitLocalPath()))
210
211     error_descriptions = []
212     warning_descriptions = []
213     for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
214             added_includes):
215         description_with_path = '%s\n    %s' % (path, rule_description)
216         if rule_type == Rule.DISALLOW:
217             error_descriptions.append(description_with_path)
218         else:
219             warning_descriptions.append(description_with_path)
220
221     results = []
222     if error_descriptions:
223         results.append(output_api.PresubmitError(
224                 'You added one or more #includes that violate checkdeps rules.',
225                 error_descriptions))
226     if warning_descriptions:
227         results.append(output_api.PresubmitPromptOrNotify(
228                 'You added one or more #includes of files that are temporarily\n'
229                 'allowed but being removed. Can you avoid introducing the\n'
230                 '#include? See relevant DEPS file(s) for details and contacts.',
231                 warning_descriptions))
232     return results
233
234
235 def _CheckChromiumPlatformMacros(input_api, output_api, source_file_filter=None):
236     """Ensures that Blink code uses WTF's platform macros instead of
237     Chromium's. Using the latter has resulted in at least one subtle
238     build breakage."""
239     os_macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bOS_')
240     errors = input_api.canned_checks._FindNewViolationsOfRule(
241         lambda _, x: not os_macro_re.search(x),
242         input_api, source_file_filter)
243     errors = ['Found use of Chromium OS_* macro in %s. '
244         'Use WTF platform macros instead.' % violation for violation in errors]
245     if errors:
246         return [output_api.PresubmitPromptWarning('\n'.join(errors))]
247     return []
248
249
250 def _CheckForPrintfDebugging(input_api, output_api):
251     """Generally speaking, we'd prefer not to land patches that printf
252     debug output."""
253     os_macro_re = input_api.re.compile(r'^\s*printf\(')
254     errors = input_api.canned_checks._FindNewViolationsOfRule(
255         lambda _, x: not os_macro_re.search(x),
256         input_api, None)
257     errors = ['  * %s' % violation for violation in errors]
258     if errors:
259         return [output_api.PresubmitPromptOrNotify(
260                     'printf debugging is best debugging! That said, it might '
261                     'be a good idea to drop the following occurances from '
262                     'your patch before uploading:\n%s' % '\n'.join(errors))]
263     return []
264
265
266 def _CheckForFailInFile(input_api, f):
267     pattern = input_api.re.compile('^FAIL')
268     errors = []
269     for line_num, line in f.ChangedContents():
270         if pattern.match(line):
271             errors.append('    %s:%d %s' % (f.LocalPath(), line_num, line))
272     return errors
273
274
275 def _CheckFilePermissions(input_api, output_api):
276     """Check that all files have their permissions properly set."""
277     if input_api.platform == 'win32':
278         return []
279     path = input_api.os_path.join(
280         '..', '..', 'tools', 'checkperms', 'checkperms.py')
281     args = [sys.executable, path, '--root', input_api.change.RepositoryRoot()]
282     for f in input_api.AffectedFiles():
283         args += ['--file', f.LocalPath()]
284     checkperms = input_api.subprocess.Popen(
285         args, stdout=input_api.subprocess.PIPE)
286     errors = checkperms.communicate()[0].strip()
287     if errors:
288         return [output_api.PresubmitError(
289             'checkperms.py failed.', errors.splitlines())]
290     return []
291
292
293 def CheckChangeOnUpload(input_api, output_api):
294     results = []
295     results.extend(_CommonChecks(input_api, output_api))
296     results.extend(_CheckStyle(input_api, output_api))
297     results.extend(_CheckForPrintfDebugging(input_api, output_api))
298     return results
299
300
301 def CheckChangeOnCommit(input_api, output_api):
302     results = []
303     results.extend(_CommonChecks(input_api, output_api))
304     results.extend(input_api.canned_checks.CheckTreeIsOpen(
305         input_api, output_api,
306         json_url='http://blink-status.appspot.com/current?format=json'))
307     results.extend(input_api.canned_checks.CheckChangeHasDescription(
308         input_api, output_api))
309     results.extend(_CheckSubversionConfig(input_api, output_api))
310     return results
311
312 def GetPreferredTrySlaves(project, change):
313     return [
314         'linux_blink_rel', 'mac_blink_rel', 'win_blink_rel',
315         'linux_blink', 'mac_layout:webkit_lint', 'win_layout:webkit_lint',
316     ]