Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 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.3.5' | 9 __version__ = '1.4' |
| 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 exceptions | 17 import exceptions |
| 18 import fnmatch | 18 import fnmatch |
| 19 import glob | 19 import glob |
| (...skipping 1056 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1076 if items: | 1076 if items: |
| 1077 output.write('** Presubmit %s **\n' % name) | 1077 output.write('** Presubmit %s **\n' % name) |
| 1078 for item in items: | 1078 for item in items: |
| 1079 item.handle(output) | 1079 item.handle(output) |
| 1080 output.write('\n') | 1080 output.write('\n') |
| 1081 | 1081 |
| 1082 total_time = time.time() - start_time | 1082 total_time = time.time() - start_time |
| 1083 if total_time > 1.0: | 1083 if total_time > 1.0: |
| 1084 output.write("Presubmit checks took %.1fs to calculate.\n" % total_time) | 1084 output.write("Presubmit checks took %.1fs to calculate.\n" % total_time) |
| 1085 | 1085 |
| 1086 if not errors and warnings and may_prompt: | 1086 if not errors and warnings: |
| 1087 output.prompt_yes_no('There were presubmit warnings. ' | 1087 if may_prompt: |
| 1088 'Are you sure you wish to continue? (y/N): ') | 1088 output.prompt_yes_no('There were presubmit warnings. ' |
| 1089 'Are you sure you wish to continue? (y/N): ') | |
| 1090 else: | |
| 1091 output.fail() | |
| 1089 | 1092 |
| 1090 global _ASKED_FOR_FEEDBACK | 1093 global _ASKED_FOR_FEEDBACK |
| 1091 # Ask for feedback one time out of 5. | 1094 # Ask for feedback one time out of 5. |
| 1092 if (len(results) and random.randint(0, 4) == 0 and not _ASKED_FOR_FEEDBACK): | 1095 if (len(results) and random.randint(0, 4) == 0 and not _ASKED_FOR_FEEDBACK): |
| 1093 output.write("Was the presubmit check useful? Please send feedback " | 1096 output.write("Was the presubmit check useful? Please send feedback " |
| 1094 "& hate mail to maruel@chromium.org!\n") | 1097 "& hate mail to maruel@chromium.org!\n") |
| 1095 _ASKED_FOR_FEEDBACK = True | 1098 _ASKED_FOR_FEEDBACK = True |
| 1096 return output | 1099 return output |
| 1097 | 1100 |
| 1098 | 1101 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1113 | 1116 |
| 1114 | 1117 |
| 1115 def ParseFiles(args, recursive): | 1118 def ParseFiles(args, recursive): |
| 1116 logging.debug('Searching for %s' % args) | 1119 logging.debug('Searching for %s' % args) |
| 1117 files = [] | 1120 files = [] |
| 1118 for arg in args: | 1121 for arg in args: |
| 1119 files.extend([('M', f) for f in ScanSubDirs(arg, recursive)]) | 1122 files.extend([('M', f) for f in ScanSubDirs(arg, recursive)]) |
| 1120 return files | 1123 return files |
| 1121 | 1124 |
| 1122 | 1125 |
| 1126 def DetermineScm(options, args): | |
| 1127 """Tries to determine the SCM.""" | |
| 1128 files = [] | |
| 1129 if os.path.isdir(os.path.join(options.root, '.svn')): | |
| 1130 change_class = SvnChange | |
| 1131 status_fn = scm.SVN.CaptureStatus | |
| 1132 else: | |
| 1133 is_git = os.path.isdir(os.path.join(options.root, '.git')) | |
| 1134 if not is_git: | |
| 1135 is_git = (0 == subprocess.call( | |
| 1136 ['git', 'rev-parse', '--show-cdup'], | |
| 1137 stdout=subprocess.PIPE, cwd=options.root)) | |
| 1138 if is_git: | |
| 1139 # Only look at the subdirectories below cwd. | |
| 1140 change_class = GitChange | |
| 1141 status_fn = scm.GIT.CaptureStatus | |
| 1142 else: | |
| 1143 logging.info('Doesn\'t seem under source control. Got %d files' % | |
| 1144 len(args)) | |
| 1145 if not args: | |
| 1146 return None, None | |
| 1147 change_class = Change | |
| 1148 if args: | |
| 1149 files = ParseFiles(args, options.recursive) | |
| 1150 else: | |
| 1151 # Grab modified files. | |
| 1152 files = status_fn([options.root]) | |
| 1153 return change_class, files | |
| 1154 | |
| 1155 | |
|
Dirk Pranke
2011/03/17 19:12:56
Can we put this in scm.py? It doesn't feel like it
| |
| 1123 def Main(argv): | 1156 def Main(argv): |
| 1124 parser = optparse.OptionParser(usage="%prog [options]", | 1157 parser = optparse.OptionParser(usage="%prog [options] <files...>", |
| 1125 version="%prog " + str(__version__)) | 1158 version="%prog " + str(__version__)) |
| 1126 parser.add_option("-c", "--commit", action="store_true", default=False, | 1159 parser.add_option("-c", "--commit", action="store_true", default=False, |
| 1127 help="Use commit instead of upload checks") | 1160 help="Use commit instead of upload checks") |
| 1128 parser.add_option("-u", "--upload", action="store_false", dest='commit', | 1161 parser.add_option("-u", "--upload", action="store_false", dest='commit', |
| 1129 help="Use upload instead of commit checks") | 1162 help="Use upload instead of commit checks") |
| 1130 parser.add_option("-r", "--recursive", action="store_true", | 1163 parser.add_option("-r", "--recursive", action="store_true", |
| 1131 help="Act recursively") | 1164 help="Act recursively") |
| 1132 parser.add_option("-v", "--verbose", action="store_true", default=False, | 1165 parser.add_option("-v", "--verbose", action="store_true", default=False, |
| 1133 help="Verbose output") | 1166 help="Verbose output") |
| 1134 parser.add_option("--files") | |
| 1135 parser.add_option("--name", default='no name') | 1167 parser.add_option("--name", default='no name') |
| 1136 parser.add_option("--description", default='') | 1168 parser.add_option("--description", default='') |
| 1137 parser.add_option("--issue", type='int', default=0) | 1169 parser.add_option("--issue", type='int', default=0) |
| 1138 parser.add_option("--patchset", type='int', default=0) | 1170 parser.add_option("--patchset", type='int', default=0) |
| 1139 parser.add_option("--root", default=os.getcwd(), | 1171 parser.add_option("--root", default=os.getcwd(), |
| 1140 help="Search for PRESUBMIT.py up to this directory. " | 1172 help="Search for PRESUBMIT.py up to this directory. " |
| 1141 "If inherit-review-settings-ok is present in this " | 1173 "If inherit-review-settings-ok is present in this " |
| 1142 "directory, parent directories up to the root file " | 1174 "directory, parent directories up to the root file " |
| 1143 "system directories will also be searched.") | 1175 "system directories will also be searched.") |
| 1144 parser.add_option("--default_presubmit") | 1176 parser.add_option("--default_presubmit") |
| 1145 parser.add_option("--may_prompt", action='store_true', default=False) | 1177 parser.add_option("--may_prompt", action='store_true', default=False) |
| 1146 options, args = parser.parse_args(argv) | 1178 options, args = parser.parse_args(argv) |
| 1147 if options.verbose: | 1179 if options.verbose: |
| 1148 logging.basicConfig(level=logging.DEBUG) | 1180 logging.basicConfig(level=logging.DEBUG) |
| 1149 if os.path.isdir(os.path.join(options.root, '.svn')): | 1181 change_class, files = DetermineScm(options, args) |
| 1150 change_class = SvnChange | 1182 if not change_class: |
| 1151 if not options.files: | 1183 parser.error('For unversioned directory, <files> is not optional.') |
| 1152 if args: | |
| 1153 options.files = ParseFiles(args, options.recursive) | |
| 1154 else: | |
| 1155 # Grab modified files. | |
| 1156 options.files = scm.SVN.CaptureStatus([options.root]) | |
| 1157 else: | |
| 1158 is_git = os.path.isdir(os.path.join(options.root, '.git')) | |
| 1159 if not is_git: | |
| 1160 is_git = (0 == subprocess.call( | |
| 1161 ['git', 'rev-parse', '--show-cdup'], | |
| 1162 stdout=subprocess.PIPE, cwd=options.root)) | |
| 1163 if is_git: | |
| 1164 # Only look at the subdirectories below cwd. | |
| 1165 change_class = GitChange | |
| 1166 if not options.files: | |
| 1167 if args: | |
| 1168 options.files = ParseFiles(args, options.recursive) | |
| 1169 else: | |
| 1170 # Grab modified files. | |
| 1171 options.files = scm.GIT.CaptureStatus([options.root]) | |
| 1172 else: | |
| 1173 logging.info('Doesn\'t seem under source control.') | |
| 1174 change_class = Change | |
| 1175 if options.verbose: | 1184 if options.verbose: |
| 1176 if not options.files: | 1185 print "Found %d file(s)." % len(files) |
| 1177 print "Found no files." | |
| 1178 elif len(options.files) != 1: | |
| 1179 print "Found %d files." % len(options.files) | |
| 1180 else: | |
| 1181 print "Found 1 file." | |
| 1182 results = DoPresubmitChecks(change_class(options.name, | 1186 results = DoPresubmitChecks(change_class(options.name, |
| 1183 options.description, | 1187 options.description, |
| 1184 options.root, | 1188 options.root, |
| 1185 options.files, | 1189 files, |
| 1186 options.issue, | 1190 options.issue, |
| 1187 options.patchset), | 1191 options.patchset), |
| 1188 options.commit, | 1192 options.commit, |
| 1189 options.verbose, | 1193 options.verbose, |
| 1190 sys.stdout, | 1194 sys.stdout, |
| 1191 sys.stdin, | 1195 sys.stdin, |
| 1192 options.default_presubmit, | 1196 options.default_presubmit, |
| 1193 options.may_prompt) | 1197 options.may_prompt) |
| 1194 return not results.should_continue() | 1198 return not results.should_continue() |
| 1195 | 1199 |
| 1196 | 1200 |
| 1197 if __name__ == '__main__': | 1201 if __name__ == '__main__': |
| 1198 sys.exit(Main(None)) | 1202 sys.exit(Main(None)) |
| OLD | NEW |