command.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #
  2. # Copyright (C) 2008 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. import os
  16. import optparse
  17. import platform
  18. import re
  19. import sys
  20. from error import NoSuchProjectError
  21. from error import InvalidProjectGroupsError
  22. class Command(object):
  23. """Base class for any command line action in repo.
  24. """
  25. common = False
  26. manifest = None
  27. _optparse = None
  28. def WantPager(self, opt):
  29. return False
  30. @property
  31. def OptionParser(self):
  32. if self._optparse is None:
  33. try:
  34. me = 'repo %s' % self.NAME
  35. usage = self.helpUsage.strip().replace('%prog', me)
  36. except AttributeError:
  37. usage = 'repo %s' % self.NAME
  38. self._optparse = optparse.OptionParser(usage = usage)
  39. self._Options(self._optparse)
  40. return self._optparse
  41. def _Options(self, p):
  42. """Initialize the option parser.
  43. """
  44. def Usage(self):
  45. """Display usage and terminate.
  46. """
  47. self.OptionParser.print_usage()
  48. sys.exit(1)
  49. def Execute(self, opt, args):
  50. """Perform the action, after option parsing is complete.
  51. """
  52. raise NotImplementedError
  53. def GetProjects(self, args, missing_ok=False):
  54. """A list of projects that match the arguments.
  55. """
  56. all_projects = self.manifest.projects
  57. result = []
  58. mp = self.manifest.manifestProject
  59. groups = mp.config.GetString('manifest.groups')
  60. if not groups:
  61. groups = 'all,-notdefault,platform-' + platform.system().lower()
  62. groups = [x for x in re.split(r'[,\s]+', groups) if x]
  63. if not args:
  64. for project in all_projects.values():
  65. if ((missing_ok or project.Exists) and
  66. project.MatchesGroups(groups)):
  67. result.append(project)
  68. else:
  69. by_path = None
  70. for arg in args:
  71. project = all_projects.get(arg)
  72. if not project:
  73. path = os.path.abspath(arg).replace('\\', '/')
  74. if not by_path:
  75. by_path = dict()
  76. for p in all_projects.values():
  77. by_path[p.worktree] = p
  78. if os.path.exists(path):
  79. oldpath = None
  80. while path \
  81. and path != oldpath \
  82. and path != self.manifest.topdir:
  83. try:
  84. project = by_path[path]
  85. break
  86. except KeyError:
  87. oldpath = path
  88. path = os.path.dirname(path)
  89. else:
  90. try:
  91. project = by_path[path]
  92. except KeyError:
  93. pass
  94. if not project:
  95. raise NoSuchProjectError(arg)
  96. if not missing_ok and not project.Exists:
  97. raise NoSuchProjectError(arg)
  98. if not project.MatchesGroups(groups):
  99. raise InvalidProjectGroupsError(arg)
  100. result.append(project)
  101. def _getpath(x):
  102. return x.relpath
  103. result.sort(key=_getpath)
  104. return result
  105. # pylint: disable=W0223
  106. # Pylint warns that the `InteractiveCommand` and `PagedCommand` classes do not
  107. # override method `Execute` which is abstract in `Command`. Since that method
  108. # is always implemented in classes derived from `InteractiveCommand` and
  109. # `PagedCommand`, this warning can be suppressed.
  110. class InteractiveCommand(Command):
  111. """Command which requires user interaction on the tty and
  112. must not run within a pager, even if the user asks to.
  113. """
  114. def WantPager(self, opt):
  115. return False
  116. class PagedCommand(Command):
  117. """Command which defaults to output in a pager, as its
  118. display tends to be larger than one screen full.
  119. """
  120. def WantPager(self, opt):
  121. return True
  122. # pylint: enable=W0223
  123. class MirrorSafeCommand(object):
  124. """Command permits itself to run within a mirror,
  125. and does not require a working directory.
  126. """