# 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, WORKER_BATCH_SIZE 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 [...] 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