Index: shell/main.py |
diff --git a/shell/main.py b/shell/main.py |
index c847e9df2eb700192777befce68dc526347c6474..5a2f60342a9e9610b0693bbea221af657a4a557e 100755 |
--- a/shell/main.py |
+++ b/shell/main.py |
@@ -93,6 +93,58 @@ def _FindCommand(cmd_name): |
return possible_cmds[choice] |
+def _ParseArguments(parser, argv): |
+ '''Helper function to separate arguments for a main program and sub-command. |
+ |
+ We split arguments into ones we understand, and ones to pass on to |
+ sub-commands. For the former, we put them through the given optparse and |
+ return the result options and sub-command name. For the latter, we just |
+ return a list of options and arguments not intended for us. |
+ |
+ We want to parse only the options that we understand at the top level of |
+ Chromite. Our heuristic here is that anything after the first positional |
+ parameter (which we assume is the command) is ignored at this level, and |
+ is passed down to the command level to handle. |
+ |
+ TODO(sjg): Revisit this to include tolerant option parser instead |
+ http://codereview.chromium.org/6469035/ |
+ |
+ Args: |
+ parser: Option parser. |
+ argv: List of program arguments |
+ |
+ Returns: |
+ options: Top level options (returned from optparse). |
+ cmd_str: Subcommand to run |
+ cmd_args: Arguments intended for subcommands. |
+ ''' |
+ our_args = [] |
+ cmd_args = list(argv) |
+ cmd_str = '' |
+ args = [] # Nothing until we call optparse |
+ while not cmd_str: |
+ if our_args: |
+ (options, args) = parser.parse_args(our_args) |
+ if len(args) > 1: |
+ cmd_str = args[1].lower() |
+ elif cmd_args: |
+ # We don't have a command yet. Transfer a positional arg from from |
+ # cmd_args to our_args to see if that does the trick. We move over any |
+ # options we find also. |
+ while cmd_args: |
+ arg = cmd_args.pop(0) |
+ our_args.append(arg) |
+ if not arg.startswith( '-'): |
+ break |
+ else: |
+ # No more cmd_args to consume. |
+ break |
+ |
+ # We must run the parser, even if it dies due to lack of arguments |
+ if not args: |
+ (options, args) = parser.parse_args(our_args) |
+ return options, cmd_str, cmd_args |
+ |
def main(): |
"""Main function for the chromite shell.""" |
@@ -128,7 +180,7 @@ def main(): |
# Verbose defaults to full for now, just to keep people acclimatized to |
# vast amounts of comforting output. |
- parser.add_option('-v', dest='verbose', default=3, |
+ parser.add_option('-v', dest='verbose', default=3, type='int', |
help='Control verbosity: 0=silent, 1=progress, 3=full') |
parser.add_option('-q', action='store_const', dest='verbose', const=0, |
help='Be quieter (sets verbosity to 1)') |
@@ -138,10 +190,9 @@ def main(): |
help="Chroot spec to use. Can be an absolute path to a spec file " |
"or a substring of a chroot spec name (without .spec suffix)") |
parser.usage = help_str |
- try: |
- (options, args) = parser.parse_args() |
- except: |
- sys.exit(1) |
+ |
+ # Parse the arguments and separate them into top-level and subcmd arguments. |
+ options, cmd_str, cmd_args = _ParseArguments(parser, sys.argv) |
# Set up the cros system. |
cros_env = chromite_env.ChromiteEnv() |
@@ -163,13 +214,6 @@ def main(): |
# Already in the chroot; no need to get config... |
chroot_config = None |
- # Get command and arguments |
- if args: |
- cmd_str = args[0].lower() |
- args = args[1:] |
- else: |
- cmd_str = '' |
- |
# Validate the subcmd, popping a menu if needed. |
cmd_str = _FindCommand(cmd_str) |
oper.Info("Running command '%s'." % cmd_str) |
@@ -179,7 +223,7 @@ def main(): |
cmd_obj = cmd_cls() |
cmd_obj.SetChromiteEnv(cros_env) |
try: |
- cmd_obj.Run([cmd_str] + args, chroot_config=chroot_config) |
+ cmd_obj.Run([cmd_str] + cmd_args, chroot_config=chroot_config) |
# Handle an error in one of the scripts: print a message and exit. |
except chromite_env.ChromiteError, msg: |