| Index: git_cl.py
|
| diff --git a/git_cl.py b/git_cl.py
|
| index d838b9dd9eed764e28598cb01652a30ddc541356..039b35df17cdfb4c402730c3d233c057df27e4b0 100755
|
| --- a/git_cl.py
|
| +++ b/git_cl.py
|
| @@ -8,6 +8,7 @@
|
| """A git-command for integrating reviews on Rietveld."""
|
|
|
| from distutils.version import LooseVersion
|
| +from multiprocessing.pool import ThreadPool
|
| import base64
|
| import glob
|
| import json
|
| @@ -20,7 +21,6 @@ import stat
|
| import sys
|
| import tempfile
|
| import textwrap
|
| -import threading
|
| import urllib2
|
| import urlparse
|
| import webbrowser
|
| @@ -1342,6 +1342,51 @@ def color_for_status(status):
|
| 'error': Fore.WHITE,
|
| }.get(status, Fore.WHITE)
|
|
|
| +def fetch_cl_status(b):
|
| + """Fetches information for an issue and returns (branch, issue, color)."""
|
| + c = Changelist(branchref=b)
|
| + i = c.GetIssueURL()
|
| + status = c.GetStatus()
|
| + color = color_for_status(status)
|
| +
|
| + if i and (not status or status == 'error'):
|
| + # The issue probably doesn't exist anymore.
|
| + i += ' (broken)'
|
| +
|
| + return (b, i, color)
|
| +
|
| +def get_cl_statuses(branches, fine_grained, max_processes=None):
|
| + """Returns a blocking iterable of (branch, issue, color) for given branches.
|
| +
|
| + If fine_grained is true, this will fetch CL statuses from the server.
|
| + Otherwise, simply indicate if there's a matching url for the given branches.
|
| +
|
| + If max_processes is specified, it is used as the maximum number of processes
|
| + to spawn to fetch CL status from the server. Otherwise 1 process per branch is
|
| + spawned.
|
| + """
|
| + # Silence upload.py otherwise it becomes unwieldly.
|
| + upload.verbosity = 0
|
| +
|
| + if fine_grained:
|
| + # Process one branch synchronously to work through authentication, then
|
| + # spawn processes to process all the other branches in parallel.
|
| + if branches:
|
| + yield fetch_cl_status(branches[0])
|
| +
|
| + branches_to_fetch = branches[1:]
|
| + pool = ThreadPool(
|
| + min(max_processes, len(branches_to_fetch))
|
| + if max_processes is not None
|
| + else len(branches_to_fetch))
|
| + for x in pool.imap_unordered(fetch_cl_status, branches_to_fetch):
|
| + yield x
|
| + else:
|
| + # Do not use GetApprovingReviewers(), since it requires an HTTP request.
|
| + for b in branches:
|
| + c = Changelist(branchref=b)
|
| + url = c.GetIssueURL()
|
| + yield (b, url, Fore.BLUE if url else Fore.WHITE)
|
|
|
| def CMDstatus(parser, args):
|
| """Show status of changelists.
|
| @@ -1360,6 +1405,9 @@ def CMDstatus(parser, args):
|
| help='print only specific field (desc|id|patch|url)')
|
| parser.add_option('-f', '--fast', action='store_true',
|
| help='Do not retrieve review status')
|
| + parser.add_option(
|
| + '-j', '--maxjobs', action='store', type=int,
|
| + help='The maximum number of jobs to use when retrieving review status')
|
| (options, args) = parser.parse_args(args)
|
| if args:
|
| parser.error('Unsupported args: %s' % args)
|
| @@ -1391,49 +1439,17 @@ def CMDstatus(parser, args):
|
| branches = [c.GetBranch() 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):
|
| - """Fetches information for an issue and returns (branch, issue, color)."""
|
| - c = Changelist(branchref=b)
|
| - i = c.GetIssueURL()
|
| - status = c.GetStatus()
|
| - color = color_for_status(status)
|
| -
|
| - if i and (not status or status == 'error'):
|
| - # The issue probably doesn't exist anymore.
|
| - i += ' (broken)'
|
| -
|
| - output.put((b, i, color))
|
| -
|
| - # Process one branch synchronously to work through authentication, then
|
| - # spawn threads to process all the other branches in parallel.
|
| - if branches:
|
| - fetch(branches[0])
|
| - threads = [
|
| - threading.Thread(target=fetch, args=(b,)) for b in branches[1:]]
|
| - 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)
|
| - url = c.GetIssueURL()
|
| - output.put((b, url, Fore.BLUE if url else Fore.WHITE))
|
| + output = get_cl_statuses(branches,
|
| + fine_grained=not options.fast,
|
| + max_processes=options.maxjobs)
|
|
|
| - tmp = {}
|
| + branch_statuses = {}
|
| alignment = max(5, max(len(ShortBranchName(b)) for b in branches))
|
| for branch in sorted(branches):
|
| - while branch not in tmp:
|
| - b, i, color = output.get()
|
| - tmp[b] = (i, color)
|
| - issue, color = tmp.pop(branch)
|
| + while branch not in branch_statuses:
|
| + b, i, color = output.next()
|
| + branch_statuses[b] = (i, color)
|
| + issue, color = branch_statuses.pop(branch)
|
| reset = Fore.RESET
|
| if not sys.stdout.isatty():
|
| color = ''
|
|
|