Upstream version 9.38.198.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(), '..', '..', 'buildtools', '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     printf_re = input_api.re.compile(r'^\s*printf\(')
254     errors = input_api.canned_checks._FindNewViolationsOfRule(
255         lambda _, x: not printf_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 _CheckForDangerousTestFunctions(input_api, output_api):
267     """Tests should not be using serveAsynchronousMockedRequests, since it does
268     not guarantee that the threaded HTML parser will have completed."""
269     serve_async_requests_re = input_api.re.compile(
270         r'serveAsynchronousMockedRequests')
271     errors = input_api.canned_checks._FindNewViolationsOfRule(
272         lambda _, x: not serve_async_requests_re.search(x),
273         input_api, None)
274     errors = ['  * %s' % violation for violation in errors]
275     if errors:
276         return [output_api.PresubmitError(
277                     'You should be using FrameTestHelpers::'
278                     'pumpPendingRequests() instead of '
279                     'serveAsynchronousMockedRequests() in the following '
280                     'locations:\n%s' % '\n'.join(errors))]
281     return []
282
283
284 def _CheckForFailInFile(input_api, f):
285     pattern = input_api.re.compile('^FAIL')
286     errors = []
287     for line_num, line in f.ChangedContents():
288         if pattern.match(line):
289             errors.append('    %s:%d %s' % (f.LocalPath(), line_num, line))
290     return errors
291
292
293 def _CheckFilePermissions(input_api, output_api):
294     """Check that all files have their permissions properly set."""
295     if input_api.platform == 'win32':
296         return []
297     path = input_api.os_path.join(
298         '..', '..', 'tools', 'checkperms', 'checkperms.py')
299     args = [sys.executable, path, '--root', input_api.change.RepositoryRoot()]
300     for f in input_api.AffectedFiles():
301         args += ['--file', f.LocalPath()]
302     checkperms = input_api.subprocess.Popen(
303         args, stdout=input_api.subprocess.PIPE)
304     errors = checkperms.communicate()[0].strip()
305     if errors:
306         return [output_api.PresubmitError(
307             'checkperms.py failed.', errors.splitlines())]
308     return []
309
310
311 def _CheckForInvalidPreferenceError(input_api, output_api):
312     pattern = input_api.re.compile('Invalid name for preference: (.+)')
313     results = []
314
315     for f in input_api.AffectedFiles():
316         if not f.LocalPath().endswith('-expected.txt'):
317             continue
318         for line_num, line in f.ChangedContents():
319             error = pattern.search(line)
320             if error:
321                 results.append(output_api.PresubmitError('Found an invalid preference %s in expected result %s:%s' % (error.group(1), f, line_num)))
322     return results
323
324 def CheckChangeOnUpload(input_api, output_api):
325     results = []
326     results.extend(_CommonChecks(input_api, output_api))
327     results.extend(_CheckStyle(input_api, output_api))
328     results.extend(_CheckForPrintfDebugging(input_api, output_api))
329     results.extend(_CheckForDangerousTestFunctions(input_api, output_api))
330     results.extend(_CheckForInvalidPreferenceError(input_api, output_api))
331     return results
332
333
334 def CheckChangeOnCommit(input_api, output_api):
335     results = []
336     results.extend(_CommonChecks(input_api, output_api))
337     results.extend(input_api.canned_checks.CheckTreeIsOpen(
338         input_api, output_api,
339         json_url='http://blink-status.appspot.com/current?format=json'))
340     results.extend(input_api.canned_checks.CheckChangeHasDescription(
341         input_api, output_api))
342     results.extend(_CheckSubversionConfig(input_api, output_api))
343     return results
344
345
346 def GetPreferredTryMasters(project, change):
347     return {
348         'tryserver.blink': {
349             'android_blink_compile_dbg': set(['defaulttests']),
350             'android_blink_compile_rel': set(['defaulttests']),
351             'android_chromium_gn_compile_rel': set(['defaulttests']),
352             'linux_blink_dbg': set(['defaulttests']),
353             'linux_blink_rel': set(['defaulttests']),
354             'linux_chromium_gn_rel': set(['defaulttests']),
355             'mac_blink_compile_dbg': set(['defaulttests']),
356             'mac_blink_rel': set(['defaulttests']),
357             'win_blink_compile_dbg': set(['defaulttests']),
358             'win_blink_rel': set(['defaulttests']),
359         },
360         'tryserver.chromium.gpu': {
361             'linux_gpu': set(['defaulttests']),
362             'mac_gpu': set(['defaulttests']),
363             'win_gpu': set(['defaulttests']),
364         }
365     }