Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(601)

Side by Side Diff: gcl.py

Issue 6667042: Revert both r78355 and r78329 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/gcl_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 """\ 6 """\
7 Wrapper script around Rietveld's upload.py that simplifies working with groups 7 Wrapper script around Rietveld's upload.py that simplifies working with groups
8 of files. 8 of files.
9 """ 9 """
10 10
(...skipping 21 matching lines...) Expand all
32 json.loads 32 json.loads
33 except (ImportError, AttributeError): 33 except (ImportError, AttributeError):
34 # Import the one included in depot_tools. 34 # Import the one included in depot_tools.
35 sys.path.append(os.path.join(os.path.dirname(__file__), 'third_party')) 35 sys.path.append(os.path.join(os.path.dirname(__file__), 'third_party'))
36 import simplejson as json # pylint: disable=F0401 36 import simplejson as json # pylint: disable=F0401
37 37
38 import breakpad # pylint: disable=W0611 38 import breakpad # pylint: disable=W0611
39 39
40 # gcl now depends on gclient. 40 # gcl now depends on gclient.
41 from scm import SVN 41 from scm import SVN
42
43 import gclient_utils 42 import gclient_utils
44 import owners
45 import presubmit_support
46 43
47 __version__ = '1.2' 44 __version__ = '1.2'
48 45
49 46
50 CODEREVIEW_SETTINGS = { 47 CODEREVIEW_SETTINGS = {
51 # To make gcl send reviews to a server, check in a file named 48 # To make gcl send reviews to a server, check in a file named
52 # "codereview.settings" (see |CODEREVIEW_SETTINGS_FILE| below) to your 49 # "codereview.settings" (see |CODEREVIEW_SETTINGS_FILE| below) to your
53 # project's base directory and add the following line to codereview.settings: 50 # project's base directory and add the following line to codereview.settings:
54 # CODE_REVIEW_SERVER: codereview.yourserver.org 51 # CODE_REVIEW_SERVER: codereview.yourserver.org
55 } 52 }
(...skipping 10 matching lines...) Expand all
66 # Warning message when the change appears to be missing tests. 63 # Warning message when the change appears to be missing tests.
67 MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!" 64 MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!"
68 65
69 # Global cache of files cached in GetCacheDir(). 66 # Global cache of files cached in GetCacheDir().
70 FILES_CACHE = {} 67 FILES_CACHE = {}
71 68
72 # Valid extensions for files we want to lint. 69 # Valid extensions for files we want to lint.
73 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)" 70 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)"
74 DEFAULT_LINT_IGNORE_REGEX = r"$^" 71 DEFAULT_LINT_IGNORE_REGEX = r"$^"
75 72
76 REVIEWERS_REGEX = r'\s*R=(.+)'
77 73
78 def CheckHomeForFile(filename): 74 def CheckHomeForFile(filename):
79 """Checks the users home dir for the existence of the given file. Returns 75 """Checks the users home dir for the existence of the given file. Returns
80 the path to the file if it's there, or None if it is not. 76 the path to the file if it's there, or None if it is not.
81 """ 77 """
82 home_vars = ['HOME'] 78 home_vars = ['HOME']
83 if sys.platform in ('cygwin', 'win32'): 79 if sys.platform in ('cygwin', 'win32'):
84 home_vars.append('USERPROFILE') 80 home_vars.append('USERPROFILE')
85 for home_var in home_vars: 81 for home_var in home_vars:
86 home = os.getenv(home_var) 82 home = os.getenv(home_var)
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 rietveld: rietveld server for this change 279 rietveld: rietveld server for this change
284 """ 280 """
285 # Kept for unit test support. This is for the old format, it's deprecated. 281 # Kept for unit test support. This is for the old format, it's deprecated.
286 _SEPARATOR = "\n-----\n" 282 _SEPARATOR = "\n-----\n"
287 283
288 def __init__(self, name, issue, patchset, description, files, local_root, 284 def __init__(self, name, issue, patchset, description, files, local_root,
289 rietveld, needs_upload=False): 285 rietveld, needs_upload=False):
290 self.name = name 286 self.name = name
291 self.issue = int(issue) 287 self.issue = int(issue)
292 self.patchset = int(patchset) 288 self.patchset = int(patchset)
293 self._description = None 289 self.description = description
294 self._subject = None
295 self._reviewers = None
296 self._set_description(description)
297 if files is None: 290 if files is None:
298 files = [] 291 files = []
299 self._files = files 292 self._files = files
300 self.patch = None 293 self.patch = None
301 self._local_root = local_root 294 self._local_root = local_root
302 self.needs_upload = needs_upload 295 self.needs_upload = needs_upload
303 self.rietveld = rietveld 296 self.rietveld = rietveld
304 if not self.rietveld: 297 if not self.rietveld:
305 # Set the default value. 298 # Set the default value.
306 self.rietveld = GetCodeReviewSetting('CODE_REVIEW_SERVER') 299 self.rietveld = GetCodeReviewSetting('CODE_REVIEW_SERVER')
307 300
308 def _get_description(self):
309 return self._description
310
311 def _set_description(self, description):
312 # TODO(dpranke): Cloned from git_cl.py. These should be shared.
313 if not description:
314 self._description = description
315 return
316
317 parsed_lines = []
318 reviewers_re = re.compile(REVIEWERS_REGEX)
319 reviewers = ''
320 subject = ''
321 for l in description.splitlines():
322 if not subject:
323 subject = l
324 matched_reviewers = reviewers_re.match(l)
325 if matched_reviewers:
326 reviewers = matched_reviewers.group(1)
327 parsed_lines.append(l)
328
329 if len(subject) > 100:
330 subject = subject[:97] + '...'
331
332 self._subject = subject
333 self._reviewers = reviewers
334 self._description = '\n'.join(parsed_lines)
335
336 description = property(_get_description, _set_description)
337
338 @property
339 def reviewers(self):
340 return self._reviewers
341
342 @property
343 def subject(self):
344 return self._subject
345
346 def NeedsUpload(self): 301 def NeedsUpload(self):
347 return self.needs_upload 302 return self.needs_upload
348 303
349 def GetFileNames(self): 304 def GetFileNames(self):
350 """Returns the list of file names included in this change.""" 305 """Returns the list of file names included in this change."""
351 return [f[1] for f in self._files] 306 return [f[1] for f in self._files]
352 307
353 def GetFiles(self): 308 def GetFiles(self):
354 """Returns the list of files included in this change with their status.""" 309 """Returns the list of files included in this change with their status."""
355 return self._files 310 return self._files
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after
752 707
753 return editor 708 return editor
754 709
755 710
756 def GenerateDiff(files, root=None): 711 def GenerateDiff(files, root=None):
757 return SVN.GenerateDiff(files, root=root) 712 return SVN.GenerateDiff(files, root=root)
758 713
759 714
760 def OptionallyDoPresubmitChecks(change_info, committing, args): 715 def OptionallyDoPresubmitChecks(change_info, committing, args):
761 if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"): 716 if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"):
762 return presubmit_support.PresubmitOutput() 717 return True
763 return DoPresubmitChecks(change_info, committing, True) 718 return DoPresubmitChecks(change_info, committing, True)
764 719
765 720
766 def suggest_reviewers(change_info, affected_files):
767 owners_db = owners.Database(change_info.GetLocalRoot(), fopen=file,
768 os_path=os.path)
769 return owners_db.reviewers_for(affected_files)
770
771
772 def defer_attributes(a, b): 721 def defer_attributes(a, b):
773 """Copy attributes from an object (like a function) to another.""" 722 """Copy attributes from an object (like a function) to another."""
774 for x in dir(a): 723 for x in dir(a):
775 if not getattr(b, x, None): 724 if not getattr(b, x, None):
776 setattr(b, x, getattr(a, x)) 725 setattr(b, x, getattr(a, x))
777 726
778 727
779 def need_change(function): 728 def need_change(function):
780 """Converts args -> change_info.""" 729 """Converts args -> change_info."""
781 # pylint: disable=W0612,W0621 730 # pylint: disable=W0612,W0621
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
841 def CMDupload(change_info, args): 790 def CMDupload(change_info, args):
842 """Uploads the changelist to the server for review. 791 """Uploads the changelist to the server for review.
843 792
844 This does not submit a try job; use gcl try to submit a try job. 793 This does not submit a try job; use gcl try to submit a try job.
845 """ 794 """
846 if '-s' in args or '--server' in args: 795 if '-s' in args or '--server' in args:
847 ErrorExit('Don\'t use the -s flag, fix codereview.settings instead') 796 ErrorExit('Don\'t use the -s flag, fix codereview.settings instead')
848 if not change_info.GetFiles(): 797 if not change_info.GetFiles():
849 print "Nothing to upload, changelist is empty." 798 print "Nothing to upload, changelist is empty."
850 return 0 799 return 0
851 800 if not OptionallyDoPresubmitChecks(change_info, False, args):
852 output = OptionallyDoPresubmitChecks(change_info, False, args)
853 if not output.should_continue():
854 return 1 801 return 1
855 no_watchlists = (FilterFlag(args, "--no_watchlists") or 802 no_watchlists = (FilterFlag(args, "--no_watchlists") or
856 FilterFlag(args, "--no-watchlists")) 803 FilterFlag(args, "--no-watchlists"))
857 804
858 # Map --send-mail to --send_mail 805 # Map --send-mail to --send_mail
859 if FilterFlag(args, "--send-mail"): 806 if FilterFlag(args, "--send-mail"):
860 args.append("--send_mail") 807 args.append("--send_mail")
861 808
862 upload_arg = ["upload.py", "-y"] 809 upload_arg = ["upload.py", "-y"]
863 upload_arg.append("--server=%s" % change_info.rietveld) 810 upload_arg.append("--server=%s" % change_info.rietveld)
864
865 reviewers = change_info.reviewers or output.reviewers
866 if (reviewers and
867 not any(arg.startswith('-r') or arg.startswith('--reviewer') for
868 arg in args)):
869 upload_arg.append('--reviewers=%s' % ','.join(reviewers))
870
871 upload_arg.extend(args) 811 upload_arg.extend(args)
872 812
873 desc_file = "" 813 desc_file = ""
874 if change_info.issue: # Uploading a new patchset. 814 if change_info.issue: # Uploading a new patchset.
875 found_message = False 815 found_message = False
876 for arg in args: 816 for arg in args:
877 if arg.startswith("--message") or arg.startswith("-m"): 817 if arg.startswith("--message") or arg.startswith("-m"):
878 found_message = True 818 found_message = True
879 break 819 break
880 820
(...skipping 13 matching lines...) Expand all
894 watchlist = watchlists.Watchlists(change_info.GetLocalRoot()) 834 watchlist = watchlists.Watchlists(change_info.GetLocalRoot())
895 watchers = watchlist.GetWatchersForPaths(change_info.GetFileNames()) 835 watchers = watchlist.GetWatchersForPaths(change_info.GetFileNames())
896 836
897 cc_list = GetCodeReviewSetting("CC_LIST") 837 cc_list = GetCodeReviewSetting("CC_LIST")
898 if not no_watchlists and watchers: 838 if not no_watchlists and watchers:
899 # Filter out all empty elements and join by ',' 839 # Filter out all empty elements and join by ','
900 cc_list = ','.join(filter(None, [cc_list] + watchers)) 840 cc_list = ','.join(filter(None, [cc_list] + watchers))
901 if cc_list: 841 if cc_list:
902 upload_arg.append("--cc=" + cc_list) 842 upload_arg.append("--cc=" + cc_list)
903 upload_arg.append("--description_file=" + desc_file + "") 843 upload_arg.append("--description_file=" + desc_file + "")
904 if change_info.subject: 844 if change_info.description:
905 upload_arg.append("--message=" + change_info.subject) 845 subject = change_info.description[:77]
846 if subject.find("\r\n") != -1:
847 subject = subject[:subject.find("\r\n")]
848 if subject.find("\n") != -1:
849 subject = subject[:subject.find("\n")]
850 if len(change_info.description) > 77:
851 subject = subject + "..."
852 upload_arg.append("--message=" + subject)
906 853
907 if GetCodeReviewSetting("PRIVATE") == "True": 854 if GetCodeReviewSetting("PRIVATE") == "True":
908 upload_arg.append("--private") 855 upload_arg.append("--private")
909 856
910 # Change the current working directory before calling upload.py so that it 857 # Change the current working directory before calling upload.py so that it
911 # shows the correct base. 858 # shows the correct base.
912 previous_cwd = os.getcwd() 859 previous_cwd = os.getcwd()
913 os.chdir(change_info.GetLocalRoot()) 860 os.chdir(change_info.GetLocalRoot())
914 # If we have a lot of files with long paths, then we won't be able to fit 861 # If we have a lot of files with long paths, then we won't be able to fit
915 # the command to "svn diff". Instead, we generate the diff manually for 862 # the command to "svn diff". Instead, we generate the diff manually for
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
1027 output = RunShell(commit_cmd, True) 974 output = RunShell(commit_cmd, True)
1028 os.remove(commit_filename) 975 os.remove(commit_filename)
1029 os.remove(targets_filename) 976 os.remove(targets_filename)
1030 if output.find("Committed revision") != -1: 977 if output.find("Committed revision") != -1:
1031 change_info.Delete() 978 change_info.Delete()
1032 979
1033 if change_info.issue: 980 if change_info.issue:
1034 revision = re.compile(".*?\nCommitted revision (\d+)", 981 revision = re.compile(".*?\nCommitted revision (\d+)",
1035 re.DOTALL).match(output).group(1) 982 re.DOTALL).match(output).group(1)
1036 viewvc_url = GetCodeReviewSetting("VIEW_VC") 983 viewvc_url = GetCodeReviewSetting("VIEW_VC")
1037 change_info.description += '\n' 984 change_info.description = change_info.description + '\n'
1038 if viewvc_url: 985 if viewvc_url:
1039 change_info.description += "\nCommitted: " + viewvc_url + revision 986 change_info.description += "\nCommitted: " + viewvc_url + revision
1040 change_info.CloseIssue() 987 change_info.CloseIssue()
1041 os.chdir(previous_cwd) 988 os.chdir(previous_cwd)
1042 return 0 989 return 0
1043 990
1044 991
1045 def CMDchange(args): 992 def CMDchange(args):
1046 """Creates or edits a changelist. 993 """Creates or edits a changelist.
1047 994
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1089 description = change_info.description 1036 description = change_info.description
1090 1037
1091 other_files = GetFilesNotInCL() 1038 other_files = GetFilesNotInCL()
1092 1039
1093 # Edited files (as opposed to files with only changed properties) will have 1040 # Edited files (as opposed to files with only changed properties) will have
1094 # a letter for the first character in the status string. 1041 # a letter for the first character in the status string.
1095 file_re = re.compile(r"^[a-z].+\Z", re.IGNORECASE) 1042 file_re = re.compile(r"^[a-z].+\Z", re.IGNORECASE)
1096 affected_files = [x for x in other_files if file_re.match(x[0])] 1043 affected_files = [x for x in other_files if file_re.match(x[0])]
1097 unaffected_files = [x for x in other_files if not file_re.match(x[0])] 1044 unaffected_files = [x for x in other_files if not file_re.match(x[0])]
1098 1045
1099 suggested_reviewers = suggest_reviewers(change_info, affected_files)
1100 if suggested_reviewers:
1101 reviewers_re = re.compile(REVIEWERS_REGEX)
1102 if not any(
1103 reviewers_re.match(l) for l in description.splitlines()):
1104 description += '\nR=' + ','.join(suggested_reviewers) + '\n'
1105
1106 separator1 = ("\n---All lines above this line become the description.\n" 1046 separator1 = ("\n---All lines above this line become the description.\n"
1107 "---Repository Root: " + change_info.GetLocalRoot() + "\n" 1047 "---Repository Root: " + change_info.GetLocalRoot() + "\n"
1108 "---Paths in this changelist (" + change_info.name + "):\n") 1048 "---Paths in this changelist (" + change_info.name + "):\n")
1109 separator2 = "\n\n---Paths modified but not in any changelist:\n\n" 1049 separator2 = "\n\n---Paths modified but not in any changelist:\n\n"
1110 text = (description + separator1 + '\n' + 1050 text = (description + separator1 + '\n' +
1111 '\n'.join([f[0] + f[1] for f in change_info.GetFiles()])) 1051 '\n'.join([f[0] + f[1] for f in change_info.GetFiles()]))
1112 1052
1113 if change_info.Exists(): 1053 if change_info.Exists():
1114 text += (separator2 + 1054 text += (separator2 +
1115 '\n'.join([f[0] + f[1] for f in affected_files]) + '\n') 1055 '\n'.join([f[0] + f[1] for f in affected_files]) + '\n')
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1217 else: 1157 else:
1218 print "Skipping file %s" % filename 1158 print "Skipping file %s" % filename
1219 1159
1220 print "Total errors found: %d\n" % cpplint._cpplint_state.error_count 1160 print "Total errors found: %d\n" % cpplint._cpplint_state.error_count
1221 os.chdir(previous_cwd) 1161 os.chdir(previous_cwd)
1222 return 1 1162 return 1
1223 1163
1224 1164
1225 def DoPresubmitChecks(change_info, committing, may_prompt): 1165 def DoPresubmitChecks(change_info, committing, may_prompt):
1226 """Imports presubmit, then calls presubmit.DoPresubmitChecks.""" 1166 """Imports presubmit, then calls presubmit.DoPresubmitChecks."""
1167 # Need to import here to avoid circular dependency.
1168 import presubmit_support
1227 root_presubmit = GetCachedFile('PRESUBMIT.py', use_root=True) 1169 root_presubmit = GetCachedFile('PRESUBMIT.py', use_root=True)
1228 change = presubmit_support.SvnChange(change_info.name, 1170 change = presubmit_support.SvnChange(change_info.name,
1229 change_info.description, 1171 change_info.description,
1230 change_info.GetLocalRoot(), 1172 change_info.GetLocalRoot(),
1231 change_info.GetFiles(), 1173 change_info.GetFiles(),
1232 change_info.issue, 1174 change_info.issue,
1233 change_info.patchset) 1175 change_info.patchset)
1234 output = presubmit_support.DoPresubmitChecks(change=change, 1176 output = presubmit_support.DoPresubmitChecks(change=change,
1235 committing=committing, 1177 committing=committing,
1236 verbose=False, 1178 verbose=False,
1237 output_stream=sys.stdout, 1179 output_stream=sys.stdout,
1238 input_stream=sys.stdin, 1180 input_stream=sys.stdin,
1239 default_presubmit=root_presubmit, 1181 default_presubmit=root_presubmit,
1240 may_prompt=may_prompt, 1182 may_prompt=may_prompt)
1241 tbr=False,
1242 host_url=change_info.rietveld)
1243 if not output.should_continue() and may_prompt: 1183 if not output.should_continue() and may_prompt:
1244 # TODO(dpranke): move into DoPresubmitChecks(), unify cmd line args. 1184 # TODO(dpranke): move into DoPresubmitChecks(), unify cmd line args.
1245 print "\nPresubmit errors, can't continue (use --no_presubmit to bypass)" 1185 print "\nPresubmit errors, can't continue (use --no_presubmit to bypass)"
1246 1186
1247 return output 1187 # TODO(dpranke): Return the output object and make use of it.
1188 return output.should_continue()
1248 1189
1249 1190
1250 @no_args 1191 @no_args
1251 def CMDchanges(): 1192 def CMDchanges():
1252 """Lists all the changelists and their files.""" 1193 """Lists all the changelists and their files."""
1253 for cl in GetCLs(): 1194 for cl in GetCLs():
1254 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) 1195 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True)
1255 print "\n--- Changelist " + change_info.name + ":" 1196 print "\n--- Changelist " + change_info.name + ":"
1256 for filename in change_info.GetFiles(): 1197 for filename in change_info.GetFiles():
1257 print "".join(filename) 1198 print "".join(filename)
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
1461 if e.code != 500: 1402 if e.code != 500:
1462 raise 1403 raise
1463 print >> sys.stderr, ( 1404 print >> sys.stderr, (
1464 'AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' 1405 'AppEngine is misbehaving and returned HTTP %d, again. Keep faith '
1465 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e)) 1406 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))
1466 return 1 1407 return 1
1467 1408
1468 1409
1469 if __name__ == "__main__": 1410 if __name__ == "__main__":
1470 sys.exit(main(sys.argv[1:])) 1411 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | tests/gcl_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698