branches.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. # -*- coding:utf-8 -*-
  2. #
  3. # Copyright (C) 2009 The Android Open Source Project
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. from __future__ import print_function
  17. import sys
  18. from color import Coloring
  19. from command import Command
  20. class 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. class BranchInfo(object):
  27. def __init__(self, name):
  28. self.name = name
  29. self.current = 0
  30. self.published = 0
  31. self.published_equal = 0
  32. self.projects = []
  33. def add(self, b):
  34. if b.current:
  35. self.current += 1
  36. if b.published:
  37. self.published += 1
  38. if b.revision == b.published:
  39. self.published_equal += 1
  40. self.projects.append(b)
  41. @property
  42. def IsCurrent(self):
  43. return self.current > 0
  44. @property
  45. def IsSplitCurrent(self):
  46. return self.current != 0 and self.current != len(self.projects)
  47. @property
  48. def IsPublished(self):
  49. return self.published > 0
  50. @property
  51. def IsPublishedEqual(self):
  52. return self.published_equal == len(self.projects)
  53. class Branches(Command):
  54. common = True
  55. helpSummary = "View current topic branches"
  56. helpUsage = """
  57. %prog [<project>...]
  58. Summarizes the currently available topic branches.
  59. # Branch Display
  60. The branch display output by this command is organized into four
  61. columns of information; for example:
  62. *P nocolor | in repo
  63. repo2 |
  64. The first column contains a * if the branch is the currently
  65. checked out branch in any of the specified projects, or a blank
  66. if no project has the branch checked out.
  67. The second column contains either blank, p or P, depending upon
  68. the upload status of the branch.
  69. (blank): branch not yet published by repo upload
  70. P: all commits were published by repo upload
  71. p: only some commits were published by repo upload
  72. The third column contains the branch name.
  73. The fourth column (after the | separator) lists the projects that
  74. the branch appears in, or does not appear in. If no project list
  75. is shown, then the branch appears in all projects.
  76. """
  77. def Execute(self, opt, args):
  78. projects = self.GetProjects(args)
  79. out = BranchColoring(self.manifest.manifestProject.config)
  80. all_branches = {}
  81. project_cnt = len(projects)
  82. for project in projects:
  83. for name, b in project.GetBranches().items():
  84. b.project = project
  85. if name not in all_branches:
  86. all_branches[name] = BranchInfo(name)
  87. all_branches[name].add(b)
  88. names = list(sorted(all_branches))
  89. if not names:
  90. print(' (no branches)', file=sys.stderr)
  91. return
  92. width = 25
  93. for name in names:
  94. if width < len(name):
  95. width = len(name)
  96. for name in names:
  97. i = all_branches[name]
  98. in_cnt = len(i.projects)
  99. if i.IsCurrent:
  100. current = '*'
  101. hdr = out.current
  102. else:
  103. current = ' '
  104. hdr = out.local
  105. if i.IsPublishedEqual:
  106. published = 'P'
  107. elif i.IsPublished:
  108. published = 'p'
  109. else:
  110. published = ' '
  111. hdr('%c%c %-*s' % (current, published, width, name))
  112. out.write(' |')
  113. if in_cnt < project_cnt:
  114. fmt = out.write
  115. paths = []
  116. non_cur_paths = []
  117. if i.IsSplitCurrent or (in_cnt < project_cnt - in_cnt):
  118. in_type = 'in'
  119. for b in i.projects:
  120. if not i.IsSplitCurrent or b.current:
  121. paths.append(b.project.relpath)
  122. else:
  123. non_cur_paths.append(b.project.relpath)
  124. else:
  125. fmt = out.notinproject
  126. in_type = 'not in'
  127. have = set()
  128. for b in i.projects:
  129. have.add(b.project)
  130. for p in projects:
  131. if p not in have:
  132. paths.append(p.relpath)
  133. s = ' %s %s' % (in_type, ', '.join(paths))
  134. if not i.IsSplitCurrent and (width + 7 + len(s) < 80):
  135. fmt = out.current if i.IsCurrent else fmt
  136. fmt(s)
  137. else:
  138. fmt(' %s:' % in_type)
  139. fmt = out.current if i.IsCurrent else out.write
  140. for p in paths:
  141. out.nl()
  142. fmt(width * ' ' + ' %s' % p)
  143. fmt = out.write
  144. for p in non_cur_paths:
  145. out.nl()
  146. fmt(width * ' ' + ' %s' % p)
  147. else:
  148. out.write(' in all projects')
  149. out.nl()