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

Side by Side Diff: gcl.py

Issue 6719004: refactor parsing of change descriptions, fix TBR= (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: rebase to head, fix bugs 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 | gclient_utils.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 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 rietveld: rietveld server for this change 283 rietveld: rietveld server for this change
284 """ 284 """
285 # Kept for unit test support. This is for the old format, it's deprecated. 285 # Kept for unit test support. This is for the old format, it's deprecated.
286 _SEPARATOR = "\n-----\n" 286 _SEPARATOR = "\n-----\n"
287 287
288 def __init__(self, name, issue, patchset, description, files, local_root, 288 def __init__(self, name, issue, patchset, description, files, local_root,
289 rietveld, needs_upload=False): 289 rietveld, needs_upload=False):
290 self.name = name 290 self.name = name
291 self.issue = int(issue) 291 self.issue = int(issue)
292 self.patchset = int(patchset) 292 self.patchset = int(patchset)
293 self._description = None 293 self._change_desc = None
294 self._subject = None
295 self._reviewers = None
296 self._set_description(description) 294 self._set_description(description)
297 if files is None: 295 if files is None:
298 files = [] 296 files = []
299 self._files = files 297 self._files = files
300 self.patch = None 298 self.patch = None
301 self._local_root = local_root 299 self._local_root = local_root
302 self.needs_upload = needs_upload 300 self.needs_upload = needs_upload
303 self.rietveld = rietveld 301 self.rietveld = rietveld
304 if not self.rietveld: 302 if not self.rietveld:
305 # Set the default value. 303 # Set the default value.
306 self.rietveld = GetCodeReviewSetting('CODE_REVIEW_SERVER') 304 self.rietveld = GetCodeReviewSetting('CODE_REVIEW_SERVER')
307 305
308 def _get_description(self): 306 def _get_description(self):
309 return self._description 307 return self._change_desc.description
310 308
311 def _set_description(self, description): 309 def _set_description(self, description):
312 # TODO(dpranke): Cloned from git_cl.py. These should be shared. 310 self._change_desc = presubmit_support.ChangeDescription(
313 if not description: 311 description=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).split(',')
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 312
336 description = property(_get_description, _set_description) 313 description = property(_get_description, _set_description)
337 314
338 @property 315 @property
339 def reviewers(self): 316 def reviewers(self):
340 return self._reviewers 317 return self._change_desc.reviewers
341 318
342 @property 319 @property
343 def subject(self): 320 def subject(self):
344 return self._subject 321 return self._change_desc.subject
345 322
346 def NeedsUpload(self): 323 def NeedsUpload(self):
347 return self.needs_upload 324 return self.needs_upload
348 325
349 def GetFileNames(self): 326 def GetFileNames(self):
350 """Returns the list of file names included in this change.""" 327 """Returns the list of file names included in this change."""
351 return [f[1] for f in self._files] 328 return [f[1] for f in self._files]
352 329
353 def GetFiles(self): 330 def GetFiles(self):
354 """Returns the list of files included in this change with their status.""" 331 """Returns the list of files included in this change with their status."""
(...skipping 16 matching lines...) Expand all
371 """Returns a list of files added in this change.""" 348 """Returns a list of files added in this change."""
372 return [f[1] for f in self.GetFiles() if f[0].startswith("A")] 349 return [f[1] for f in self.GetFiles() if f[0].startswith("A")]
373 350
374 def Save(self): 351 def Save(self):
375 """Writes the changelist information to disk.""" 352 """Writes the changelist information to disk."""
376 data = json.dumps({ 353 data = json.dumps({
377 'issue': self.issue, 354 'issue': self.issue,
378 'patchset': self.patchset, 355 'patchset': self.patchset,
379 'needs_upload': self.NeedsUpload(), 356 'needs_upload': self.NeedsUpload(),
380 'files': self.GetFiles(), 357 'files': self.GetFiles(),
381 'description': self.description, 358 'description': self._change_desc.description,
382 'rietveld': self.rietveld, 359 'rietveld': self.rietveld,
383 }, sort_keys=True, indent=2) 360 }, sort_keys=True, indent=2)
384 gclient_utils.FileWrite(GetChangelistInfoFile(self.name), data) 361 gclient_utils.FileWrite(GetChangelistInfoFile(self.name), data)
385 362
386 def Delete(self): 363 def Delete(self):
387 """Removes the changelist information from disk.""" 364 """Removes the changelist information from disk."""
388 os.remove(GetChangelistInfoFile(self.name)) 365 os.remove(GetChangelistInfoFile(self.name))
389 366
390 def CloseIssue(self): 367 def CloseIssue(self):
391 """Closes the Rietveld issue for this changelist.""" 368 """Closes the Rietveld issue for this changelist."""
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after
732 if (files.get('') or (show_unknown_files and len(unknown_files))): 709 if (files.get('') or (show_unknown_files and len(unknown_files))):
733 print "\n--- Not in any changelist:" 710 print "\n--- Not in any changelist:"
734 for item in files.get('', []): 711 for item in files.get('', []):
735 print "".join(item) 712 print "".join(item)
736 if show_unknown_files: 713 if show_unknown_files:
737 for filename in unknown_files: 714 for filename in unknown_files:
738 print "? %s" % filename 715 print "? %s" % filename
739 return 0 716 return 0
740 717
741 718
742 def GetEditor():
743 editor = os.environ.get("SVN_EDITOR")
744 if not editor:
745 editor = os.environ.get("EDITOR")
746
747 if not editor:
748 if sys.platform.startswith("win"):
749 editor = "notepad"
750 else:
751 editor = "vi"
752
753 return editor
754
755
756 def GenerateDiff(files, root=None): 719 def GenerateDiff(files, root=None):
757 return SVN.GenerateDiff(files, root=root) 720 return SVN.GenerateDiff(files, root=root)
758 721
759 722
760 def OptionallyDoPresubmitChecks(change_info, committing, args): 723 def OptionallyDoPresubmitChecks(change_info, committing, args):
761 if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"): 724 if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"):
762 return presubmit_support.PresubmitOutput() 725 return presubmit_support.PresubmitOutput()
763 return DoPresubmitChecks(change_info, committing, True) 726 return DoPresubmitChecks(change_info, committing, True)
764 727
765 728
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
1086 1049
1087 other_files = GetFilesNotInCL() 1050 other_files = GetFilesNotInCL()
1088 1051
1089 # Edited files (as opposed to files with only changed properties) will have 1052 # Edited files (as opposed to files with only changed properties) will have
1090 # a letter for the first character in the status string. 1053 # a letter for the first character in the status string.
1091 file_re = re.compile(r"^[a-z].+\Z", re.IGNORECASE) 1054 file_re = re.compile(r"^[a-z].+\Z", re.IGNORECASE)
1092 affected_files = [x for x in other_files if file_re.match(x[0])] 1055 affected_files = [x for x in other_files if file_re.match(x[0])]
1093 unaffected_files = [x for x in other_files if not file_re.match(x[0])] 1056 unaffected_files = [x for x in other_files if not file_re.match(x[0])]
1094 1057
1095 description = description.rstrip() + '\n' 1058 description = description.rstrip() + '\n'
1059 reviewers = change_info.reviewers
1096 1060
1097 separator1 = ("\n---All lines above this line become the description.\n" 1061 separator1 = ("\n---All lines above this line become the description.\n"
1098 "---Repository Root: " + change_info.GetLocalRoot() + "\n" 1062 "---Repository Root: " + change_info.GetLocalRoot() + "\n"
1099 "---Paths in this changelist (" + change_info.name + "):\n") 1063 "---Paths in this changelist (" + change_info.name + "):\n")
1100 separator2 = "\n\n---Paths modified but not in any changelist:\n\n" 1064 separator2 = "\n\n---Paths modified but not in any changelist:\n\n"
1101 text = (description + separator1 + '\n' + 1065
1102 '\n'.join([f[0] + f[1] for f in change_info.GetFiles()])) 1066 footer = (separator1 + '\n' +
1067 '\n'.join([f[0] + f[1] for f in change_info.GetFiles()]))
1103 1068
1104 if change_info.Exists(): 1069 if change_info.Exists():
1105 text += (separator2 + 1070 footer += (separator2 +
1106 '\n'.join([f[0] + f[1] for f in affected_files]) + '\n') 1071 '\n'.join([f[0] + f[1] for f in affected_files]) + '\n')
1107 else: 1072 else:
1108 text += ('\n'.join([f[0] + f[1] for f in affected_files]) + '\n' + 1073 footer += ('\n'.join([f[0] + f[1] for f in affected_files]) + '\n' +
1109 separator2) 1074 separator2)
1110 text += '\n'.join([f[0] + f[1] for f in unaffected_files]) + '\n' 1075 footer += '\n'.join([f[0] + f[1] for f in unaffected_files]) + '\n'
1111 1076
1112 handle, filename = tempfile.mkstemp(text=True) 1077 change_desc = presubmit_support.ChangeDescription(description=description,
1113 os.write(handle, text) 1078 reviewers=reviewers)
1114 os.close(handle)
1115 1079
1116 # Open up the default editor in the system to get the CL description. 1080 # These next few lines are equivalent to change_desc.UserUpdate(). We
1117 try: 1081 # call them individually to avoid passing a lot of state back and forth.
1118 if not silent: 1082 original_description = change_desc.description
1119 cmd = '%s %s' % (GetEditor(), filename) 1083
1120 if sys.platform == 'win32' and os.environ.get('TERM') == 'msys': 1084 result = change_desc.EditableDescription() + footer
1121 # Msysgit requires the usage of 'env' to be present. 1085 if not silent:
1122 cmd = 'env ' + cmd 1086 result = change_desc.editor(result)
1123 # shell=True to allow the shell to handle all forms of quotes in $EDITOR.
1124 subprocess.check_call(cmd, shell=True)
1125 result = gclient_utils.FileRead(filename, 'r')
1126 finally:
1127 os.remove(filename)
1128 1087
1129 if not result: 1088 if not result:
1130 return 0 1089 return 0
1131 1090
1132 split_result = result.split(separator1, 1) 1091 split_result = result.split(separator1, 1)
1133 if len(split_result) != 2: 1092 if len(split_result) != 2:
1134 ErrorExit("Don't modify the text starting with ---!\n\n" + result) 1093 ErrorExit("Don't modify the text starting with ---!\n\n" + result)
1135 1094
1136 # Update the CL description if it has changed. 1095 # Update the CL description if it has changed.
1137 new_description = split_result[0] 1096 new_description = split_result[0]
1138 cl_files_text = split_result[1] 1097 cl_files_text = split_result[1]
1139 if new_description != description or override_description: 1098 change_desc.Parse(new_description)
1140 change_info.description = new_description 1099 if change_desc.description != original_description or override_description:
1141 change_info.needs_upload = True 1100 change_info.needs_upload = True
1142 1101
1143 new_cl_files = [] 1102 new_cl_files = []
1144 for line in cl_files_text.splitlines(): 1103 for line in cl_files_text.splitlines():
1145 if not len(line): 1104 if not len(line):
1146 continue 1105 continue
1147 if line.startswith("---"): 1106 if line.startswith("---"):
1148 break 1107 break
1149 status = line[:7] 1108 status = line[:7]
1150 filename = line[7:] 1109 filename = line[7:]
1151 new_cl_files.append((status, filename)) 1110 new_cl_files.append((status, filename))
1152 1111
1153 if (not len(change_info.GetFiles()) and not change_info.issue and 1112 if (not len(change_info.GetFiles()) and not change_info.issue and
1154 not len(new_description) and not new_cl_files): 1113 not len(change_desc.description) and not new_cl_files):
1155 ErrorExit("Empty changelist not saved") 1114 ErrorExit("Empty changelist not saved")
1156 1115
1157 change_info._files = new_cl_files 1116 change_info._files = new_cl_files
1158 change_info.Save() 1117 change_info.Save()
1159 if svn_info.get('URL', '').startswith('http:'): 1118 if svn_info.get('URL', '').startswith('http:'):
1160 Warn("WARNING: Creating CL in a read-only checkout. You will not be " 1119 Warn("WARNING: Creating CL in a read-only checkout. You will not be "
1161 "able to commit it!") 1120 "able to commit it!")
1162 1121
1163 print change_info.name + " changelist saved." 1122 print change_info.name + " changelist saved."
1164 if change_info.MissingTests(): 1123 if change_info.MissingTests():
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
1453 raise 1412 raise
1454 print >> sys.stderr, ( 1413 print >> sys.stderr, (
1455 'AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' 1414 'AppEngine is misbehaving and returned HTTP %d, again. Keep faith '
1456 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e)) 1415 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))
1457 return 1 1416 return 1
1458 1417
1459 1418
1460 if __name__ == "__main__": 1419 if __name__ == "__main__":
1461 fix_encoding.fix_encoding() 1420 fix_encoding.fix_encoding()
1462 sys.exit(main(sys.argv[1:])) 1421 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | gclient_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698