blob: 9665e85f1ef11bdb51656caa3098d6c9232cc7bc [file] [log] [blame]
Shawn O. Pearce27b07322009-04-10 16:02:48 -07001# Copyright (C) 2009 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Chris McDonald8add6232020-12-09 14:27:59 -070015import itertools
16import multiprocessing
Shawn O. Pearce27b07322009-04-10 16:02:48 -070017import sys
18from color import Coloring
Mike Frysinger6a2400a2021-02-16 01:43:31 -050019from command import Command, DEFAULT_LOCAL_JOBS
Shawn O. Pearce27b07322009-04-10 16:02:48 -070020
Chris McDonald8add6232020-12-09 14:27:59 -070021# Number of projects to submit to a single worker process at a time.
22# This number represents a tradeoff between the overhead of IPC and finer
23# grained opportunity for parallelism. This particular value was chosen by
24# iterating through powers of two until the overall performance no longer
25# improved. The performance of this batch size is not a function of the
26# number of cores on the system.
27WORKER_BATCH_SIZE = 32
28
David Pursehouse819827a2020-02-12 15:20:19 +090029
Shawn O. Pearce27b07322009-04-10 16:02:48 -070030class BranchColoring(Coloring):
31 def __init__(self, config):
32 Coloring.__init__(self, config, 'branch')
33 self.current = self.printer('current', fg='green')
David Pursehouse54a4e602020-02-12 14:31:05 +090034 self.local = self.printer('local')
Shawn O. Pearce27b07322009-04-10 16:02:48 -070035 self.notinproject = self.printer('notinproject', fg='red')
36
David Pursehouse819827a2020-02-12 15:20:19 +090037
Shawn O. Pearce27b07322009-04-10 16:02:48 -070038class BranchInfo(object):
39 def __init__(self, name):
40 self.name = name
41 self.current = 0
42 self.published = 0
43 self.published_equal = 0
44 self.projects = []
45
46 def add(self, b):
47 if b.current:
48 self.current += 1
49 if b.published:
50 self.published += 1
51 if b.revision == b.published:
52 self.published_equal += 1
53 self.projects.append(b)
54
55 @property
56 def IsCurrent(self):
57 return self.current > 0
58
59 @property
Etan Cohen588142d2014-07-09 21:33:31 -070060 def IsSplitCurrent(self):
61 return self.current != 0 and self.current != len(self.projects)
62
63 @property
Shawn O. Pearce27b07322009-04-10 16:02:48 -070064 def IsPublished(self):
65 return self.published > 0
66
67 @property
68 def IsPublishedEqual(self):
69 return self.published_equal == len(self.projects)
70
71
72class Branches(Command):
73 common = True
74 helpSummary = "View current topic branches"
75 helpUsage = """
76%prog [<project>...]
77
78Summarizes the currently available topic branches.
Shawn O. Pearce7da73d62009-06-12 17:35:43 -070079
Mike Frysingerb8f7bb02018-10-10 01:05:11 -040080# Branch Display
Shawn O. Pearce7da73d62009-06-12 17:35:43 -070081
82The branch display output by this command is organized into four
83columns of information; for example:
84
85 *P nocolor | in repo
86 repo2 |
87
88The first column contains a * if the branch is the currently
89checked out branch in any of the specified projects, or a blank
90if no project has the branch checked out.
91
92The second column contains either blank, p or P, depending upon
93the upload status of the branch.
94
95 (blank): branch not yet published by repo upload
96 P: all commits were published by repo upload
97 p: only some commits were published by repo upload
98
99The third column contains the branch name.
100
101The fourth column (after the | separator) lists the projects that
102the branch appears in, or does not appear in. If no project list
103is shown, then the branch appears in all projects.
104
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700105"""
Mike Frysinger6a2400a2021-02-16 01:43:31 -0500106 PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
Chris McDonald8add6232020-12-09 14:27:59 -0700107
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700108 def Execute(self, opt, args):
109 projects = self.GetProjects(args)
110 out = BranchColoring(self.manifest.manifestProject.config)
David Pursehouse5c6eeac2012-10-11 16:44:48 +0900111 all_branches = {}
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700112 project_cnt = len(projects)
Chris McDonald8add6232020-12-09 14:27:59 -0700113 with multiprocessing.Pool(processes=opt.jobs) as pool:
114 project_branches = pool.imap_unordered(
115 expand_project_to_branches, projects, chunksize=WORKER_BATCH_SIZE)
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700116
Chris McDonald8add6232020-12-09 14:27:59 -0700117 for name, b in itertools.chain.from_iterable(project_branches):
David Pursehouse5c6eeac2012-10-11 16:44:48 +0900118 if name not in all_branches:
119 all_branches[name] = BranchInfo(name)
120 all_branches[name].add(b)
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700121
Chris McDonald8add6232020-12-09 14:27:59 -0700122 names = sorted(all_branches)
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700123
Shawn O. Pearce4e3d6732009-04-18 15:18:35 -0700124 if not names:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700125 print(' (no branches)', file=sys.stderr)
Shawn O. Pearce4e3d6732009-04-18 15:18:35 -0700126 return
127
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700128 width = 25
129 for name in names:
130 if width < len(name):
131 width = len(name)
132
133 for name in names:
David Pursehouse5c6eeac2012-10-11 16:44:48 +0900134 i = all_branches[name]
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700135 in_cnt = len(i.projects)
136
137 if i.IsCurrent:
138 current = '*'
139 hdr = out.current
140 else:
141 current = ' '
142 hdr = out.local
143
144 if i.IsPublishedEqual:
145 published = 'P'
146 elif i.IsPublished:
147 published = 'p'
148 else:
149 published = ' '
150
151 hdr('%c%c %-*s' % (current, published, width, name))
152 out.write(' |')
153
Pär Åsfältff6929d2009-09-05 23:10:56 +0200154 if in_cnt < project_cnt:
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700155 fmt = out.write
156 paths = []
Etan Cohen588142d2014-07-09 21:33:31 -0700157 non_cur_paths = []
158 if i.IsSplitCurrent or (in_cnt < project_cnt - in_cnt):
David Pursehouse8a68ff92012-09-24 12:15:13 +0900159 in_type = 'in'
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700160 for b in i.projects:
Etan Cohen588142d2014-07-09 21:33:31 -0700161 if not i.IsSplitCurrent or b.current:
162 paths.append(b.project.relpath)
163 else:
164 non_cur_paths.append(b.project.relpath)
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700165 else:
166 fmt = out.notinproject
David Pursehouse8a68ff92012-09-24 12:15:13 +0900167 in_type = 'not in'
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700168 have = set()
169 for b in i.projects:
170 have.add(b.project)
171 for p in projects:
David Pursehouseeeff3532020-02-12 11:24:10 +0900172 if p not in have:
Pär Åsfältff6929d2009-09-05 23:10:56 +0200173 paths.append(p.relpath)
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700174
David Pursehouse8a68ff92012-09-24 12:15:13 +0900175 s = ' %s %s' % (in_type, ', '.join(paths))
Etan Cohen588142d2014-07-09 21:33:31 -0700176 if not i.IsSplitCurrent and (width + 7 + len(s) < 80):
177 fmt = out.current if i.IsCurrent else fmt
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700178 fmt(s)
179 else:
David Pursehouse8a68ff92012-09-24 12:15:13 +0900180 fmt(' %s:' % in_type)
Etan Cohen588142d2014-07-09 21:33:31 -0700181 fmt = out.current if i.IsCurrent else out.write
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700182 for p in paths:
183 out.nl()
David Pursehouse54a4e602020-02-12 14:31:05 +0900184 fmt(width * ' ' + ' %s' % p)
Etan Cohen588142d2014-07-09 21:33:31 -0700185 fmt = out.write
186 for p in non_cur_paths:
187 out.nl()
David Pursehouse54a4e602020-02-12 14:31:05 +0900188 fmt(width * ' ' + ' %s' % p)
Pär Åsfältff6929d2009-09-05 23:10:56 +0200189 else:
190 out.write(' in all projects')
Shawn O. Pearce27b07322009-04-10 16:02:48 -0700191 out.nl()
Chris McDonald8add6232020-12-09 14:27:59 -0700192
193
194def expand_project_to_branches(project):
195 """Expands a project into a list of branch names & associated information.
196
197 Args:
198 project: project.Project
199
200 Returns:
201 List[Tuple[str, git_config.Branch]]
202 """
203 branches = []
204 for name, b in project.GetBranches().items():
205 b.project = project
206 branches.append((name, b))
207 return branches