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 load_files(options, args): | |
1127 """Tries to determine the SCM.""" | |
1128 change_scm = scm.determine_scm(options.root) | |
Dirk Pranke
2011/03/18 16:16:04
At some point it seems like it might be better to
| |
1129 files = [] | |
1130 if change_scm == 'svn': | |
1131 change_class = SvnChange | |
1132 status_fn = scm.SVN.CaptureStatus | |
1133 elif change_scm == 'git': | |
1134 change_class = GitChange | |
1135 status_fn = scm.GIT.CaptureStatus | |
1136 else: | |
1137 logging.info('Doesn\'t seem under source control. Got %d files' % len(args)) | |
1138 if not args: | |
1139 return None, None | |
1140 change_class = Change | |
1141 if args: | |
1142 files = ParseFiles(args, options.recursive) | |
1143 else: | |
1144 # Grab modified files. | |
1145 files = status_fn([options.root]) | |
1146 return change_class, files | |
1147 | |
1148 | |
1123 def Main(argv): | 1149 def Main(argv): |
1124 parser = optparse.OptionParser(usage="%prog [options]", | 1150 parser = optparse.OptionParser(usage="%prog [options] <files...>", |
1125 version="%prog " + str(__version__)) | 1151 version="%prog " + str(__version__)) |
1126 parser.add_option("-c", "--commit", action="store_true", default=False, | 1152 parser.add_option("-c", "--commit", action="store_true", default=False, |
1127 help="Use commit instead of upload checks") | 1153 help="Use commit instead of upload checks") |
1128 parser.add_option("-u", "--upload", action="store_false", dest='commit', | 1154 parser.add_option("-u", "--upload", action="store_false", dest='commit', |
1129 help="Use upload instead of commit checks") | 1155 help="Use upload instead of commit checks") |
1130 parser.add_option("-r", "--recursive", action="store_true", | 1156 parser.add_option("-r", "--recursive", action="store_true", |
1131 help="Act recursively") | 1157 help="Act recursively") |
1132 parser.add_option("-v", "--verbose", action="store_true", default=False, | 1158 parser.add_option("-v", "--verbose", action="store_true", default=False, |
1133 help="Verbose output") | 1159 help="Verbose output") |
1134 parser.add_option("--files") | |
1135 parser.add_option("--name", default='no name') | 1160 parser.add_option("--name", default='no name') |
1136 parser.add_option("--description", default='') | 1161 parser.add_option("--description", default='') |
1137 parser.add_option("--issue", type='int', default=0) | 1162 parser.add_option("--issue", type='int', default=0) |
1138 parser.add_option("--patchset", type='int', default=0) | 1163 parser.add_option("--patchset", type='int', default=0) |
1139 parser.add_option("--root", default=os.getcwd(), | 1164 parser.add_option("--root", default=os.getcwd(), |
1140 help="Search for PRESUBMIT.py up to this directory. " | 1165 help="Search for PRESUBMIT.py up to this directory. " |
1141 "If inherit-review-settings-ok is present in this " | 1166 "If inherit-review-settings-ok is present in this " |
1142 "directory, parent directories up to the root file " | 1167 "directory, parent directories up to the root file " |
1143 "system directories will also be searched.") | 1168 "system directories will also be searched.") |
1144 parser.add_option("--default_presubmit") | 1169 parser.add_option("--default_presubmit") |
1145 parser.add_option("--may_prompt", action='store_true', default=False) | 1170 parser.add_option("--may_prompt", action='store_true', default=False) |
1146 options, args = parser.parse_args(argv) | 1171 options, args = parser.parse_args(argv) |
1147 if options.verbose: | 1172 if options.verbose: |
1148 logging.basicConfig(level=logging.DEBUG) | 1173 logging.basicConfig(level=logging.DEBUG) |
1149 if os.path.isdir(os.path.join(options.root, '.svn')): | 1174 change_class, files = load_files(options, args) |
1150 change_class = SvnChange | 1175 if not change_class: |
1151 if not options.files: | 1176 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: | 1177 if options.verbose: |
1176 if not options.files: | 1178 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, | 1179 results = DoPresubmitChecks(change_class(options.name, |
1183 options.description, | 1180 options.description, |
1184 options.root, | 1181 options.root, |
1185 options.files, | 1182 files, |
1186 options.issue, | 1183 options.issue, |
1187 options.patchset), | 1184 options.patchset), |
1188 options.commit, | 1185 options.commit, |
1189 options.verbose, | 1186 options.verbose, |
1190 sys.stdout, | 1187 sys.stdout, |
1191 sys.stdin, | 1188 sys.stdin, |
1192 options.default_presubmit, | 1189 options.default_presubmit, |
1193 options.may_prompt) | 1190 options.may_prompt) |
1194 return not results.should_continue() | 1191 return not results.should_continue() |
1195 | 1192 |
1196 | 1193 |
1197 if __name__ == '__main__': | 1194 if __name__ == '__main__': |
1198 sys.exit(Main(None)) | 1195 sys.exit(Main(None)) |
OLD | NEW |