blob: 0a4ef9819333efa9dee592b0ef36cbb878b40ee0 [file] [log] [blame]
Doug Anderson4b6d3962011-01-21 09:41:50 -08001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""ChromiteCmd abstract class and related functions."""
6
Doug Andersona9b10902011-02-01 17:54:31 -08007# Python imports
8import os
9import sys
10
11# Local imports
12import chromite.lib.cros_build_lib as cros_lib
13from chromite.shell import utils
14
Doug Anderson4b6d3962011-01-21 09:41:50 -080015
16class ChromiteCmd(object):
17 """The abstract base class of commands listed at the top level of chromite."""
18
19 def __init__(self):
Simon Glass21599602011-02-11 13:57:29 -080020 """ChromiteCmd constructor.
21
22 Args:
23 cr: ChromiteEnv object to use for this command
24 """
Doug Anderson4b6d3962011-01-21 09:41:50 -080025 super(ChromiteCmd, self).__init__()
Simon Glass21599602011-02-11 13:57:29 -080026 self.cros_env = None
27
28 def SetChromiteEnv(self, cros_env):
29 """Sets the Chromite environment for this command
30
31 This is split out from __init() since subclasses of ChromiteCmd do not
32 have similar constructors and there are a lot of them, and the number is
33 likely to grow.
34
35 Please call this method after the constructor.
36 """
37 self.cros_env = cros_env
Simon Glass5329b932011-03-14 16:49:04 -070038 self._oper = cros_env.GetOperation()
Doug Anderson4b6d3962011-01-21 09:41:50 -080039
Doug Anderson4b6d3962011-01-21 09:41:50 -080040 def Run(self, raw_argv, chroot_config=None):
41 """Run the command.
42
43 All subclasses must implement this.
44
45 Args:
46 raw_argv: Command line arguments, including this command's name, but not
47 the chromite command name or chromite options.
48 chroot_config: A SafeConfigParser for the chroot config; or None chromite
49 was called from within the chroot.
50 """
51 # Must be implemented by subclass...
52 raise NotImplementedError()
Doug Andersona9b10902011-02-01 17:54:31 -080053
54
55class WrappedChrootCmd(ChromiteCmd):
56 """Superclass for any command that is simply wrapped by chromite.
57
58 These are commands where:
59 - We parse the command line only enough to figure out what board they
60 want. All othe command line parsing is handled by the wrapped command.
61 Because of this, the board name _needs_ to be specified first.
62 - Everything else (arg parsing, help, etc) is handled by the wrapped command.
63 The usage string will be a little messed up, but hopefully that's OK.
64 """
65
Simon Glass5329b932011-03-14 16:49:04 -070066 def __init__(self, name, target_cmd, host_cmd, need_args=False,
67 env_whitelist=None):
Doug Andersona9b10902011-02-01 17:54:31 -080068 """WrappedChrootCmd constructor.
69
70 Args:
Simon Glass5329b932011-03-14 16:49:04 -070071 name: This is a name for the command, displayed to the user.
Doug Andersona9b10902011-02-01 17:54:31 -080072 target_cmd: We'll put this at the start of argv when calling a target
73 command. We'll substiture %s with the target.
74 Like - ['my_command-%s'] or ['my_command', '--board=%s']
75 host_cmd: We'll put this at the start of argv when calling a host command.
76 Like - ['my_command'] or ['sudo', 'my_command']
77 need_args: If True, we'll prompt for arguments if they weren't specified.
78 This makes the most sense when someone runs chromite with no arguments
79 and then walks through the menus. It's not ideal, but less sucky than
80 just quitting.
Doug Anderson143e7032011-02-04 15:05:37 -080081 env_whitelist: This is a whitelist of environment variables that will be
82 read from the current environment and passed through to the command.
83 Note that this doesn't matter much when we start inside the chroot,
84 but matters a lot when we transition into the chroot (since the
85 environment is reset when that happens).
86 Useful for portage commands. Like: ['USE', 'FEATURES']
Doug Andersona9b10902011-02-01 17:54:31 -080087 """
88 # Call superclass constructor.
89 super(WrappedChrootCmd, self).__init__()
90
91 # Save away params for use later in Run().
Simon Glass5329b932011-03-14 16:49:04 -070092 self._name = name
Doug Andersona9b10902011-02-01 17:54:31 -080093 self._target_cmd = target_cmd
94 self._host_cmd = host_cmd
95 self._need_args = need_args
96
Doug Anderson143e7032011-02-04 15:05:37 -080097 # Handle the env_whitelist. We need to do this in __init__ rather than in
98 # Run(), since we want the environment vars from outside the chroot.
Doug Andersona17e0102011-02-07 13:16:55 -080099 if env_whitelist is None:
100 self._env_to_add = {}
101 else:
102 self._env_to_add = dict((key, os.environ[key]) for key in env_whitelist
103 if key in os.environ)
Doug Anderson143e7032011-02-04 15:05:37 -0800104
Doug Andersona9b10902011-02-01 17:54:31 -0800105 def Run(self, raw_argv, chroot_config=None, argv=None, build_config=None):
106 """Run the command.
107
108 Args:
109 raw_argv: Command line arguments, including this command's name, but not
110 the chromite command name or chromite options.
111 chroot_config: A SafeConfigParser for the chroot config; or None chromite
112 was called from within the chroot.
113 argv: None when called normally, but contains argv with board stripped off
114 if we call ourselves with utils.EnterChroot().
115 build_config: None when called normally, but contains the SafeConfigParser
116 for the build config if we call ourselves with utils.EnterChroot().
117 Note that even when called through utils.EnterChroot(), could still
118 be None if user chose 'HOST' as the target.
119 """
120 # If we didn't get called through EnterChroot, we need to read the build
121 # config.
122 if argv is None:
123 # We look for the build config without calling OptionParser. This means
124 # that the board _needs_ to be first (if it's specified) and all options
125 # will be passed straight to our subcommand.
126 argv, build_config = utils.GetBuildConfigFromArgs(raw_argv[1:])
127
128 # Enter the chroot if needed...
129 if not cros_lib.IsInsideChroot():
Simon Glass5329b932011-03-14 16:49:04 -0700130 self._oper.Info('ENTERING THE CHROOT')
Doug Andersona9b10902011-02-01 17:54:31 -0800131 utils.EnterChroot(chroot_config, (self, 'Run'), raw_argv, argv=argv,
132 build_config=build_config)
133 else:
134 # We'll put CWD as src/scripts when running the command. Since everyone
135 # running by hand has their cwd there, it is probably the safest.
136 cwd = os.path.join(utils.SRCROOT_PATH, 'src', 'scripts')
137
138 # Get command to call. If build_config is None, it means host.
139 if build_config is None:
140 argv_prefix = self._host_cmd
141 else:
142 # Make argv_prefix w/ target.
Doug Anderson6f530612011-02-11 13:19:25 -0800143 target_name = build_config.get('DEFAULT', 'target')
Doug Andersona9b10902011-02-01 17:54:31 -0800144 argv_prefix = [arg % target_name for arg in self._target_cmd]
145
146 # Not a great way to to specify arguments, but works for now... Wrapped
147 # commands are not wonderful interfaces anyway...
148 if self._need_args and not argv:
149 while True:
150 sys.stderr.write('arg %d (blank to exit): ' % (len(argv)+1))
151 arg = raw_input()
152 if not arg:
153 break
154 argv.append(arg)
155
156 # Add the prefix...
157 argv = argv_prefix + argv
158
Doug Anderson143e7032011-02-04 15:05:37 -0800159 # Update the environment with anything from the whitelist.
160 env = os.environ.copy()
161 env.update(self._env_to_add)
162
Simon Glass5329b932011-03-14 16:49:04 -0700163 self.cros_env.RunScript(self._name, '', argv, env=env)