Extend the Command class to support adding the --jobs option to the parser if the command declares it supports running in parallel. Also pull the default value used for the number of local jobs into the command module so local commands can share it. Change-Id: I22b0f8d2cf69875013cec657b8e6c4385549ccac Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/297024 Tested-by: Mike Frysinger <vapier@google.com> Reviewed-by: Chris Mcdonald <cjmcdonald@google.com>
207 lines
5.8 KiB
Python
207 lines
5.8 KiB
Python
# Copyright (C) 2009 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import itertools
|
|
import multiprocessing
|
|
import sys
|
|
from color import Coloring
|
|
from command import Command, DEFAULT_LOCAL_JOBS
|
|
|
|
# Number of projects to submit to a single worker process at a time.
|
|
# This number represents a tradeoff between the overhead of IPC and finer
|
|
# grained opportunity for parallelism. This particular value was chosen by
|
|
# iterating through powers of two until the overall performance no longer
|
|
# improved. The performance of this batch size is not a function of the
|
|
# number of cores on the system.
|
|
WORKER_BATCH_SIZE = 32
|
|
|
|
|
|
class BranchColoring(Coloring):
|
|
def __init__(self, config):
|
|
Coloring.__init__(self, config, 'branch')
|
|
self.current = self.printer('current', fg='green')
|
|
self.local = self.printer('local')
|
|
self.notinproject = self.printer('notinproject', fg='red')
|
|
|
|
|
|
class BranchInfo(object):
|
|
def __init__(self, name):
|
|
self.name = name
|
|
self.current = 0
|
|
self.published = 0
|
|
self.published_equal = 0
|
|
self.projects = []
|
|
|
|
def add(self, b):
|
|
if b.current:
|
|
self.current += 1
|
|
if b.published:
|
|
self.published += 1
|
|
if b.revision == b.published:
|
|
self.published_equal += 1
|
|
self.projects.append(b)
|
|
|
|
@property
|
|
def IsCurrent(self):
|
|
return self.current > 0
|
|
|
|
@property
|
|
def IsSplitCurrent(self):
|
|
return self.current != 0 and self.current != len(self.projects)
|
|
|
|
@property
|
|
def IsPublished(self):
|
|
return self.published > 0
|
|
|
|
@property
|
|
def IsPublishedEqual(self):
|
|
return self.published_equal == len(self.projects)
|
|
|
|
|
|
class Branches(Command):
|
|
common = True
|
|
helpSummary = "View current topic branches"
|
|
helpUsage = """
|
|
%prog [<project>...]
|
|
|
|
Summarizes the currently available topic branches.
|
|
|
|
# Branch Display
|
|
|
|
The branch display output by this command is organized into four
|
|
columns of information; for example:
|
|
|
|
*P nocolor | in repo
|
|
repo2 |
|
|
|
|
The first column contains a * if the branch is the currently
|
|
checked out branch in any of the specified projects, or a blank
|
|
if no project has the branch checked out.
|
|
|
|
The second column contains either blank, p or P, depending upon
|
|
the upload status of the branch.
|
|
|
|
(blank): branch not yet published by repo upload
|
|
P: all commits were published by repo upload
|
|
p: only some commits were published by repo upload
|
|
|
|
The third column contains the branch name.
|
|
|
|
The fourth column (after the | separator) lists the projects that
|
|
the branch appears in, or does not appear in. If no project list
|
|
is shown, then the branch appears in all projects.
|
|
|
|
"""
|
|
PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
|
|
|
|
def Execute(self, opt, args):
|
|
projects = self.GetProjects(args)
|
|
out = BranchColoring(self.manifest.manifestProject.config)
|
|
all_branches = {}
|
|
project_cnt = len(projects)
|
|
with multiprocessing.Pool(processes=opt.jobs) as pool:
|
|
project_branches = pool.imap_unordered(
|
|
expand_project_to_branches, projects, chunksize=WORKER_BATCH_SIZE)
|
|
|
|
for name, b in itertools.chain.from_iterable(project_branches):
|
|
if name not in all_branches:
|
|
all_branches[name] = BranchInfo(name)
|
|
all_branches[name].add(b)
|
|
|
|
names = sorted(all_branches)
|
|
|
|
if not names:
|
|
print(' (no branches)', file=sys.stderr)
|
|
return
|
|
|
|
width = 25
|
|
for name in names:
|
|
if width < len(name):
|
|
width = len(name)
|
|
|
|
for name in names:
|
|
i = all_branches[name]
|
|
in_cnt = len(i.projects)
|
|
|
|
if i.IsCurrent:
|
|
current = '*'
|
|
hdr = out.current
|
|
else:
|
|
current = ' '
|
|
hdr = out.local
|
|
|
|
if i.IsPublishedEqual:
|
|
published = 'P'
|
|
elif i.IsPublished:
|
|
published = 'p'
|
|
else:
|
|
published = ' '
|
|
|
|
hdr('%c%c %-*s' % (current, published, width, name))
|
|
out.write(' |')
|
|
|
|
if in_cnt < project_cnt:
|
|
fmt = out.write
|
|
paths = []
|
|
non_cur_paths = []
|
|
if i.IsSplitCurrent or (in_cnt < project_cnt - in_cnt):
|
|
in_type = 'in'
|
|
for b in i.projects:
|
|
if not i.IsSplitCurrent or b.current:
|
|
paths.append(b.project.relpath)
|
|
else:
|
|
non_cur_paths.append(b.project.relpath)
|
|
else:
|
|
fmt = out.notinproject
|
|
in_type = 'not in'
|
|
have = set()
|
|
for b in i.projects:
|
|
have.add(b.project)
|
|
for p in projects:
|
|
if p not in have:
|
|
paths.append(p.relpath)
|
|
|
|
s = ' %s %s' % (in_type, ', '.join(paths))
|
|
if not i.IsSplitCurrent and (width + 7 + len(s) < 80):
|
|
fmt = out.current if i.IsCurrent else fmt
|
|
fmt(s)
|
|
else:
|
|
fmt(' %s:' % in_type)
|
|
fmt = out.current if i.IsCurrent else out.write
|
|
for p in paths:
|
|
out.nl()
|
|
fmt(width * ' ' + ' %s' % p)
|
|
fmt = out.write
|
|
for p in non_cur_paths:
|
|
out.nl()
|
|
fmt(width * ' ' + ' %s' % p)
|
|
else:
|
|
out.write(' in all projects')
|
|
out.nl()
|
|
|
|
|
|
def expand_project_to_branches(project):
|
|
"""Expands a project into a list of branch names & associated information.
|
|
|
|
Args:
|
|
project: project.Project
|
|
|
|
Returns:
|
|
List[Tuple[str, git_config.Branch]]
|
|
"""
|
|
branches = []
|
|
for name, b in project.GetBranches().items():
|
|
b.project = project
|
|
branches.append((name, b))
|
|
return branches
|