blob: 724e4c5d5e9a8fbc4c0608aa57ca924ae721c81c [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
Colin Cross5acde752012-03-28 20:15:45 -070018import re
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070019import sys
20
21from error import NoSuchProjectError
Colin Cross5acde752012-03-28 20:15:45 -070022from error import InvalidProjectGroupsError
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070023
24class Command(object):
25 """Base class for any command line action in repo.
26 """
27
28 common = False
29 manifest = None
30 _optparse = None
31
Shawn O. Pearcedb45da12009-04-18 13:49:13 -070032 def WantPager(self, opt):
33 return False
34
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070035 @property
36 def OptionParser(self):
37 if self._optparse is None:
38 try:
39 me = 'repo %s' % self.NAME
40 usage = self.helpUsage.strip().replace('%prog', me)
41 except AttributeError:
42 usage = 'repo %s' % self.NAME
43 self._optparse = optparse.OptionParser(usage = usage)
44 self._Options(self._optparse)
45 return self._optparse
46
47 def _Options(self, p):
48 """Initialize the option parser.
49 """
50
51 def Usage(self):
52 """Display usage and terminate.
53 """
54 self.OptionParser.print_usage()
55 sys.exit(1)
56
57 def Execute(self, opt, args):
58 """Perform the action, after option parsing is complete.
59 """
60 raise NotImplementedError
61
62 def GetProjects(self, args, missing_ok=False):
63 """A list of projects that match the arguments.
64 """
65 all = self.manifest.projects
66 result = []
67
Colin Cross5acde752012-03-28 20:15:45 -070068 mp = self.manifest.manifestProject
69
70 groups = mp.config.GetString('manifest.groups')
71 if groups:
72 groups = re.split('[,\s]+', groups)
73
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070074 if not args:
75 for project in all.values():
Colin Cross5acde752012-03-28 20:15:45 -070076 if ((missing_ok or project.Exists) and
77 project.MatchesGroups(groups)):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070078 result.append(project)
79 else:
80 by_path = None
81
82 for arg in args:
83 project = all.get(arg)
84
85 if not project:
Anthony Newnamdf14a702011-01-09 17:31:57 -080086 path = os.path.abspath(arg).replace('\\', '/')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070087
88 if not by_path:
89 by_path = dict()
90 for p in all.values():
91 by_path[p.worktree] = p
92
93 if os.path.exists(path):
Anthony Newnamdf14a702011-01-09 17:31:57 -080094 oldpath = None
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070095 while path \
Anthony Newnamdf14a702011-01-09 17:31:57 -080096 and path != oldpath \
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070097 and path != self.manifest.topdir:
98 try:
99 project = by_path[path]
100 break
101 except KeyError:
Anthony Newnamdf14a702011-01-09 17:31:57 -0800102 oldpath = path
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700103 path = os.path.dirname(path)
104 else:
105 try:
106 project = by_path[path]
107 except KeyError:
108 pass
109
110 if not project:
111 raise NoSuchProjectError(arg)
112 if not missing_ok and not project.Exists:
113 raise NoSuchProjectError(arg)
Colin Cross5acde752012-03-28 20:15:45 -0700114 if not project.MatchesGroups(groups):
115 raise InvalidProjectGroupsError(arg)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700116
117 result.append(project)
118
119 def _getpath(x):
120 return x.relpath
121 result.sort(key=_getpath)
122 return result
123
124class InteractiveCommand(Command):
125 """Command which requires user interaction on the tty and
126 must not run within a pager, even if the user asks to.
127 """
Shawn O. Pearcedb45da12009-04-18 13:49:13 -0700128 def WantPager(self, opt):
129 return False
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700130
131class PagedCommand(Command):
132 """Command which defaults to output in a pager, as its
133 display tends to be larger than one screen full.
134 """
Shawn O. Pearcedb45da12009-04-18 13:49:13 -0700135 def WantPager(self, opt):
136 return True
Shawn O. Pearcec95583b2009-03-03 17:47:06 -0800137
138class MirrorSafeCommand(object):
139 """Command permits itself to run within a mirror,
140 and does not require a working directory.
141 """