summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2009-04-10 16:02:48 -0700
committerShawn O. Pearce <sop@google.com>2009-04-10 16:02:48 -0700
commit27b07327bc9f4bcda2c29422e064bced092759e3 (patch)
tree3eeee2ebd7314a35e9fadb317912791eecb8dbdf
parent02d7945eb836f33f63b94fb2a556c844faf0ef8d (diff)
downloadgit-repo-27b07327bc9f4bcda2c29422e064bced092759e3.tar.gz
Add a repo branches subcommand to describe current branches
We now display a summary of the available topic branches in this client, based upon a sorted union of all existing projects. Bug: REPO-21 Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r--project.py26
-rw-r--r--subcmds/branches.py150
2 files changed, 176 insertions, 0 deletions
diff --git a/project.py b/project.py
index 24254676..4f560bd6 100644
--- a/project.py
+++ b/project.py
@@ -306,6 +306,32 @@ class Project(object):
306 """ 306 """
307 return self.config.GetBranch(name) 307 return self.config.GetBranch(name)
308 308
309 def GetBranches(self):
310 """Get all existing local branches.
311 """
312 current = self.CurrentBranch
313 all = self.bare_git.ListRefs()
314 heads = {}
315 pubd = {}
316
317 for name, id in all.iteritems():
318 if name.startswith(R_HEADS):
319 name = name[len(R_HEADS):]
320 b = self.GetBranch(name)
321 b.current = name == current
322 b.published = None
323 b.revision = id
324 heads[name] = b
325
326 for name, id in all.iteritems():
327 if name.startswith(R_PUB):
328 name = name[len(R_PUB):]
329 b = heads.get(name)
330 if b:
331 b.published = id
332
333 return heads
334
309 335
310## Status Display ## 336## Status Display ##
311 337
diff --git a/subcmds/branches.py b/subcmds/branches.py
new file mode 100644
index 00000000..d5a0812f
--- /dev/null
+++ b/subcmds/branches.py
@@ -0,0 +1,150 @@
1#
2# Copyright (C) 2009 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import sys
17from color import Coloring
18from command import Command
19
20class BranchColoring(Coloring):
21 def __init__(self, config):
22 Coloring.__init__(self, config, 'branch')
23 self.current = self.printer('current', fg='green')
24 self.local = self.printer('local')
25 self.notinproject = self.printer('notinproject', fg='red')
26
27class BranchInfo(object):
28 def __init__(self, name):
29 self.name = name
30 self.current = 0
31 self.published = 0
32 self.published_equal = 0
33 self.projects = []
34
35 def add(self, b):
36 if b.current:
37 self.current += 1
38 if b.published:
39 self.published += 1
40 if b.revision == b.published:
41 self.published_equal += 1
42 self.projects.append(b)
43
44 @property
45 def IsCurrent(self):
46 return self.current > 0
47
48 @property
49 def IsPublished(self):
50 return self.published > 0
51
52 @property
53 def IsPublishedEqual(self):
54 return self.published_equal == len(self.projects)
55
56
57class Branches(Command):
58 common = True
59 helpSummary = "View current topic branches"
60 helpUsage = """
61%prog [<project>...]
62
63Summarizes the currently available topic branches.
64"""
65
66 def _Options(self, p):
67 p.add_option('-a', '--all',
68 dest='all', action='store_true',
69 help='show all branches, not just the majority')
70
71 def Execute(self, opt, args):
72 projects = self.GetProjects(args)
73 out = BranchColoring(self.manifest.manifestProject.config)
74 all = {}
75 project_cnt = len(projects)
76
77 for project in projects:
78 for name, b in project.GetBranches().iteritems():
79 b.project = project
80 if name not in all:
81 all[name] = BranchInfo(name)
82 all[name].add(b)
83
84 names = all.keys()
85 names.sort()
86
87 if not opt.all and not args:
88 # No -a and no specific projects listed; try to filter the
89 # results down to only the majority of projects.
90 #
91 n = []
92 for name in names:
93 i = all[name]
94 if i.IsCurrent \
95 or 80 <= (100 * len(i.projects)) / project_cnt:
96 n.append(name)
97 names = n
98
99 width = 25
100 for name in names:
101 if width < len(name):
102 width = len(name)
103
104 for name in names:
105 i = all[name]
106 in_cnt = len(i.projects)
107
108 if i.IsCurrent:
109 current = '*'
110 hdr = out.current
111 else:
112 current = ' '
113 hdr = out.local
114
115 if i.IsPublishedEqual:
116 published = 'P'
117 elif i.IsPublished:
118 published = 'p'
119 else:
120 published = ' '
121
122 hdr('%c%c %-*s' % (current, published, width, name))
123 out.write(' |')
124
125 if in_cnt < project_cnt and (in_cnt == 1 or opt.all):
126 fmt = out.write
127 paths = []
128 if in_cnt < project_cnt - in_cnt:
129 type = 'in'
130 for b in i.projects:
131 paths.append(b.project.relpath)
132 else:
133 fmt = out.notinproject
134 type = 'not in'
135 have = set()
136 for b in i.projects:
137 have.add(b.project)
138 for p in projects:
139 paths.append(p.relpath)
140
141 s = ' %s %s' % (type, ', '.join(paths))
142 if width + 7 + len(s) < 80:
143 fmt(s)
144 else:
145 out.nl()
146 fmt(' %s:' % type)
147 for p in paths:
148 out.nl()
149 fmt(' %s' % p)
150 out.nl()