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

Side by Side Diff: git_cl.py

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