branches.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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. from __future__ import print_function
  16. import sys
  17. from color import Coloring
  18. from command import Command
  19. class BranchColoring(Coloring):
  20. def __init__(self, config):
  21. Coloring.__init__(self, config, 'branch')
  22. self.current = self.printer('current', fg='green')
  23. self.local = self.printer('local')
  24. self.notinproject = self.printer('notinproject', fg='red')
  25. class BranchInfo(object):
  26. def __init__(self, name):
  27. self.name = name
  28. self.current = 0
  29. self.published = 0
  30. self.published_equal = 0
  31. self.projects = []
  32. def add(self, b):
  33. if b.current:
  34. self.current += 1
  35. if b.published:
  36. self.published += 1
  37. if b.revision == b.published:
  38. self.published_equal += 1
  39. self.projects.append(b)
  40. @property
  41. def IsCurrent(self):
  42. return self.current > 0
  43. @property
  44. def IsSplitCurrent(self):
  45. return self.current != 0 and self.current != len(self.projects)
  46. @property
  47. def IsPublished(self):
  48. return self.published > 0
  49. @property
  50. def IsPublishedEqual(self):
  51. return self.published_equal == len(self.projects)
  52. class Branches(Command):
  53. common = True
  54. helpSummary = "View current topic branches"
  55. helpUsage = """
  56. %prog [<project>...]
  57. Summarizes the currently available topic branches.
  58. # Branch Display
  59. The branch display output by this command is organized into four
  60. columns of information; for example:
  61. *P nocolor | in repo
  62. repo2 |
  63. The first column contains a * if the branch is the currently
  64. checked out branch in any of the specified projects, or a blank
  65. if no project has the branch checked out.
  66. The second column contains either blank, p or P, depending upon
  67. the upload status of the branch.
  68. (blank): branch not yet published by repo upload
  69. P: all commits were published by repo upload
  70. p: only some commits were published by repo upload
  71. The third column contains the branch name.
  72. The fourth column (after the | separator) lists the projects that
  73. the branch appears in, or does not appear in. If no project list
  74. is shown, then the branch appears in all projects.
  75. """
  76. def Execute(self, opt, args):
  77. projects = self.GetProjects(args)
  78. out = BranchColoring(self.manifest.manifestProject.config)
  79. all_branches = {}
  80. project_cnt = len(projects)
  81. for project in projects:
  82. for name, b in project.GetBranches().items():
  83. b.project = project
  84. if name not in all_branches:
  85. all_branches[name] = BranchInfo(name)
  86. all_branches[name].add(b)
  87. names = list(sorted(all_branches))
  88. if not names:
  89. print(' (no branches)', file=sys.stderr)
  90. return
  91. width = 25
  92. for name in names:
  93. if width < len(name):
  94. width = len(name)
  95. for name in names:
  96. i = all_branches[name]
  97. in_cnt = len(i.projects)
  98. if i.IsCurrent:
  99. current = '*'
  100. hdr = out.current
  101. else:
  102. current = ' '
  103. hdr = out.local
  104. if i.IsPublishedEqual:
  105. published = 'P'
  106. elif i.IsPublished:
  107. published = 'p'
  108. else:
  109. published = ' '
  110. hdr('%c%c %-*s' % (current, published, width, name))
  111. out.write(' |')
  112. if in_cnt < project_cnt:
  113. fmt = out.write
  114. paths = []
  115. non_cur_paths = []
  116. if i.IsSplitCurrent or (in_cnt < project_cnt - in_cnt):
  117. in_type = 'in'
  118. for b in i.projects:
  119. if not i.IsSplitCurrent or b.current:
  120. paths.append(b.project.relpath)
  121. else:
  122. non_cur_paths.append(b.project.relpath)
  123. else:
  124. fmt = out.notinproject
  125. in_type = 'not in'
  126. have = set()
  127. for b in i.projects:
  128. have.add(b.project)
  129. for p in projects:
  130. if not p in have:
  131. paths.append(p.relpath)
  132. s = ' %s %s' % (in_type, ', '.join(paths))
  133. if not i.IsSplitCurrent and (width + 7 + len(s) < 80):
  134. fmt = out.current if i.IsCurrent else fmt
  135. fmt(s)
  136. else:
  137. fmt(' %s:' % in_type)
  138. fmt = out.current if i.IsCurrent else out.write
  139. for p in paths:
  140. out.nl()
  141. fmt(width*' ' + ' %s' % p)
  142. fmt = out.write
  143. for p in non_cur_paths:
  144. out.nl()
  145. fmt(width*' ' + ' %s' % p)
  146. else:
  147. out.write(' in all projects')
  148. out.nl()