Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Enables directory-specific presubmit checks to run at upload and/or commit. | 6 """Enables directory-specific presubmit checks to run at upload and/or commit. |
| 7 """ | 7 """ |
| 8 | 8 |
| 9 __version__ = '1.6.1' | 9 __version__ = '1.6.1' |
| 10 | 10 |
| 11 # TODO(joi) Add caching where appropriate/needed. The API is designed to allow | 11 # TODO(joi) Add caching where appropriate/needed. The API is designed to allow |
| 12 # caching (between all different invocations of presubmit scripts for a given | 12 # caching (between all different invocations of presubmit scripts for a given |
| 13 # change). We should add it as our presubmit scripts start feeling slow. | 13 # change). We should add it as our presubmit scripts start feeling slow. |
| 14 | 14 |
| 15 import cPickle # Exposed through the API. | 15 import cPickle # Exposed through the API. |
| 16 import cStringIO # Exposed through the API. | 16 import cStringIO # Exposed through the API. |
| 17 import contextlib | |
| 17 import fnmatch | 18 import fnmatch |
| 18 import glob | 19 import glob |
| 19 import inspect | 20 import inspect |
| 20 import json # Exposed through the API. | 21 import json # Exposed through the API. |
| 21 import logging | 22 import logging |
| 22 import marshal # Exposed through the API. | 23 import marshal # Exposed through the API. |
| 23 import optparse | 24 import optparse |
| 24 import os # Somewhat exposed through the API. | 25 import os # Somewhat exposed through the API. |
| 25 import pickle # Exposed through the API. | 26 import pickle # Exposed through the API. |
| 26 import random | 27 import random |
| (...skipping 1164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1191 if not files: | 1192 if not files: |
| 1192 files = scm.GIT.CaptureStatus([], options.root, None) | 1193 files = scm.GIT.CaptureStatus([], options.root, None) |
| 1193 else: | 1194 else: |
| 1194 logging.info('Doesn\'t seem under source control. Got %d files' % len(args)) | 1195 logging.info('Doesn\'t seem under source control. Got %d files' % len(args)) |
| 1195 if not files: | 1196 if not files: |
| 1196 return None, None | 1197 return None, None |
| 1197 change_class = Change | 1198 change_class = Change |
| 1198 return change_class, files | 1199 return change_class, files |
| 1199 | 1200 |
| 1200 | 1201 |
| 1202 class NonexistantCannedCheckFilter(Exception): | |
| 1203 pass | |
| 1204 | |
|
M-A Ruel
2013/03/08 02:09:02
2 lines
| |
| 1205 @contextlib.contextmanager | |
| 1206 def canned_check_filter(method_names): | |
| 1207 filtered = {} | |
| 1208 try: | |
| 1209 for method_name in method_names: | |
| 1210 if hasattr(presubmit_canned_checks, method_name): | |
|
M-A Ruel
2013/03/08 02:09:02
if not hasattr():
raise
then align -2 lines 1211
| |
| 1211 filtered[method_name] = getattr(presubmit_canned_checks, method_name) | |
| 1212 setattr(presubmit_canned_checks, method_name, lambda *_a, **_kw: []) | |
| 1213 else: | |
| 1214 raise NonexistantCannedCheckFilter(method_name) | |
| 1215 yield | |
| 1216 finally: | |
| 1217 for name, method in filtered.iteritems(): | |
| 1218 setattr(presubmit_canned_checks, name, method) | |
| 1219 | |
| 1220 | |
| 1201 def Main(argv): | 1221 def Main(argv): |
| 1202 parser = optparse.OptionParser(usage="%prog [options] <files...>", | 1222 parser = optparse.OptionParser(usage="%prog [options] <files...>", |
| 1203 version="%prog " + str(__version__)) | 1223 version="%prog " + str(__version__)) |
| 1204 parser.add_option("-c", "--commit", action="store_true", default=False, | 1224 parser.add_option("-c", "--commit", action="store_true", default=False, |
| 1205 help="Use commit instead of upload checks") | 1225 help="Use commit instead of upload checks") |
| 1206 parser.add_option("-u", "--upload", action="store_false", dest='commit', | 1226 parser.add_option("-u", "--upload", action="store_false", dest='commit', |
| 1207 help="Use upload instead of commit checks") | 1227 help="Use upload instead of commit checks") |
| 1208 parser.add_option("-r", "--recursive", action="store_true", | 1228 parser.add_option("-r", "--recursive", action="store_true", |
| 1209 help="Act recursively") | 1229 help="Act recursively") |
| 1210 parser.add_option("-v", "--verbose", action="count", default=0, | 1230 parser.add_option("-v", "--verbose", action="count", default=0, |
| 1211 help="Use 2 times for more debug info") | 1231 help="Use 2 times for more debug info") |
| 1212 parser.add_option("--name", default='no name') | 1232 parser.add_option("--name", default='no name') |
| 1213 parser.add_option("--author") | 1233 parser.add_option("--author") |
| 1214 parser.add_option("--description", default='') | 1234 parser.add_option("--description", default='') |
| 1215 parser.add_option("--issue", type='int', default=0) | 1235 parser.add_option("--issue", type='int', default=0) |
| 1216 parser.add_option("--patchset", type='int', default=0) | 1236 parser.add_option("--patchset", type='int', default=0) |
| 1217 parser.add_option("--root", default=os.getcwd(), | 1237 parser.add_option("--root", default=os.getcwd(), |
| 1218 help="Search for PRESUBMIT.py up to this directory. " | 1238 help="Search for PRESUBMIT.py up to this directory. " |
| 1219 "If inherit-review-settings-ok is present in this " | 1239 "If inherit-review-settings-ok is present in this " |
| 1220 "directory, parent directories up to the root file " | 1240 "directory, parent directories up to the root file " |
| 1221 "system directories will also be searched.") | 1241 "system directories will also be searched.") |
| 1222 parser.add_option("--default_presubmit") | 1242 parser.add_option("--default_presubmit") |
| 1223 parser.add_option("--may_prompt", action='store_true', default=False) | 1243 parser.add_option("--may_prompt", action='store_true', default=False) |
| 1244 parser.add_option("--skip_canned", action='append', default=[], | |
| 1245 help="A list of checks to skip which appear in " | |
| 1246 "presubmit_canned_checks. Can be provided multiple times " | |
| 1247 "to skip multiple canned checks.") | |
| 1224 parser.add_option("--rietveld_url", help=optparse.SUPPRESS_HELP) | 1248 parser.add_option("--rietveld_url", help=optparse.SUPPRESS_HELP) |
| 1225 parser.add_option("--rietveld_email", help=optparse.SUPPRESS_HELP) | 1249 parser.add_option("--rietveld_email", help=optparse.SUPPRESS_HELP) |
| 1226 parser.add_option("--rietveld_password", help=optparse.SUPPRESS_HELP) | 1250 parser.add_option("--rietveld_password", help=optparse.SUPPRESS_HELP) |
| 1227 options, args = parser.parse_args(argv) | 1251 options, args = parser.parse_args(argv) |
| 1228 if options.verbose >= 2: | 1252 if options.verbose >= 2: |
| 1229 logging.basicConfig(level=logging.DEBUG) | 1253 logging.basicConfig(level=logging.DEBUG) |
| 1230 elif options.verbose: | 1254 elif options.verbose: |
| 1231 logging.basicConfig(level=logging.INFO) | 1255 logging.basicConfig(level=logging.INFO) |
| 1232 else: | 1256 else: |
| 1233 logging.basicConfig(level=logging.ERROR) | 1257 logging.basicConfig(level=logging.ERROR) |
| 1234 change_class, files = load_files(options, args) | 1258 change_class, files = load_files(options, args) |
| 1235 if not change_class: | 1259 if not change_class: |
| 1236 parser.error('For unversioned directory, <files> is not optional.') | 1260 parser.error('For unversioned directory, <files> is not optional.') |
| 1237 logging.info('Found %d file(s).' % len(files)) | 1261 logging.info('Found %d file(s).' % len(files)) |
| 1238 rietveld_obj = None | 1262 rietveld_obj = None |
| 1239 if options.rietveld_url: | 1263 if options.rietveld_url: |
| 1240 rietveld_obj = rietveld.CachingRietveld( | 1264 rietveld_obj = rietveld.CachingRietveld( |
| 1241 options.rietveld_url, | 1265 options.rietveld_url, |
| 1242 options.rietveld_email, | 1266 options.rietveld_email, |
| 1243 options.rietveld_password) | 1267 options.rietveld_password) |
| 1244 try: | 1268 try: |
| 1245 results = DoPresubmitChecks( | 1269 with canned_check_filter(options.skip_canned): |
| 1246 change_class(options.name, | 1270 results = DoPresubmitChecks( |
| 1247 options.description, | 1271 change_class(options.name, |
| 1248 options.root, | 1272 options.description, |
| 1249 files, | 1273 options.root, |
| 1250 options.issue, | 1274 files, |
| 1251 options.patchset, | 1275 options.issue, |
| 1252 options.author), | 1276 options.patchset, |
| 1253 options.commit, | 1277 options.author), |
| 1254 options.verbose, | 1278 options.commit, |
| 1255 sys.stdout, | 1279 options.verbose, |
| 1256 sys.stdin, | 1280 sys.stdout, |
| 1257 options.default_presubmit, | 1281 sys.stdin, |
| 1258 options.may_prompt, | 1282 options.default_presubmit, |
| 1259 rietveld_obj) | 1283 options.may_prompt, |
| 1284 rietveld_obj) | |
| 1260 return not results.should_continue() | 1285 return not results.should_continue() |
| 1286 except NonexistantCannedCheckFilter, e: | |
| 1287 print >> sys.stderr, ( | |
| 1288 'Attempted to skip nonexistent canned presubmit check: %s' % e.message) | |
| 1289 return 2 | |
| 1261 except PresubmitFailure, e: | 1290 except PresubmitFailure, e: |
| 1262 print >> sys.stderr, e | 1291 print >> sys.stderr, e |
| 1263 print >> sys.stderr, 'Maybe your depot_tools is out of date?' | 1292 print >> sys.stderr, 'Maybe your depot_tools is out of date?' |
| 1264 print >> sys.stderr, 'If all fails, contact maruel@' | 1293 print >> sys.stderr, 'If all fails, contact maruel@' |
| 1265 return 2 | 1294 return 2 |
| 1266 | 1295 |
| 1267 | 1296 |
| 1268 if __name__ == '__main__': | 1297 if __name__ == '__main__': |
| 1269 fix_encoding.fix_encoding() | 1298 fix_encoding.fix_encoding() |
| 1270 sys.exit(Main(None)) | 1299 sys.exit(Main(None)) |
| OLD | NEW |