blob: babb83389185d5e68057ffbf40892c7ab4bf17bf [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001#
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
16import os
17import optparse
Conley Owensd21720d2012-04-16 11:02:21 -070018import platform
Colin Cross5acde752012-03-28 20:15:45 -070019import re
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070020import sys
21
22from error import NoSuchProjectError
Colin Cross5acde752012-03-28 20:15:45 -070023from error import InvalidProjectGroupsError
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070024
25class Command(object):
26 """Base class for any command line action in repo.
27 """
28
29 common = False
30 manifest = None
31 _optparse = None
32
Shawn O. Pearcedb45da12009-04-18 13:49:13 -070033 def WantPager(self, opt):
34 return False
35
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070036 @property
37 def OptionParser(self):
38 if self._optparse is None:
39 try:
40 me = 'repo %s' % self.NAME
41 usage = self.helpUsage.strip().replace('%prog', me)
42 except AttributeError:
43 usage = 'repo %s' % self.NAME
44 self._optparse = optparse.OptionParser(usage = usage)
45 self._Options(self._optparse)
46 return self._optparse
47
48 def _Options(self, p):
49 """Initialize the option parser.
50 """
51
52 def Usage(self):
53 """Display usage and terminate.
54 """
55 self.OptionParser.print_usage()
56 sys.exit(1)
57
58 def Execute(self, opt, args):
59 """Perform the action, after option parsing is complete.
60 """
61 raise NotImplementedError
Conley Owens971de8e2012-04-16 10:36:08 -070062
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070063 def GetProjects(self, args, missing_ok=False):
64 """A list of projects that match the arguments.
65 """
David Pursehouse8a68ff92012-09-24 12:15:13 +090066 all_projects = self.manifest.projects
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070067 result = []
68
Colin Cross5acde752012-03-28 20:15:45 -070069 mp = self.manifest.manifestProject
70
71 groups = mp.config.GetString('manifest.groups')
Colin Crossc39864f2012-04-23 13:41:58 -070072 if not groups:
Conley Owensbb1b5f52012-08-13 13:11:18 -070073 groups = 'all,-notdefault,platform-' + platform.system().lower()
David Pursehouse1d947b32012-10-25 12:23:11 +090074 groups = [x for x in re.split(r'[,\s]+', groups) if x]
Colin Cross5acde752012-03-28 20:15:45 -070075
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070076 if not args:
Shawn O. Pearcecd81dd62012-10-26 12:18:00 -070077 for project in all_projects.values():
Colin Cross5acde752012-03-28 20:15:45 -070078 if ((missing_ok or project.Exists) and
79 project.MatchesGroups(groups)):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070080 result.append(project)
81 else:
Shawn O. Pearcecd81dd62012-10-26 12:18:00 -070082 by_path = None
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070083
84 for arg in args:
David Pursehouse8a68ff92012-09-24 12:15:13 +090085 project = all_projects.get(arg)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070086
87 if not project:
Anthony Newnamdf14a702011-01-09 17:31:57 -080088 path = os.path.abspath(arg).replace('\\', '/')
Shawn O. Pearcecd81dd62012-10-26 12:18:00 -070089
90 if not by_path:
91 by_path = dict()
92 for p in all_projects.values():
93 by_path[p.worktree] = p
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070094
Shawn O. Pearcecd81dd62012-10-26 12:18:00 -070095 if os.path.exists(path):
96 oldpath = None
97 while path \
98 and path != oldpath \
99 and path != self.manifest.topdir:
100 try:
101 project = by_path[path]
102 break
103 except KeyError:
104 oldpath = path
105 path = os.path.dirname(path)
106 else:
107 try:
108 project = by_path[path]
109 except KeyError:
110 pass
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700111
112 if not project:
113 raise NoSuchProjectError(arg)
114 if not missing_ok and not project.Exists:
115 raise NoSuchProjectError(arg)
Colin Cross5acde752012-03-28 20:15:45 -0700116 if not project.MatchesGroups(groups):
117 raise InvalidProjectGroupsError(arg)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700118
119 result.append(project)
120
121 def _getpath(x):
122 return x.relpath
123 result.sort(key=_getpath)
124 return result
125
David Pursehouse4f7bdea2012-10-22 12:50:15 +0900126# pylint: disable=W0223
David Pursehouse5c6eeac2012-10-11 16:44:48 +0900127# Pylint warns that the `InteractiveCommand` and `PagedCommand` classes do not
128# override method `Execute` which is abstract in `Command`. Since that method
129# is always implemented in classes derived from `InteractiveCommand` and
130# `PagedCommand`, this warning can be suppressed.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700131class InteractiveCommand(Command):
132 """Command which requires user interaction on the tty and
133 must not run within a pager, even if the user asks to.
134 """
Shawn O. Pearcedb45da12009-04-18 13:49:13 -0700135 def WantPager(self, opt):
136 return False
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700137
138class PagedCommand(Command):
139 """Command which defaults to output in a pager, as its
140 display tends to be larger than one screen full.
141 """
Shawn O. Pearcedb45da12009-04-18 13:49:13 -0700142 def WantPager(self, opt):
143 return True
Shawn O. Pearcec95583b2009-03-03 17:47:06 -0800144
David Pursehouse4f7bdea2012-10-22 12:50:15 +0900145# pylint: enable=W0223
David Pursehouse5c6eeac2012-10-11 16:44:48 +0900146
Shawn O. Pearcec95583b2009-03-03 17:47:06 -0800147class MirrorSafeCommand(object):
148 """Command permits itself to run within a mirror,
149 and does not require a working directory.
150 """