blob: 26242705617efa5c7b1795c6692a9fe41d2fc46e [file] [log] [blame]
Doug Andersonf0c73952011-01-18 13:46:07 -08001#!/usr/bin/python
Doug Andersone91900d2011-01-26 11:37:17 -08002#
3# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Doug Andersonf0c73952011-01-18 13:46:07 -08004# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
Doug Andersone91900d2011-01-26 11:37:17 -08007"""Main file for the chromite shell."""
Doug Andersonf0c73952011-01-18 13:46:07 -08008
9# Python imports
Simon Glassf4616ab2011-03-30 13:19:16 -070010import optparse
Doug Andersonf0c73952011-01-18 13:46:07 -080011import os
12import sys
Doug Andersonf0c73952011-01-18 13:46:07 -080013
14
Doug Anderson4b6d3962011-01-21 09:41:50 -080015# Local imports
Doug Andersone91900d2011-01-26 11:37:17 -080016from chromite.lib import text_menu
Doug Andersona9b10902011-02-01 17:54:31 -080017import chromite.lib.cros_build_lib as cros_lib
18from chromite.shell import utils
19from chromite.shell.subcmds import build_cmd
20from chromite.shell.subcmds import clean_cmd
21from chromite.shell.subcmds import portage_cmds
22from chromite.shell.subcmds import shell_cmd
23from chromite.shell.subcmds import workon_cmd
Simon Glass21599602011-02-11 13:57:29 -080024from chromite.shell import chromite_env
25from chromite.lib import operation
Doug Andersonf0c73952011-01-18 13:46:07 -080026
27
Doug Andersona9b10902011-02-01 17:54:31 -080028# Define command handlers and command strings.
Doug Andersonf0c73952011-01-18 13:46:07 -080029#
30# ORDER MATTERS here when we show the menu.
Doug Andersonf0c73952011-01-18 13:46:07 -080031_COMMAND_HANDLERS = [
Doug Andersona9b10902011-02-01 17:54:31 -080032 build_cmd.BuildCmd,
33 clean_cmd.CleanCmd,
34 portage_cmds.EbuildCmd,
35 portage_cmds.EmergeCmd,
36 portage_cmds.EqueryCmd,
37 portage_cmds.PortageqCmd,
38 shell_cmd.ShellCmd,
39 workon_cmd.WorkonCmd,
Doug Andersonf0c73952011-01-18 13:46:07 -080040]
Doug Andersona9b10902011-02-01 17:54:31 -080041_COMMAND_STRS = [cls.__name__[:-len('Cmd')].lower()
42 for cls in _COMMAND_HANDLERS]
Doug Andersonf0c73952011-01-18 13:46:07 -080043
44
45def _FindCommand(cmd_name):
46 """Find the command that matches the given command name.
47
48 This tries to be smart. See the cmd_name parameter for details.
49
50 Args:
51 cmd_name: Can be any of the following:
52 1. The full name of a command. This is checked first so that if one
53 command name is a substring of another, you can still specify
54 the shorter spec name and know you won't get a menu (the exact
55 match prevents the menu).
56 2. A _prefix_ that will be used to pare-down a menu of commands
57 Can be the empty string to show a menu of all commands
58
59 Returns:
60 The command name.
61 """
62 # Always make cmd_name lower. Commands are case-insensitive.
63 cmd_name = cmd_name.lower()
64
65 # If we're an exact match, we're done!
66 if cmd_name in _COMMAND_STRS:
67 return cmd_name
68
69 # Find ones that match and put them in a menu...
70 possible_cmds = []
71 possible_choices = []
72 for cmd_num, this_cmd in enumerate(_COMMAND_STRS):
73 if this_cmd.startswith(cmd_name):
Doug Andersona9b10902011-02-01 17:54:31 -080074 handler = _COMMAND_HANDLERS[cmd_num]
Doug Andersonf0c73952011-01-18 13:46:07 -080075 assert hasattr(handler, '__doc__'), \
76 ('All handlers must have docstrings: %s' % cmd_name)
77 desc = handler.__doc__.splitlines()[0]
78
79 possible_cmds.append(this_cmd)
80 possible_choices.append('%s - %s' % (this_cmd, desc))
81
82 if not possible_choices:
Doug Andersona9b10902011-02-01 17:54:31 -080083 cros_lib.Die('No commands matched: "%s". '
Doug Andersonf0c73952011-01-18 13:46:07 -080084 'Try running with no arguments for a menu.' %
85 cmd_name)
86
87 if cmd_name and len(possible_choices) == 1:
88 # Avoid showing the user a menu if the user's search string matched exactly
89 # one item.
90 choice = 0
Doug Andersonf0c73952011-01-18 13:46:07 -080091 else:
92 choice = text_menu.TextMenu(possible_choices, 'Which chromite command',
93 menu_width=0)
94
95 if choice is None:
Doug Andersona9b10902011-02-01 17:54:31 -080096 cros_lib.Die('OK, cancelling...')
Doug Andersonf0c73952011-01-18 13:46:07 -080097 else:
98 return possible_cmds[choice]
99
100
Doug Andersonf0c73952011-01-18 13:46:07 -0800101def main():
Doug Andersona9b10902011-02-01 17:54:31 -0800102 """Main function for the chromite shell."""
103
104 # Hack it so that argv[0] is 'chromite' so that it doesn't tell user to run
105 # 'main.py' in help commands...
106 # TODO(dianders): Remove this hack, since it is ugly. Shouldn't be needed
107 # once we change the way that the chromite wrapper works.
108 sys.argv[0] = 'chromite'
109
110 # Support EnterChroot().
Simon Glass5329b932011-03-14 16:49:04 -0700111 # This may raise a ChromiteError if the child dies, so we must handle this.
112 try:
113 did_resume = utils.ResumeEnterChrootIfNeeded(sys.argv)
114 if did_resume:
115 return
116 except chromite_env.ChromiteError:
117 # The error has been reported, but we must exit indicating failure
118 sys.exit(1)
Doug Andersona9b10902011-02-01 17:54:31 -0800119
Doug Andersonf0c73952011-01-18 13:46:07 -0800120 # TODO(dianders): Make help a little better. Specifically:
121 # 1. Add a command called 'help'
122 # 2. Make the help string below include command list and descriptions (like
123 # the menu, but without being interactive).
124 # 3. Make "help command" and "--help command" equivalent to "command --help".
125 help_str = (
Simon Glassf4616ab2011-03-30 13:19:16 -0700126 """%(prog)s [chromite_options] [cmd [args]]\n"""
Doug Andersonf0c73952011-01-18 13:46:07 -0800127 """\n"""
128 """The chromite script is a wrapper to make it easy to do various\n"""
Simon Glassf4616ab2011-03-30 13:19:16 -0700129 """build tasks. For a list of commands, run without any arguments."""
Doug Andersonf0c73952011-01-18 13:46:07 -0800130 ) % {'prog': os.path.basename(sys.argv[0])}
Simon Glassf4616ab2011-03-30 13:19:16 -0700131
132 parser = optparse.OptionParser()
133
134 # Verbose defaults to full for now, just to keep people acclimatized to
135 # vast amounts of comforting output.
136 parser.add_option('-v', dest='verbose', default=3,
137 help='Control verbosity: 0=silent, 1=progress, 3=full')
138 parser.add_option('-q', action='store_const', dest='verbose', const=0,
139 help='Be quieter (sets verbosity to 1)')
Doug Andersona9b10902011-02-01 17:54:31 -0800140 if not cros_lib.IsInsideChroot():
Simon Glassf4616ab2011-03-30 13:19:16 -0700141 parser.add_option('--chroot', action='store', type='string',
142 dest='chroot_name', default='chroot',
143 help="Chroot spec to use. Can be an absolute path to a spec file "
144 "or a substring of a chroot spec name (without .spec suffix)")
145 parser.usage = help_str
146 try:
147 (options, args) = parser.parse_args()
148 except:
149 sys.exit(1)
Doug Andersonf0c73952011-01-18 13:46:07 -0800150
Simon Glassf4616ab2011-03-30 13:19:16 -0700151 if False: # To preserve indent and minimize changes in this CL
152 pass
Doug Andersonf0c73952011-01-18 13:46:07 -0800153 else:
Simon Glass5329b932011-03-14 16:49:04 -0700154 # Set up the cros system.
155 cros_env = chromite_env.ChromiteEnv()
156
157 # Configure the operation setup.
158 oper = cros_env.GetOperation()
Simon Glassf4616ab2011-03-30 13:19:16 -0700159 oper.verbose = options.verbose >= 3
160 oper.progress = options.verbose >= 1
Simon Glass5329b932011-03-14 16:49:04 -0700161
Doug Andersonf0c73952011-01-18 13:46:07 -0800162 # Look for special "--chroot" argument to allow for alternate chroots
Doug Andersona9b10902011-02-01 17:54:31 -0800163 if not cros_lib.IsInsideChroot():
Simon Glassf4616ab2011-03-30 13:19:16 -0700164 chroot_spec_path = utils.FindSpec(options.chroot_name,
Doug Andersona9b10902011-02-01 17:54:31 -0800165 spec_type=utils.CHROOT_SPEC_TYPE)
Doug Andersonf0c73952011-01-18 13:46:07 -0800166
Simon Glass5329b932011-03-14 16:49:04 -0700167 oper.Info('Using chroot "%s"' % os.path.relpath(chroot_spec_path))
Doug Andersonf0c73952011-01-18 13:46:07 -0800168
Doug Andersona9b10902011-02-01 17:54:31 -0800169 chroot_config = utils.ReadConfig(chroot_spec_path)
Doug Andersonf0c73952011-01-18 13:46:07 -0800170 else:
171 # Already in the chroot; no need to get config...
172 chroot_config = None
173
174 # Get command and arguments
Simon Glassf4616ab2011-03-30 13:19:16 -0700175 if args:
176 cmd_str = args[0].lower()
177 args = args[1:]
Doug Andersonf0c73952011-01-18 13:46:07 -0800178 else:
Doug Anderson4b6d3962011-01-21 09:41:50 -0800179 cmd_str = ''
Doug Andersonf0c73952011-01-18 13:46:07 -0800180
Doug Andersone91900d2011-01-26 11:37:17 -0800181 # Validate the subcmd, popping a menu if needed.
Doug Anderson4b6d3962011-01-21 09:41:50 -0800182 cmd_str = _FindCommand(cmd_str)
Simon Glass5329b932011-03-14 16:49:04 -0700183 oper.Info("Running command '%s'." % cmd_str)
Simon Glass21599602011-02-11 13:57:29 -0800184
Doug Andersonf0c73952011-01-18 13:46:07 -0800185 # Finally, call the function w/ standard argv.
Doug Andersona9b10902011-02-01 17:54:31 -0800186 cmd_cls = _COMMAND_HANDLERS[_COMMAND_STRS.index(cmd_str)]
Doug Anderson4b6d3962011-01-21 09:41:50 -0800187 cmd_obj = cmd_cls()
Simon Glass21599602011-02-11 13:57:29 -0800188 cmd_obj.SetChromiteEnv(cros_env)
Simon Glass5329b932011-03-14 16:49:04 -0700189 try:
Simon Glassf4616ab2011-03-30 13:19:16 -0700190 cmd_obj.Run([cmd_str] + args, chroot_config=chroot_config)
Doug Andersonf0c73952011-01-18 13:46:07 -0800191
Simon Glass5329b932011-03-14 16:49:04 -0700192 # Handle an error in one of the scripts: print a message and exit.
193 except chromite_env.ChromiteError, msg:
194 sys.exit(1)
Doug Andersonf0c73952011-01-18 13:46:07 -0800195
196if __name__ == '__main__':
197 main()