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

Side by Side Diff: git_cl.py

Issue 19552004: Improve description layout. Improve coloring and add legend in help. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: cleaner Created 7 years, 5 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 | « gclient.py ('k') | tests/gclient_test.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/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 # Copyright (C) 2008 Evan Martin <martine@danga.com> 6 # Copyright (C) 2008 Evan Martin <martine@danga.com>
7 7
8 """A git-command for integrating reviews on Rietveld.""" 8 """A git-command for integrating reviews on Rietveld."""
9 9
10 import difflib 10 import difflib
(...skipping 1015 matching lines...) Expand 10 before | Expand all | Expand 10 after
1026 urlretrieve(src, dst) 1026 urlretrieve(src, dst)
1027 os.chmod(dst, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) 1027 os.chmod(dst, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
1028 except Exception: 1028 except Exception:
1029 if os.path.exists(dst): 1029 if os.path.exists(dst):
1030 os.remove(dst) 1030 os.remove(dst)
1031 DieWithError('\nFailed to download hooks from %s' % src) 1031 DieWithError('\nFailed to download hooks from %s' % src)
1032 1032
1033 1033
1034 @usage('[repo root containing codereview.settings]') 1034 @usage('[repo root containing codereview.settings]')
1035 def CMDconfig(parser, args): 1035 def CMDconfig(parser, args):
1036 """edit configuration for this tree""" 1036 """Edits configuration for this tree."""
1037 1037
1038 _, args = parser.parse_args(args) 1038 _, args = parser.parse_args(args)
1039 if len(args) == 0: 1039 if len(args) == 0:
1040 GetCodereviewSettingsInteractively() 1040 GetCodereviewSettingsInteractively()
1041 DownloadHooks(True) 1041 DownloadHooks(True)
1042 return 0 1042 return 0
1043 1043
1044 url = args[0] 1044 url = args[0]
1045 if not url.endswith('codereview.settings'): 1045 if not url.endswith('codereview.settings'):
1046 url = os.path.join(url, 'codereview.settings') 1046 url = os.path.join(url, 'codereview.settings')
1047 1047
1048 # Load code review settings and download hooks (if available). 1048 # Load code review settings and download hooks (if available).
1049 LoadCodereviewSettingsFromFile(urllib2.urlopen(url)) 1049 LoadCodereviewSettingsFromFile(urllib2.urlopen(url))
1050 DownloadHooks(True) 1050 DownloadHooks(True)
1051 return 0 1051 return 0
1052 1052
1053 1053
1054 def CMDbaseurl(parser, args): 1054 def CMDbaseurl(parser, args):
1055 """get or set base-url for this branch""" 1055 """Gets or sets base-url for this branch."""
1056 branchref = RunGit(['symbolic-ref', 'HEAD']).strip() 1056 branchref = RunGit(['symbolic-ref', 'HEAD']).strip()
1057 branch = ShortBranchName(branchref) 1057 branch = ShortBranchName(branchref)
1058 _, args = parser.parse_args(args) 1058 _, args = parser.parse_args(args)
1059 if not args: 1059 if not args:
1060 print("Current base-url:") 1060 print("Current base-url:")
1061 return RunGit(['config', 'branch.%s.base-url' % branch], 1061 return RunGit(['config', 'branch.%s.base-url' % branch],
1062 error_ok=False).strip() 1062 error_ok=False).strip()
1063 else: 1063 else:
1064 print("Setting base-url to %s" % args[0]) 1064 print("Setting base-url to %s" % args[0])
1065 return RunGit(['config', 'branch.%s.base-url' % branch, args[0]], 1065 return RunGit(['config', 'branch.%s.base-url' % branch, args[0]],
1066 error_ok=False).strip() 1066 error_ok=False).strip()
1067 1067
1068 1068
1069 def CMDstatus(parser, args): 1069 def CMDstatus(parser, args):
1070 """show status of changelists""" 1070 """Show status of changelists.
1071
1072 Colors are used to tell the state of the CL unless --fast is used:
1073 - Green LGTM'ed
1074 - Blue waiting for review
1075 - Yellow waiting for you to reply to review
1076 - Red not sent for review or broken
1077 - Cyan was committed, branch can be deleted
1078
1079 Also see 'git cl comments'.
1080 """
1071 parser.add_option('--field', 1081 parser.add_option('--field',
1072 help='print only specific field (desc|id|patch|url)') 1082 help='print only specific field (desc|id|patch|url)')
1073 parser.add_option('-f', '--fast', action='store_true', 1083 parser.add_option('-f', '--fast', action='store_true',
1074 help='Do not retrieve review status') 1084 help='Do not retrieve review status')
1075 (options, args) = parser.parse_args(args) 1085 (options, args) = parser.parse_args(args)
1076 1086
1077 if options.field: 1087 if options.field:
1078 cl = Changelist() 1088 cl = Changelist()
1079 if options.field.startswith('desc'): 1089 if options.field.startswith('desc'):
1080 print cl.GetDescription() 1090 print cl.GetDescription()
(...skipping 21 matching lines...) Expand all
1102 alignment = max(5, max(len(b) for b in branches)) 1112 alignment = max(5, max(len(b) for b in branches))
1103 print 'Branches associated with reviews:' 1113 print 'Branches associated with reviews:'
1104 # Adhoc thread pool to request data concurrently. 1114 # Adhoc thread pool to request data concurrently.
1105 output = Queue.Queue() 1115 output = Queue.Queue()
1106 1116
1107 # Silence upload.py otherwise it becomes unweldly. 1117 # Silence upload.py otherwise it becomes unweldly.
1108 upload.verbosity = 0 1118 upload.verbosity = 0
1109 1119
1110 if not options.fast: 1120 if not options.fast:
1111 def fetch(b): 1121 def fetch(b):
1122 """Fetches information for an issue and returns (branch, issue, color)."""
1112 c = Changelist(branchref=b) 1123 c = Changelist(branchref=b)
1113 i = c.GetIssueURL() 1124 i = c.GetIssueURL()
1114 try: 1125 props = {}
1115 props = c.GetIssueProperties() 1126 r = None
1116 r = c.GetApprovingReviewers() if i else None 1127 if i:
1117 if not props.get('messages'): 1128 try:
1118 r = None 1129 props = c.GetIssueProperties()
1119 except urllib2.HTTPError: 1130 r = c.GetApprovingReviewers() if i else None
1120 # The issue probably doesn't exist anymore. 1131 except urllib2.HTTPError:
1121 i += ' (broken)' 1132 # The issue probably doesn't exist anymore.
1122 r = None 1133 i += ' (broken)'
1123 output.put((b, i, r)) 1134
1135 msgs = props.get('messages') or []
1136
1137 if not i:
1138 color = Fore.WHITE
1139 elif props.get('closed'):
1140 # Issue is closed.
1141 color = Fore.CYAN
1142 elif r:
1143 # Was LGTM'ed.
1144 color = Fore.GREEN
1145 elif not msgs:
1146 # No message was sent.
1147 color = Fore.RED
1148 elif msgs[-1]['sender'] != props.get('owner_email'):
1149 color = Fore.YELLOW
1150 else:
1151 color = Fore.BLUE
1152 output.put((b, i, color))
1124 1153
1125 threads = [threading.Thread(target=fetch, args=(b,)) for b in branches] 1154 threads = [threading.Thread(target=fetch, args=(b,)) for b in branches]
1126 for t in threads: 1155 for t in threads:
1127 t.daemon = True 1156 t.daemon = True
1128 t.start() 1157 t.start()
1129 else: 1158 else:
1130 # Do not use GetApprovingReviewers(), since it requires an HTTP request. 1159 # Do not use GetApprovingReviewers(), since it requires an HTTP request.
1131 for b in branches: 1160 for b in branches:
1132 c = Changelist(branchref=b) 1161 c = Changelist(branchref=b)
1133 output.put((b, c.GetIssue(), None)) 1162 url = c.GetIssueURL()
1163 output.put((b, url, Fore.BLUE if url else Fore.WHITE))
1134 1164
1135 tmp = {} 1165 tmp = {}
1136 alignment = max(5, max(len(ShortBranchName(b)) for b in branches)) 1166 alignment = max(5, max(len(ShortBranchName(b)) for b in branches))
1137 for branch in sorted(branches): 1167 for branch in sorted(branches):
1138 while branch not in tmp: 1168 while branch not in tmp:
1139 b, i, r = output.get() 1169 b, i, color = output.get()
1140 tmp[b] = (i, r) 1170 tmp[b] = (i, color)
1141 issue, reviewers = tmp.pop(branch) 1171 issue, color = tmp.pop(branch)
1142 if not issue:
1143 color = Fore.WHITE
1144 elif reviewers:
1145 # Was approved.
1146 color = Fore.GREEN
1147 elif reviewers is None:
1148 # No message was sent.
1149 color = Fore.RED
1150 else:
1151 color = Fore.BLUE
1152 print ' %*s: %s%s%s' % ( 1172 print ' %*s: %s%s%s' % (
1153 alignment, ShortBranchName(branch), color, issue, Fore.RESET) 1173 alignment, ShortBranchName(branch), color, issue, Fore.RESET)
1154 1174
1155 cl = Changelist() 1175 cl = Changelist()
1156 print 1176 print
1157 print 'Current branch:', 1177 print 'Current branch:',
1158 if not cl.GetIssue(): 1178 if not cl.GetIssue():
1159 print 'no issue assigned.' 1179 print 'no issue assigned.'
1160 return 0 1180 return 0
1161 print cl.GetBranch() 1181 print cl.GetBranch()
1162 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) 1182 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL())
1163 print 'Issue description:' 1183 print 'Issue description:'
1164 print cl.GetDescription(pretty=True) 1184 print cl.GetDescription(pretty=True)
1165 return 0 1185 return 0
1166 1186
1167 1187
1168 @usage('[issue_number]') 1188 @usage('[issue_number]')
1169 def CMDissue(parser, args): 1189 def CMDissue(parser, args):
1170 """Set or display the current code review issue number. 1190 """Sets or displays the current code review issue number.
1171 1191
1172 Pass issue number 0 to clear the current issue. 1192 Pass issue number 0 to clear the current issue.
1173 """ 1193 """
1174 _, args = parser.parse_args(args) 1194 _, args = parser.parse_args(args)
1175 1195
1176 cl = Changelist() 1196 cl = Changelist()
1177 if len(args) > 0: 1197 if len(args) > 0:
1178 try: 1198 try:
1179 issue = int(args[0]) 1199 issue = int(args[0])
1180 except ValueError: 1200 except ValueError:
1181 DieWithError('Pass a number to set the issue or none to list it.\n' 1201 DieWithError('Pass a number to set the issue or none to list it.\n'
1182 'Maybe you want to run git cl status?') 1202 'Maybe you want to run git cl status?')
1183 cl.SetIssue(issue) 1203 cl.SetIssue(issue)
1184 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) 1204 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL())
1185 return 0 1205 return 0
1186 1206
1187 1207
1188 def CMDcomments(parser, args): 1208 def CMDcomments(parser, args):
1189 """show review comments of the current changelist""" 1209 """Shows review comments of the current changelist."""
1190 (_, args) = parser.parse_args(args) 1210 (_, args) = parser.parse_args(args)
1191 if args: 1211 if args:
1192 parser.error('Unsupported argument: %s' % args) 1212 parser.error('Unsupported argument: %s' % args)
1193 1213
1194 cl = Changelist() 1214 cl = Changelist()
1195 if cl.GetIssue(): 1215 if cl.GetIssue():
1196 data = cl.GetIssueProperties() 1216 data = cl.GetIssueProperties()
1197 for message in sorted(data['messages'], key=lambda x: x['date']): 1217 for message in sorted(data['messages'], key=lambda x: x['date']):
1198 if message['disapproval']: 1218 if message['disapproval']:
1199 color = Fore.RED 1219 color = Fore.RED
1200 elif message['approval']: 1220 elif message['approval']:
1201 color = Fore.GREEN 1221 color = Fore.GREEN
1202 elif message['sender'] == data['owner_email']: 1222 elif message['sender'] == data['owner_email']:
1203 color = Fore.MAGENTA 1223 color = Fore.MAGENTA
1204 else: 1224 else:
1205 color = Fore.BLUE 1225 color = Fore.BLUE
1206 print '\n%s%s %s%s' % ( 1226 print '\n%s%s %s%s' % (
1207 color, message['date'].split('.', 1)[0], message['sender'], 1227 color, message['date'].split('.', 1)[0], message['sender'],
1208 Fore.RESET) 1228 Fore.RESET)
1209 if message['text'].strip(): 1229 if message['text'].strip():
1210 print '\n'.join(' ' + l for l in message['text'].splitlines()) 1230 print '\n'.join(' ' + l for l in message['text'].splitlines())
1211 return 0 1231 return 0
1212 1232
1213 1233
1214 def CMDdescription(parser, args): 1234 def CMDdescription(parser, args):
1215 """brings up the editor for the current CL's description.""" 1235 """Brings up the editor for the current CL's description."""
1216 cl = Changelist() 1236 cl = Changelist()
1217 if not cl.GetIssue(): 1237 if not cl.GetIssue():
1218 DieWithError('This branch has no associated changelist.') 1238 DieWithError('This branch has no associated changelist.')
1219 description = ChangeDescription(cl.GetDescription()) 1239 description = ChangeDescription(cl.GetDescription())
1220 description.prompt() 1240 description.prompt()
1221 cl.UpdateDescription(description.description) 1241 cl.UpdateDescription(description.description)
1222 return 0 1242 return 0
1223 1243
1224 1244
1225 def CreateDescriptionFromLog(args): 1245 def CreateDescriptionFromLog(args):
1226 """Pulls out the commit log to use as a base for the CL description.""" 1246 """Pulls out the commit log to use as a base for the CL description."""
1227 log_args = [] 1247 log_args = []
1228 if len(args) == 1 and not args[0].endswith('.'): 1248 if len(args) == 1 and not args[0].endswith('.'):
1229 log_args = [args[0] + '..'] 1249 log_args = [args[0] + '..']
1230 elif len(args) == 1 and args[0].endswith('...'): 1250 elif len(args) == 1 and args[0].endswith('...'):
1231 log_args = [args[0][:-1]] 1251 log_args = [args[0][:-1]]
1232 elif len(args) == 2: 1252 elif len(args) == 2:
1233 log_args = [args[0] + '..' + args[1]] 1253 log_args = [args[0] + '..' + args[1]]
1234 else: 1254 else:
1235 log_args = args[:] # Hope for the best! 1255 log_args = args[:] # Hope for the best!
1236 return RunGit(['log', '--pretty=format:%s\n\n%b'] + log_args) 1256 return RunGit(['log', '--pretty=format:%s\n\n%b'] + log_args)
1237 1257
1238 1258
1239 def CMDpresubmit(parser, args): 1259 def CMDpresubmit(parser, args):
1240 """run presubmit tests on the current changelist""" 1260 """Runs presubmit tests on the current changelist."""
1241 parser.add_option('-u', '--upload', action='store_true', 1261 parser.add_option('-u', '--upload', action='store_true',
1242 help='Run upload hook instead of the push/dcommit hook') 1262 help='Run upload hook instead of the push/dcommit hook')
1243 parser.add_option('-f', '--force', action='store_true', 1263 parser.add_option('-f', '--force', action='store_true',
1244 help='Run checks even if tree is dirty') 1264 help='Run checks even if tree is dirty')
1245 (options, args) = parser.parse_args(args) 1265 (options, args) = parser.parse_args(args)
1246 1266
1247 if not options.force and is_dirty_git_tree('presubmit'): 1267 if not options.force and is_dirty_git_tree('presubmit'):
1248 print 'use --force to check even if tree is dirty.' 1268 print 'use --force to check even if tree is dirty.'
1249 return 1 1269 return 1
1250 1270
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
1417 So that "--reviewers joe@c,john@c --reviewers joa@c" results in 1437 So that "--reviewers joe@c,john@c --reviewers joa@c" results in
1418 options.reviewers == sorted(['joe@c', 'john@c', 'joa@c']). 1438 options.reviewers == sorted(['joe@c', 'john@c', 'joa@c']).
1419 """ 1439 """
1420 items = sum((i.split(',') for i in l), []) 1440 items = sum((i.split(',') for i in l), [])
1421 stripped_items = (i.strip() for i in items) 1441 stripped_items = (i.strip() for i in items)
1422 return sorted(filter(None, stripped_items)) 1442 return sorted(filter(None, stripped_items))
1423 1443
1424 1444
1425 @usage('[args to "git diff"]') 1445 @usage('[args to "git diff"]')
1426 def CMDupload(parser, args): 1446 def CMDupload(parser, args):
1427 """upload the current changelist to codereview""" 1447 """Uploads the current changelist to codereview."""
1428 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', 1448 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks',
1429 help='bypass upload presubmit hook') 1449 help='bypass upload presubmit hook')
1430 parser.add_option('--bypass-watchlists', action='store_true', 1450 parser.add_option('--bypass-watchlists', action='store_true',
1431 dest='bypass_watchlists', 1451 dest='bypass_watchlists',
1432 help='bypass watchlists auto CC-ing reviewers') 1452 help='bypass watchlists auto CC-ing reviewers')
1433 parser.add_option('-f', action='store_true', dest='force', 1453 parser.add_option('-f', action='store_true', dest='force',
1434 help="force yes to questions (don't prompt)") 1454 help="force yes to questions (don't prompt)")
1435 parser.add_option('-m', dest='message', help='message for patchset') 1455 parser.add_option('-m', dest='message', help='message for patchset')
1436 parser.add_option('-t', dest='title', help='title for patchset') 1456 parser.add_option('-t', dest='title', help='title for patchset')
1437 parser.add_option('-r', '--reviewers', 1457 parser.add_option('-r', '--reviewers',
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
1740 if retcode == 0: 1760 if retcode == 0:
1741 hook = POSTUPSTREAM_HOOK_PATTERN % cmd 1761 hook = POSTUPSTREAM_HOOK_PATTERN % cmd
1742 if os.path.isfile(hook): 1762 if os.path.isfile(hook):
1743 RunCommand([hook, base_branch], error_ok=True) 1763 RunCommand([hook, base_branch], error_ok=True)
1744 1764
1745 return 0 1765 return 0
1746 1766
1747 1767
1748 @usage('[upstream branch to apply against]') 1768 @usage('[upstream branch to apply against]')
1749 def CMDdcommit(parser, args): 1769 def CMDdcommit(parser, args):
1750 """commit the current changelist via git-svn""" 1770 """Commits the current changelist via git-svn."""
1751 if not settings.GetIsGitSvn(): 1771 if not settings.GetIsGitSvn():
1752 message = """This doesn't appear to be an SVN repository. 1772 message = """This doesn't appear to be an SVN repository.
1753 If your project has a git mirror with an upstream SVN master, you probably need 1773 If your project has a git mirror with an upstream SVN master, you probably need
1754 to run 'git svn init', see your project's git mirror documentation. 1774 to run 'git svn init', see your project's git mirror documentation.
1755 If your project has a true writeable upstream repository, you probably want 1775 If your project has a true writeable upstream repository, you probably want
1756 to run 'git cl push' instead. 1776 to run 'git cl push' instead.
1757 Choose wisely, if you get this wrong, your commit might appear to succeed but 1777 Choose wisely, if you get this wrong, your commit might appear to succeed but
1758 will instead be silently ignored.""" 1778 will instead be silently ignored."""
1759 print(message) 1779 print(message)
1760 ask_for_data('[Press enter to dcommit or ctrl-C to quit]') 1780 ask_for_data('[Press enter to dcommit or ctrl-C to quit]')
1761 return SendUpstream(parser, args, 'dcommit') 1781 return SendUpstream(parser, args, 'dcommit')
1762 1782
1763 1783
1764 @usage('[upstream branch to apply against]') 1784 @usage('[upstream branch to apply against]')
1765 def CMDpush(parser, args): 1785 def CMDpush(parser, args):
1766 """commit the current changelist via git""" 1786 """Commits the current changelist via git."""
1767 if settings.GetIsGitSvn(): 1787 if settings.GetIsGitSvn():
1768 print('This appears to be an SVN repository.') 1788 print('This appears to be an SVN repository.')
1769 print('Are you sure you didn\'t mean \'git cl dcommit\'?') 1789 print('Are you sure you didn\'t mean \'git cl dcommit\'?')
1770 ask_for_data('[Press enter to push or ctrl-C to quit]') 1790 ask_for_data('[Press enter to push or ctrl-C to quit]')
1771 return SendUpstream(parser, args, 'push') 1791 return SendUpstream(parser, args, 'push')
1772 1792
1773 1793
1774 @usage('<patch url or issue id>') 1794 @usage('<patch url or issue id>')
1775 def CMDpatch(parser, args): 1795 def CMDpatch(parser, args):
1776 """patch in a code review""" 1796 """Patchs in a code review."""
1777 parser.add_option('-b', dest='newbranch', 1797 parser.add_option('-b', dest='newbranch',
1778 help='create a new branch off trunk for the patch') 1798 help='create a new branch off trunk for the patch')
1779 parser.add_option('-f', action='store_true', dest='force', 1799 parser.add_option('-f', action='store_true', dest='force',
1780 help='with -b, clobber any existing branch') 1800 help='with -b, clobber any existing branch')
1781 parser.add_option('--reject', action='store_true', dest='reject', 1801 parser.add_option('--reject', action='store_true', dest='reject',
1782 help='failed patches spew .rej files rather than ' 1802 help='failed patches spew .rej files rather than '
1783 'attempting a 3-way merge') 1803 'attempting a 3-way merge')
1784 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', 1804 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit',
1785 help="don't commit after patch applies") 1805 help="don't commit after patch applies")
1786 (options, args) = parser.parse_args(args) 1806 (options, args) = parser.parse_args(args)
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
1856 cl = Changelist() 1876 cl = Changelist()
1857 cl.SetIssue(issue) 1877 cl.SetIssue(issue)
1858 cl.SetPatchset(patchset) 1878 cl.SetPatchset(patchset)
1859 print "Committed patch locally." 1879 print "Committed patch locally."
1860 else: 1880 else:
1861 print "Patch applied to index." 1881 print "Patch applied to index."
1862 return 0 1882 return 0
1863 1883
1864 1884
1865 def CMDrebase(parser, args): 1885 def CMDrebase(parser, args):
1866 """rebase current branch on top of svn repo""" 1886 """Rebases current branch on top of svn repo."""
1867 # Provide a wrapper for git svn rebase to help avoid accidental 1887 # Provide a wrapper for git svn rebase to help avoid accidental
1868 # git svn dcommit. 1888 # git svn dcommit.
1869 # It's the only command that doesn't use parser at all since we just defer 1889 # It's the only command that doesn't use parser at all since we just defer
1870 # execution to git-svn. 1890 # execution to git-svn.
1871 env = os.environ.copy() 1891 env = os.environ.copy()
1872 # 'cat' is a magical git string that disables pagers on all platforms. 1892 # 'cat' is a magical git string that disables pagers on all platforms.
1873 env['GIT_PAGER'] = 'cat' 1893 env['GIT_PAGER'] = 'cat'
1874 1894
1875 return subprocess2.call(['git', 'svn', 'rebase'] + args, env=env) 1895 return subprocess2.call(['git', 'svn', 'rebase'] + args, env=env)
1876 1896
(...skipping 17 matching lines...) Expand all
1894 with the reason for the tree to be opened or closed.""" 1914 with the reason for the tree to be opened or closed."""
1895 url = settings.GetTreeStatusUrl() 1915 url = settings.GetTreeStatusUrl()
1896 json_url = urlparse.urljoin(url, '/current?format=json') 1916 json_url = urlparse.urljoin(url, '/current?format=json')
1897 connection = urllib2.urlopen(json_url) 1917 connection = urllib2.urlopen(json_url)
1898 status = json.loads(connection.read()) 1918 status = json.loads(connection.read())
1899 connection.close() 1919 connection.close()
1900 return status['message'] 1920 return status['message']
1901 1921
1902 1922
1903 def CMDtree(parser, args): 1923 def CMDtree(parser, args):
1904 """show the status of the tree""" 1924 """Shows the status of the tree."""
1905 _, args = parser.parse_args(args) 1925 _, args = parser.parse_args(args)
1906 status = GetTreeStatus() 1926 status = GetTreeStatus()
1907 if 'unset' == status: 1927 if 'unset' == status:
1908 print 'You must configure your tree status URL by running "git cl config".' 1928 print 'You must configure your tree status URL by running "git cl config".'
1909 return 2 1929 return 2
1910 1930
1911 print "The tree is %s" % status 1931 print "The tree is %s" % status
1912 print 1932 print
1913 print GetTreeStatusReason() 1933 print GetTreeStatusReason()
1914 if status != 'open': 1934 if status != 'open':
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
2010 builders_and_tests) 2030 builders_and_tests)
2011 print('Tried jobs on:') 2031 print('Tried jobs on:')
2012 length = max(len(builder) for builder in builders_and_tests) 2032 length = max(len(builder) for builder in builders_and_tests)
2013 for builder in sorted(builders_and_tests): 2033 for builder in sorted(builders_and_tests):
2014 print ' %*s: %s' % (length, builder, ','.join(builders_and_tests[builder])) 2034 print ' %*s: %s' % (length, builder, ','.join(builders_and_tests[builder]))
2015 return 0 2035 return 0
2016 2036
2017 2037
2018 @usage('[new upstream branch]') 2038 @usage('[new upstream branch]')
2019 def CMDupstream(parser, args): 2039 def CMDupstream(parser, args):
2020 """prints or sets the name of the upstream branch, if any""" 2040 """Prints or sets the name of the upstream branch, if any."""
2021 _, args = parser.parse_args(args) 2041 _, args = parser.parse_args(args)
2022 if len(args) > 1: 2042 if len(args) > 1:
2023 parser.error('Unrecognized args: %s' % ' '.join(args)) 2043 parser.error('Unrecognized args: %s' % ' '.join(args))
2024 return 0 2044 return 0
2025 2045
2026 cl = Changelist() 2046 cl = Changelist()
2027 if args: 2047 if args:
2028 # One arg means set upstream branch. 2048 # One arg means set upstream branch.
2029 RunGit(['branch', '--set-upstream', cl.GetBranch(), args[0]]) 2049 RunGit(['branch', '--set-upstream', cl.GetBranch(), args[0]])
2030 cl = Changelist() 2050 cl = Changelist()
2031 print "Upstream branch set to " + cl.GetUpstreamBranch() 2051 print "Upstream branch set to " + cl.GetUpstreamBranch()
2032 else: 2052 else:
2033 print cl.GetUpstreamBranch() 2053 print cl.GetUpstreamBranch()
2034 return 0 2054 return 0
2035 2055
2036 2056
2037 def CMDset_commit(parser, args): 2057 def CMDset_commit(parser, args):
2038 """set the commit bit""" 2058 """Sets the commit bit to trigger the Commit Queue."""
2039 _, args = parser.parse_args(args) 2059 _, args = parser.parse_args(args)
2040 if args: 2060 if args:
2041 parser.error('Unrecognized args: %s' % ' '.join(args)) 2061 parser.error('Unrecognized args: %s' % ' '.join(args))
2042 cl = Changelist() 2062 cl = Changelist()
2043 cl.SetFlag('commit', '1') 2063 cl.SetFlag('commit', '1')
2044 return 0 2064 return 0
2045 2065
2046 2066
2047 def CMDset_close(parser, args): 2067 def CMDset_close(parser, args):
2048 """close the issue""" 2068 """Closes the issue."""
2049 _, args = parser.parse_args(args) 2069 _, args = parser.parse_args(args)
2050 if args: 2070 if args:
2051 parser.error('Unrecognized args: %s' % ' '.join(args)) 2071 parser.error('Unrecognized args: %s' % ' '.join(args))
2052 cl = Changelist() 2072 cl = Changelist()
2053 # Ensure there actually is an issue to close. 2073 # Ensure there actually is an issue to close.
2054 cl.GetDescription() 2074 cl.GetDescription()
2055 cl.CloseIssue() 2075 cl.CloseIssue()
2056 return 0 2076 return 0
2057 2077
2058 2078
2059 def CMDformat(parser, args): 2079 def CMDformat(parser, args):
2060 """run clang-format on the diff""" 2080 """Runs clang-format on the diff."""
2061 CLANG_EXTS = ['.cc', '.cpp', '.h'] 2081 CLANG_EXTS = ['.cc', '.cpp', '.h']
2062 parser.add_option('--full', action='store_true', default=False) 2082 parser.add_option('--full', action='store_true', default=False)
2063 opts, args = parser.parse_args(args) 2083 opts, args = parser.parse_args(args)
2064 if args: 2084 if args:
2065 parser.error('Unrecognized args: %s' % ' '.join(args)) 2085 parser.error('Unrecognized args: %s' % ' '.join(args))
2066 2086
2067 # Generate diff for the current branch's changes. 2087 # Generate diff for the current branch's changes.
2068 diff_cmd = ['diff', '--no-ext-diff', '--no-prefix'] 2088 diff_cmd = ['diff', '--no-ext-diff', '--no-prefix']
2069 if opts.full: 2089 if opts.full:
2070 # Only list the names of modified files. 2090 # Only list the names of modified files.
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
2147 return 2167 return
2148 2168
2149 if hamming_commands[0][0] < 0.8: 2169 if hamming_commands[0][0] < 0.8:
2150 # Not similar enough. Don't be a fool and run a random command. 2170 # Not similar enough. Don't be a fool and run a random command.
2151 return 2171 return
2152 2172
2153 return commands[hamming_commands[0][1]] 2173 return commands[hamming_commands[0][1]]
2154 2174
2155 2175
2156 def CMDhelp(parser, args): 2176 def CMDhelp(parser, args):
2157 """print list of commands or help for a specific command""" 2177 """Prints list of commands or help for a specific command."""
2158 _, args = parser.parse_args(args) 2178 _, args = parser.parse_args(args)
2159 if len(args) == 1: 2179 if len(args) == 1:
2160 return main(args + ['--help']) 2180 return main(args + ['--help'])
2161 parser.print_help() 2181 parser.print_help()
2162 return 0 2182 return 0
2163 2183
2164 2184
2165 def GenUsage(parser, command): 2185 def GenUsage(parser, command):
2166 """Modify an OptParse object with the function's documentation.""" 2186 """Modify an OptParse object with the function's documentation."""
2167 obj = Command(command) 2187 obj = Command(command)
2168 # Get back the real command name in case Command() guess the actual command 2188 # Get back the real command name in case Command() guess the actual command
2169 # name. 2189 # name.
2170 command = obj.__name__[3:] 2190 command = obj.__name__[3:]
2171 more = getattr(obj, 'usage_more', '') 2191 more = getattr(obj, 'usage_more', '')
2172 if command == 'help': 2192 if command == 'help':
2173 command = '<command>' 2193 command = '<command>'
2174 else: 2194 else:
2175 # OptParser.description prefer nicely non-formatted strings. 2195 parser.description = obj.__doc__
2176 parser.description = re.sub('[\r\n ]{2,}', ' ', obj.__doc__)
2177 parser.set_usage('usage: %%prog %s [options] %s' % (command, more)) 2196 parser.set_usage('usage: %%prog %s [options] %s' % (command, more))
2178 2197
2179 2198
2199 class OptionParser(optparse.OptionParser):
2200 """Creates the option parse and add --verbose support."""
2201 def __init__(self, *args, **kwargs):
2202 optparse.OptionParser.__init__(self, *args, **kwargs)
2203 self.add_option(
2204 '-v', '--verbose', action='count', default=0,
2205 help='Use 2 times for more debugging info')
2206
2207 def parse_args(self, args=None, values=None):
2208 options, args = optparse.OptionParser.parse_args(self, args, values)
2209 levels = [logging.WARNING, logging.INFO, logging.DEBUG]
2210 logging.basicConfig(level=levels[min(options.verbose, len(levels) - 1)])
2211 return options, args
2212
2213 def format_description(self, _):
2214 """Disables automatic reformatting."""
2215 lines = self.description.rstrip().splitlines()
2216 lines_fixed = [lines[0]] + [l[2:] if len(l) >= 2 else l for l in lines[1:]]
2217 description = ''.join(l + '\n' for l in lines_fixed)
2218 return description[0].upper() + description[1:]
2219
2220
2180 def main(argv): 2221 def main(argv):
2181 """Doesn't parse the arguments here, just find the right subcommand to 2222 """Doesn't parse the arguments here, just find the right subcommand to
2182 execute.""" 2223 execute."""
2183 if sys.hexversion < 0x02060000: 2224 if sys.hexversion < 0x02060000:
2184 print >> sys.stderr, ( 2225 print >> sys.stderr, (
2185 '\nYour python version %s is unsupported, please upgrade.\n' % 2226 '\nYour python version %s is unsupported, please upgrade.\n' %
2186 sys.version.split(' ', 1)[0]) 2227 sys.version.split(' ', 1)[0])
2187 return 2 2228 return 2
2188 2229
2189 # Reload settings. 2230 # Reload settings.
2190 global settings 2231 global settings
2191 settings = Settings() 2232 settings = Settings()
2192 2233
2193 # Do it late so all commands are listed. 2234 # Do it late so all commands are listed.
2194 commands = Commands() 2235 commands = Commands()
2195 length = max(len(c) for c in commands) 2236 length = max(len(c) for c in commands)
2237
2238 def gen_summary(x):
2239 """Creates a oneline summary from the docstring."""
2240 line = x.split('\n', 1)[0].rstrip('.')
2241 return line[0].lower() + line[1:]
2242
2196 docs = sorted( 2243 docs = sorted(
2197 (name, handler.__doc__.split('\n')[0].strip()) 2244 (name, gen_summary(handler.__doc__).strip())
2198 for name, handler in commands.iteritems()) 2245 for name, handler in commands.iteritems())
2199 CMDhelp.usage_more = ('\n\nCommands are:\n' + '\n'.join( 2246 CMDhelp.usage_more = ('\n\nCommands are:\n' + '\n'.join(
2200 ' %-*s %s' % (length, name, doc) for name, doc in docs)) 2247 ' %-*s %s' % (length, name, doc) for name, doc in docs))
2201 2248
2202 # Create the option parse and add --verbose support. 2249 parser = OptionParser()
2203 parser = optparse.OptionParser()
2204 parser.add_option(
2205 '-v', '--verbose', action='count', default=0,
2206 help='Use 2 times for more debugging info')
2207 old_parser_args = parser.parse_args
2208 def Parse(args):
2209 options, args = old_parser_args(args)
2210 if options.verbose >= 2:
2211 logging.basicConfig(level=logging.DEBUG)
2212 elif options.verbose:
2213 logging.basicConfig(level=logging.INFO)
2214 else:
2215 logging.basicConfig(level=logging.WARNING)
2216 return options, args
2217 parser.parse_args = Parse
2218
2219 if argv: 2250 if argv:
2220 command = Command(argv[0]) 2251 command = Command(argv[0])
2221 if command: 2252 if command:
2222 # "fix" the usage and the description now that we know the subcommand. 2253 # "fix" the usage and the description now that we know the subcommand.
2223 GenUsage(parser, argv[0]) 2254 GenUsage(parser, argv[0])
2224 try: 2255 try:
2225 return command(parser, argv[1:]) 2256 return command(parser, argv[1:])
2226 except urllib2.HTTPError, e: 2257 except urllib2.HTTPError, e:
2227 if e.code != 500: 2258 if e.code != 500:
2228 raise 2259 raise
2229 DieWithError( 2260 DieWithError(
2230 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' 2261 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith '
2231 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) 2262 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e)))
2232 2263
2233 # Not a known command. Default to help. 2264 # Not a known command. Default to help.
2234 GenUsage(parser, 'help') 2265 GenUsage(parser, 'help')
2235 return CMDhelp(parser, argv) 2266 return CMDhelp(parser, argv)
2236 2267
2237 2268
2238 if __name__ == '__main__': 2269 if __name__ == '__main__':
2239 # These affect sys.stdout so do it outside of main() to simplify mocks in 2270 # These affect sys.stdout so do it outside of main() to simplify mocks in
2240 # unit testing. 2271 # unit testing.
2241 fix_encoding.fix_encoding() 2272 fix_encoding.fix_encoding()
2242 colorama.init() 2273 colorama.init()
2243 sys.exit(main(sys.argv[1:])) 2274 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « gclient.py ('k') | tests/gclient_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698