2009-04-10 23:02:48 +00:00
|
|
|
# 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.
|
|
|
|
|
2020-12-09 21:27:59 +00:00
|
|
|
import itertools
|
|
|
|
import multiprocessing
|
2009-04-10 23:02:48 +00:00
|
|
|
import sys
|
|
|
|
from color import Coloring
|
|
|
|
from command import Command
|
|
|
|
|
2020-12-09 21:27:59 +00:00
|
|
|
# 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
|
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2009-04-10 23:02:48 +00:00
|
|
|
class BranchColoring(Coloring):
|
|
|
|
def __init__(self, config):
|
|
|
|
Coloring.__init__(self, config, 'branch')
|
|
|
|
self.current = self.printer('current', fg='green')
|
2020-02-12 05:31:05 +00:00
|
|
|
self.local = self.printer('local')
|
2009-04-10 23:02:48 +00:00
|
|
|
self.notinproject = self.printer('notinproject', fg='red')
|
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2009-04-10 23:02:48 +00:00
|
|
|
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
|
|
|
|
|
2014-07-10 04:33:31 +00:00
|
|
|
@property
|
|
|
|
def IsSplitCurrent(self):
|
|
|
|
return self.current != 0 and self.current != len(self.projects)
|
|
|
|
|
2009-04-10 23:02:48 +00:00
|
|
|
@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.
|
2009-06-13 00:35:43 +00:00
|
|
|
|
2018-10-10 05:05:11 +00:00
|
|
|
# Branch Display
|
2009-06-13 00:35:43 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2009-04-10 23:02:48 +00:00
|
|
|
"""
|
|
|
|
|
2020-12-09 21:27:59 +00:00
|
|
|
def _Options(self, p):
|
|
|
|
"""Add flags to CLI parser for this subcommand."""
|
|
|
|
default_jobs = min(multiprocessing.cpu_count(), 8)
|
|
|
|
p.add_option(
|
|
|
|
'-j',
|
|
|
|
'--jobs',
|
|
|
|
type=int,
|
|
|
|
default=default_jobs,
|
|
|
|
help='Number of worker processes to spawn '
|
|
|
|
'(default: %s)' % default_jobs)
|
|
|
|
|
2009-04-10 23:02:48 +00:00
|
|
|
def Execute(self, opt, args):
|
|
|
|
projects = self.GetProjects(args)
|
|
|
|
out = BranchColoring(self.manifest.manifestProject.config)
|
2012-10-11 07:44:48 +00:00
|
|
|
all_branches = {}
|
2009-04-10 23:02:48 +00:00
|
|
|
project_cnt = len(projects)
|
2020-12-09 21:27:59 +00:00
|
|
|
with multiprocessing.Pool(processes=opt.jobs) as pool:
|
|
|
|
project_branches = pool.imap_unordered(
|
|
|
|
expand_project_to_branches, projects, chunksize=WORKER_BATCH_SIZE)
|
2009-04-10 23:02:48 +00:00
|
|
|
|
2020-12-09 21:27:59 +00:00
|
|
|
for name, b in itertools.chain.from_iterable(project_branches):
|
2012-10-11 07:44:48 +00:00
|
|
|
if name not in all_branches:
|
|
|
|
all_branches[name] = BranchInfo(name)
|
|
|
|
all_branches[name].add(b)
|
2009-04-10 23:02:48 +00:00
|
|
|
|
2020-12-09 21:27:59 +00:00
|
|
|
names = sorted(all_branches)
|
2009-04-10 23:02:48 +00:00
|
|
|
|
2009-04-18 22:18:35 +00:00
|
|
|
if not names:
|
2012-11-02 05:59:27 +00:00
|
|
|
print(' (no branches)', file=sys.stderr)
|
2009-04-18 22:18:35 +00:00
|
|
|
return
|
|
|
|
|
2009-04-10 23:02:48 +00:00
|
|
|
width = 25
|
|
|
|
for name in names:
|
|
|
|
if width < len(name):
|
|
|
|
width = len(name)
|
|
|
|
|
|
|
|
for name in names:
|
2012-10-11 07:44:48 +00:00
|
|
|
i = all_branches[name]
|
2009-04-10 23:02:48 +00:00
|
|
|
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(' |')
|
|
|
|
|
2009-09-05 21:10:56 +00:00
|
|
|
if in_cnt < project_cnt:
|
2009-04-10 23:02:48 +00:00
|
|
|
fmt = out.write
|
|
|
|
paths = []
|
2014-07-10 04:33:31 +00:00
|
|
|
non_cur_paths = []
|
|
|
|
if i.IsSplitCurrent or (in_cnt < project_cnt - in_cnt):
|
2012-09-24 03:15:13 +00:00
|
|
|
in_type = 'in'
|
2009-04-10 23:02:48 +00:00
|
|
|
for b in i.projects:
|
2014-07-10 04:33:31 +00:00
|
|
|
if not i.IsSplitCurrent or b.current:
|
|
|
|
paths.append(b.project.relpath)
|
|
|
|
else:
|
|
|
|
non_cur_paths.append(b.project.relpath)
|
2009-04-10 23:02:48 +00:00
|
|
|
else:
|
|
|
|
fmt = out.notinproject
|
2012-09-24 03:15:13 +00:00
|
|
|
in_type = 'not in'
|
2009-04-10 23:02:48 +00:00
|
|
|
have = set()
|
|
|
|
for b in i.projects:
|
|
|
|
have.add(b.project)
|
|
|
|
for p in projects:
|
2020-02-12 02:24:10 +00:00
|
|
|
if p not in have:
|
2009-09-05 21:10:56 +00:00
|
|
|
paths.append(p.relpath)
|
2009-04-10 23:02:48 +00:00
|
|
|
|
2012-09-24 03:15:13 +00:00
|
|
|
s = ' %s %s' % (in_type, ', '.join(paths))
|
2014-07-10 04:33:31 +00:00
|
|
|
if not i.IsSplitCurrent and (width + 7 + len(s) < 80):
|
|
|
|
fmt = out.current if i.IsCurrent else fmt
|
2009-04-10 23:02:48 +00:00
|
|
|
fmt(s)
|
|
|
|
else:
|
2012-09-24 03:15:13 +00:00
|
|
|
fmt(' %s:' % in_type)
|
2014-07-10 04:33:31 +00:00
|
|
|
fmt = out.current if i.IsCurrent else out.write
|
2009-04-10 23:02:48 +00:00
|
|
|
for p in paths:
|
|
|
|
out.nl()
|
2020-02-12 05:31:05 +00:00
|
|
|
fmt(width * ' ' + ' %s' % p)
|
2014-07-10 04:33:31 +00:00
|
|
|
fmt = out.write
|
|
|
|
for p in non_cur_paths:
|
|
|
|
out.nl()
|
2020-02-12 05:31:05 +00:00
|
|
|
fmt(width * ' ' + ' %s' % p)
|
2009-09-05 21:10:56 +00:00
|
|
|
else:
|
|
|
|
out.write(' in all projects')
|
2009-04-10 23:02:48 +00:00
|
|
|
out.nl()
|
2020-12-09 21:27:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
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
|