blob: e1e2009465a64112d3c4cf5264e728e0bf541956 [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):
20 """ChromiteCmd constructor."""
21 super(ChromiteCmd, self).__init__()
22
23
24 def Run(self, raw_argv, chroot_config=None):
25 """Run the command.
26
27 All subclasses must implement this.
28
29 Args:
30 raw_argv: Command line arguments, including this command's name, but not
31 the chromite command name or chromite options.
32 chroot_config: A SafeConfigParser for the chroot config; or None chromite
33 was called from within the chroot.
34 """
35 # Must be implemented by subclass...
36 raise NotImplementedError()
Doug Andersona9b10902011-02-01 17:54:31 -080037
38
39class WrappedChrootCmd(ChromiteCmd):
40 """Superclass for any command that is simply wrapped by chromite.
41
42 These are commands where:
43 - We parse the command line only enough to figure out what board they
44 want. All othe command line parsing is handled by the wrapped command.
45 Because of this, the board name _needs_ to be specified first.
46 - Everything else (arg parsing, help, etc) is handled by the wrapped command.
47 The usage string will be a little messed up, but hopefully that's OK.
48 """
49
50 def __init__(self, target_cmd, host_cmd, need_args=False):
51 """WrappedChrootCmd constructor.
52
53 Args:
54 target_cmd: We'll put this at the start of argv when calling a target
55 command. We'll substiture %s with the target.
56 Like - ['my_command-%s'] or ['my_command', '--board=%s']
57 host_cmd: We'll put this at the start of argv when calling a host command.
58 Like - ['my_command'] or ['sudo', 'my_command']
59 need_args: If True, we'll prompt for arguments if they weren't specified.
60 This makes the most sense when someone runs chromite with no arguments
61 and then walks through the menus. It's not ideal, but less sucky than
62 just quitting.
63 """
64 # Call superclass constructor.
65 super(WrappedChrootCmd, self).__init__()
66
67 # Save away params for use later in Run().
68 self._target_cmd = target_cmd
69 self._host_cmd = host_cmd
70 self._need_args = need_args
71
72 def Run(self, raw_argv, chroot_config=None, argv=None, build_config=None):
73 """Run the command.
74
75 Args:
76 raw_argv: Command line arguments, including this command's name, but not
77 the chromite command name or chromite options.
78 chroot_config: A SafeConfigParser for the chroot config; or None chromite
79 was called from within the chroot.
80 argv: None when called normally, but contains argv with board stripped off
81 if we call ourselves with utils.EnterChroot().
82 build_config: None when called normally, but contains the SafeConfigParser
83 for the build config if we call ourselves with utils.EnterChroot().
84 Note that even when called through utils.EnterChroot(), could still
85 be None if user chose 'HOST' as the target.
86 """
87 # If we didn't get called through EnterChroot, we need to read the build
88 # config.
89 if argv is None:
90 # We look for the build config without calling OptionParser. This means
91 # that the board _needs_ to be first (if it's specified) and all options
92 # will be passed straight to our subcommand.
93 argv, build_config = utils.GetBuildConfigFromArgs(raw_argv[1:])
94
95 # Enter the chroot if needed...
96 if not cros_lib.IsInsideChroot():
97 utils.EnterChroot(chroot_config, (self, 'Run'), raw_argv, argv=argv,
98 build_config=build_config)
99 else:
100 # We'll put CWD as src/scripts when running the command. Since everyone
101 # running by hand has their cwd there, it is probably the safest.
102 cwd = os.path.join(utils.SRCROOT_PATH, 'src', 'scripts')
103
104 # Get command to call. If build_config is None, it means host.
105 if build_config is None:
106 argv_prefix = self._host_cmd
107 else:
108 # Make argv_prefix w/ target.
109 target_name = build_config.get('BUILD', 'target')
110 argv_prefix = [arg % target_name for arg in self._target_cmd]
111
112 # Not a great way to to specify arguments, but works for now... Wrapped
113 # commands are not wonderful interfaces anyway...
114 if self._need_args and not argv:
115 while True:
116 sys.stderr.write('arg %d (blank to exit): ' % (len(argv)+1))
117 arg = raw_input()
118 if not arg:
119 break
120 argv.append(arg)
121
122 # Add the prefix...
123 argv = argv_prefix + argv
124
125 # Run, ignoring errors since some commands (ahem, cros_workon) seem to
126 # return errors from things like --help.
127 cros_lib.RunCommand(argv, cwd=cwd, ignore_sigint=True, error_ok=True)