Index: git_cl.py |
diff --git a/git_cl.py b/git_cl.py |
index db9823042e62a91a1e8258e007cc5a90380c162b..15d19c0f1e8f95993aa0ebb41ce45de2ede1c244 100755 |
--- a/git_cl.py |
+++ b/git_cl.py |
@@ -13,10 +13,12 @@ import json |
import logging |
import optparse |
import os |
+import Queue |
import re |
import stat |
import sys |
import textwrap |
+import threading |
import urllib2 |
import urlparse |
@@ -412,7 +414,7 @@ def ShortBranchName(branch): |
class Changelist(object): |
- def __init__(self, branchref=None): |
+ def __init__(self, branchref=None, issue=None): |
# Poke settings so we get the "configure your server" message if necessary. |
global settings |
if not settings: |
@@ -426,16 +428,17 @@ class Changelist(object): |
self.branch = None |
self.rietveld_server = None |
self.upstream_branch = None |
- self.has_issue = False |
- self.issue = None |
+ self.lookedup_issue = False |
+ self.issue = issue or None |
self.has_description = False |
self.description = None |
- self.has_patchset = False |
+ self.lookedup_patchset = False |
self.patchset = None |
self._rpc_server = None |
self.cc = None |
self.watchers = () |
self._remote = None |
+ self._props = None |
def GetCCList(self): |
"""Return the users cc'd on this CL. |
@@ -601,13 +604,10 @@ or verify this branch is set up to track another (via the --track argument to |
def GetIssue(self): |
"""Returns the issue number as a int or None if not set.""" |
- if not self.has_issue: |
+ if self.issue is None and not self.lookedup_issue: |
issue = RunGit(['config', self._IssueSetting()], error_ok=True).strip() |
- if issue: |
- self.issue = int(issue) |
- else: |
- self.issue = None |
- self.has_issue = True |
+ self.issue = int(issue) or None if issue else None |
+ self.lookedup_issue = True |
return self.issue |
def GetRietveldServer(self): |
@@ -656,47 +656,53 @@ or verify this branch is set up to track another (via the --track argument to |
def GetPatchset(self): |
"""Returns the patchset number as a int or None if not set.""" |
- if not self.has_patchset: |
+ if self.patchset is None and not self.lookedup_patchset: |
patchset = RunGit(['config', self._PatchsetSetting()], |
error_ok=True).strip() |
- if patchset: |
- self.patchset = int(patchset) |
- else: |
- self.patchset = None |
- self.has_patchset = True |
+ self.patchset = int(patchset) or None if patchset else None |
+ self.lookedup_patchset = True |
return self.patchset |
def SetPatchset(self, patchset): |
"""Set this branch's patchset. If patchset=0, clears the patchset.""" |
if patchset: |
RunGit(['config', self._PatchsetSetting(), str(patchset)]) |
+ self.patchset = patchset |
else: |
RunGit(['config', '--unset', self._PatchsetSetting()], |
stderr=subprocess2.PIPE, error_ok=True) |
- self.has_patchset = False |
+ self.patchset = None |
- def GetMostRecentPatchset(self, issue): |
- return self.RpcServer().get_issue_properties( |
- int(issue), False)['patchsets'][-1] |
+ def GetMostRecentPatchset(self): |
+ return self.GetIssueProperties()['patchsets'][-1] |
def GetPatchSetDiff(self, issue, patchset): |
return self.RpcServer().get( |
'/download/issue%s_%s.diff' % (issue, patchset)) |
+ def GetIssueProperties(self): |
+ if self._props is None: |
+ issue = self.GetIssue() |
+ if not issue: |
+ self._props = {} |
+ else: |
+ self._props = self.RpcServer().get_issue_properties(issue, True) |
+ return self._props |
+ |
def GetApprovingReviewers(self): |
- return get_approving_reviewers( |
- self.RpcServer().get_issue_properties(self.GetIssue(), True)) |
+ return get_approving_reviewers(self.GetIssueProperties()) |
def SetIssue(self, issue): |
"""Set this branch's issue. If issue=0, clears the issue.""" |
if issue: |
+ self.issue = issue |
RunGit(['config', self._IssueSetting(), str(issue)]) |
if self.rietveld_server: |
RunGit(['config', self._RietveldServer(), self.rietveld_server]) |
else: |
RunGit(['config', '--unset', self._IssueSetting()]) |
- self.SetPatchset(0) |
- self.has_issue = False |
+ self.issue = None |
+ self.SetPatchset(None) |
def GetChange(self, upstream_branch, author): |
if not self.GitSanityChecks(upstream_branch): |
@@ -1064,6 +1070,8 @@ def CMDstatus(parser, args): |
"""show status of changelists""" |
parser.add_option('--field', |
help='print only specific field (desc|id|patch|url)') |
+ parser.add_option('-f', '--fast', action='store_true', |
+ help='Do not retrieve review status') |
(options, args) = parser.parse_args(args) |
if options.field: |
@@ -1093,8 +1101,57 @@ def CMDstatus(parser, args): |
branches = dict((c.GetBranch(), c.GetIssueURL()) for c in changes) |
alignment = max(5, max(len(b) for b in branches)) |
print 'Branches associated with reviews:' |
+ # Adhoc thread pool to request data concurrently. |
+ output = Queue.Queue() |
+ |
+ # Silence upload.py otherwise it becomes unweldly. |
+ upload.verbosity = 0 |
+ |
+ if not options.fast: |
+ def fetch(b): |
+ c = Changelist(branchref=b) |
+ i = c.GetIssueURL() |
+ try: |
+ props = c.GetIssueProperties() |
+ r = c.GetApprovingReviewers() if i else None |
+ if not props.get('messages'): |
+ r = None |
+ except urllib2.HTTPError: |
+ # The issue probably doesn't exist anymore. |
+ i += ' (broken)' |
+ r = None |
+ output.put((b, i, r)) |
+ |
+ threads = [threading.Thread(target=fetch, args=(b,)) for b in branches] |
+ for t in threads: |
+ t.daemon = True |
+ t.start() |
+ else: |
+ # Do not use GetApprovingReviewers(), since it requires an HTTP request. |
+ for b in branches: |
+ c = Changelist(branchref=b) |
+ output.put((b, c.GetIssue(), None)) |
+ |
+ tmp = {} |
+ alignment = max(5, max(len(ShortBranchName(b)) for b in branches)) |
for branch in sorted(branches): |
- print " %*s: %s" % (alignment, branch, branches[branch]) |
+ while branch not in tmp: |
+ b, i, r = output.get() |
+ tmp[b] = (i, r) |
+ issue, reviewers = tmp.pop(branch) |
+ if not issue: |
+ color = Fore.WHITE |
+ elif reviewers: |
+ # Was approved. |
+ color = Fore.GREEN |
+ elif reviewers is None: |
+ # No message was sent. |
+ color = Fore.RED |
+ else: |
+ color = Fore.BLUE |
+ print ' %*s: %s%s%s' % ( |
+ alignment, ShortBranchName(branch), color, issue, Fore.RESET) |
+ |
cl = Changelist() |
print 'Current branch:', |
@@ -1136,7 +1193,7 @@ def CMDcomments(parser, args): |
cl = Changelist() |
if cl.GetIssue(): |
- data = cl.RpcServer().get_issue_properties(cl.GetIssue(), True) |
+ data = cl.GetIssueProperties() |
for message in sorted(data['messages'], key=lambda x: x['date']): |
if message['disapproval']: |
color = Fore.RED |
@@ -1434,7 +1491,7 @@ def CMDupload(parser, args): |
options.reviewers = hook_results.reviewers.split(',') |
if cl.GetIssue(): |
- latest_patchset = cl.GetMostRecentPatchset(cl.GetIssue()) |
+ latest_patchset = cl.GetMostRecentPatchset() |
local_patchset = cl.GetPatchset() |
if latest_patchset and local_patchset and local_patchset != latest_patchset: |
print ('The last upload made from this repository was patchset #%d but ' |
@@ -1673,12 +1730,12 @@ def SendUpstream(parser, args, cmd): |
'(you may be prompted for your codereview password)...') |
cl.UpdateDescription(change_desc.description) |
cl.CloseIssue() |
- props = cl.RpcServer().get_issue_properties(cl.GetIssue(), False) |
+ props = cl.GetIssueProperties() |
patch_num = len(props['patchsets']) |
comment = "Committed patchset #%d manually as r%s" % (patch_num, revision) |
comment += ' (presubmit successful).' if not options.bypass_hooks else '.' |
cl.RpcServer().add_comment(cl.GetIssue(), comment) |
- cl.SetIssue(0) |
+ cl.SetIssue(None) |
iannucci
2013/07/23 21:19:25
if you git cl issue 0, will that still do the righ
M-A Ruel
2013/07/23 23:22:29
Yes, tested.
|
if retcode == 0: |
hook = POSTUPSTREAM_HOOK_PATTERN % cmd |
@@ -1737,9 +1794,9 @@ def CMDpatch(parser, args): |
if issue_arg.isdigit(): |
# Input is an issue id. Figure out the URL. |
- cl = Changelist() |
issue = int(issue_arg) |
- patchset = cl.GetMostRecentPatchset(issue) |
+ cl = Changelist(issue) |
+ patchset = cl.GetMostRecentPatchset() |
patch_data = cl.GetPatchSetDiff(issue, patchset) |
else: |
# Assume it's a URL to the patch. Default to https. |
@@ -1946,7 +2003,7 @@ def CMDtry(parser, args): |
patchset = cl.GetPatchset() |
if not cl.GetPatchset(): |
- patchset = cl.GetMostRecentPatchset(cl.GetIssue()) |
+ patchset = cl.GetMostRecentPatchset() |
cl.RpcServer().trigger_try_jobs( |
cl.GetIssue(), patchset, options.name, options.clobber, options.revision, |