diff --git a/project.py b/project.py index 2425467..4f560bd 100644 --- a/project.py +++ b/project.py @@ -306,6 +306,32 @@ class Project(object): """ return self.config.GetBranch(name) + def GetBranches(self): + """Get all existing local branches. + """ + current = self.CurrentBranch + all = self.bare_git.ListRefs() + heads = {} + pubd = {} + + for name, id in all.iteritems(): + if name.startswith(R_HEADS): + name = name[len(R_HEADS):] + b = self.GetBranch(name) + b.current = name == current + b.published = None + b.revision = id + heads[name] = b + + for name, id in all.iteritems(): + if name.startswith(R_PUB): + name = name[len(R_PUB):] + b = heads.get(name) + if b: + b.published = id + + return heads + ## Status Display ## diff --git a/subcmds/branches.py b/subcmds/branches.py new file mode 100644 index 0000000..d5a0812 --- /dev/null +++ b/subcmds/branches.py @@ -0,0 +1,150 @@ +# +# 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 sys +from color import Coloring +from command import Command + +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 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 [...] + +Summarizes the currently available topic branches. +""" + + def _Options(self, p): + p.add_option('-a', '--all', + dest='all', action='store_true', + help='show all branches, not just the majority') + + def Execute(self, opt, args): + projects = self.GetProjects(args) + out = BranchColoring(self.manifest.manifestProject.config) + all = {} + project_cnt = len(projects) + + for project in projects: + for name, b in project.GetBranches().iteritems(): + b.project = project + if name not in all: + all[name] = BranchInfo(name) + all[name].add(b) + + names = all.keys() + names.sort() + + if not opt.all and not args: + # No -a and no specific projects listed; try to filter the + # results down to only the majority of projects. + # + n = [] + for name in names: + i = all[name] + if i.IsCurrent \ + or 80 <= (100 * len(i.projects)) / project_cnt: + n.append(name) + names = n + + width = 25 + for name in names: + if width < len(name): + width = len(name) + + for name in names: + i = all[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 and (in_cnt == 1 or opt.all): + fmt = out.write + paths = [] + if in_cnt < project_cnt - in_cnt: + type = 'in' + for b in i.projects: + paths.append(b.project.relpath) + else: + fmt = out.notinproject + type = 'not in' + have = set() + for b in i.projects: + have.add(b.project) + for p in projects: + paths.append(p.relpath) + + s = ' %s %s' % (type, ', '.join(paths)) + if width + 7 + len(s) < 80: + fmt(s) + else: + out.nl() + fmt(' %s:' % type) + for p in paths: + out.nl() + fmt(' %s' % p) + out.nl()