PRESUBMIT.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
1# Copyright (c) 2012 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"""Presubmit script for changes affecting extensions.
6
7See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
8for more details about the presubmit API built into gcl.
9"""
10import fnmatch
11import os
12import re
13
14EXTENSIONS_PATH = os.path.join('chrome', 'common', 'extensions')
15DOCS_PATH = os.path.join(EXTENSIONS_PATH, 'docs')
16SERVER2_PATH = os.path.join(DOCS_PATH, 'server2')
17API_PATH = os.path.join(EXTENSIONS_PATH, 'api')
18TEMPLATES_PATH = os.path.join(DOCS_PATH, 'templates')
19PRIVATE_TEMPLATES_PATH = os.path.join(TEMPLATES_PATH, 'private')
20PUBLIC_TEMPLATES_PATH = os.path.join(TEMPLATES_PATH, 'public')
21INTROS_PATH = os.path.join(TEMPLATES_PATH, 'intros')
22ARTICLES_PATH = os.path.join(TEMPLATES_PATH, 'articles')
23
24LOCAL_PUBLIC_TEMPLATES_PATH = os.path.join('docs',
25                                           'templates',
26                                           'public')
27
28def _ListFilesInPublic():
29  all_files = []
30  for path, dirs, files in os.walk(LOCAL_PUBLIC_TEMPLATES_PATH):
31    all_files.extend(
32        os.path.join(path, filename)[len(LOCAL_PUBLIC_TEMPLATES_PATH + os.sep):]
33        for filename in files)
34  return all_files
35
36def _UnixName(name):
37  name = os.path.splitext(name)[0]
38  s1 = re.sub('([a-z])([A-Z])', r'\1_\2', name)
39  s2 = re.sub('([A-Z]+)([A-Z][a-z])', r'\1_\2', s1)
40  return s2.replace('.', '_').lower()
41
42def _FindMatchingTemplates(template_name, template_path_list):
43  matches = []
44  unix_name = _UnixName(template_name)
45  for template in template_path_list:
46    if unix_name == _UnixName(template.split(os.sep)[-1]):
47      matches.append(template)
48  return matches
49
50def _SanitizeAPIName(name, api_path):
51  if not api_path.endswith(os.sep):
52    api_path += os.sep
53  filename = os.path.splitext(name)[0][len(api_path):].replace(os.sep, '_')
54  if 'experimental' in filename:
55    filename = 'experimental_' + filename.replace('experimental_', '')
56  return filename
57
58def _CreateIntegrationTestArgs(affected_files):
59  if (any(fnmatch.fnmatch(name, '%s*.py' % SERVER2_PATH)
60         for name in affected_files) or
61      any(fnmatch.fnmatch(name, '%s*' % PRIVATE_TEMPLATES_PATH)
62          for name in affected_files)):
63    return ['-a']
64  args = []
65  for name in affected_files:
66    if (fnmatch.fnmatch(name, '%s*' % PUBLIC_TEMPLATES_PATH) or
67        fnmatch.fnmatch(name, '%s*' % INTROS_PATH) or
68        fnmatch.fnmatch(name, '%s*' % ARTICLES_PATH)):
69      args.extend(_FindMatchingTemplates(name.split(os.sep)[-1],
70                                         _ListFilesInPublic()))
71    if fnmatch.fnmatch(name, '%s*' % API_PATH):
72      args.extend(_FindMatchingTemplates(_SanitizeAPIName(name, API_PATH),
73                                         _ListFilesInPublic()))
74  return args
75
76def _CheckHeadingIDs(input_api):
77  ids_re = re.compile('<h[23].*id=.*?>')
78  headings_re = re.compile('<h[23].*?>')
79  bad_files = []
80  for name in input_api.AbsoluteLocalPaths():
81    if (fnmatch.fnmatch(name, '*%s*' % INTROS_PATH) or
82        fnmatch.fnmatch(name, '*%s*' % ARTICLES_PATH)):
83      contents = input_api.ReadFile(name)
84      if (len(re.findall(headings_re, contents)) !=
85          len(re.findall(ids_re, contents))):
86        bad_files.append(name)
87  return bad_files
88
89def _CheckVersions(input_api, output_api, results):
90  version = '_VERSION ='
91  for affected_file in input_api.AffectedFiles():
92    local_path = affected_file.LocalPath()
93    if not fnmatch.fnmatch(local_path, '%s*' % SERVER2_PATH):
94      continue
95    if local_path.endswith('PRESUBMIT.py'):
96      continue
97    if any(version in line for line in affected_file.NewContents()):
98      found = False
99      for _, text in affected_file.ChangedContents():
100        if version in text:
101          found = True
102          break
103      if not found:
104        results.append(output_api.PresubmitError(
105            '_VERSION of %s needs to be incremented.' % affected_file))
106
107def _CheckChange(input_api, output_api):
108  results = [
109      output_api.PresubmitError('File %s needs an id for each heading.' % name)
110      for name in _CheckHeadingIDs(input_api)]
111  try:
112    integration_test = []
113    # From depot_tools/presubmit_canned_checks.py:529
114    if input_api.platform == 'win32':
115      integration_test = [input_api.python_executable]
116    integration_test.append(
117        os.path.join('docs', 'server2', 'integration_test.py'))
118    integration_test.extend(_CreateIntegrationTestArgs(input_api.LocalPaths()))
119    input_api.subprocess.check_call(integration_test,
120                                    cwd=input_api.PresubmitLocalPath())
121  except input_api.subprocess.CalledProcessError:
122    results.append(output_api.PresubmitError('IntegrationTest failed!'))
123  _CheckVersions(input_api, output_api, results)
124  return results
125
126def CheckChangeOnUpload(input_api, output_api):
127  return _CheckChange(input_api, output_api)
128
129def CheckChangeOnCommit(input_api, output_api):
130  return _CheckChange(input_api, output_api)
131