Fix command order

When there are two commands: one 'foo', that expects a positional
argument, and a second command 'foo bar'.
Trying to enter the command 'foo bar' will invoke the command
'foo' with position argument 'bar', and not the second command
'foo bar'.
This is due to the fact that the find command method first
checks for the first word as a command.
By trying first to match all arguments this problem is solved.

Closes-Bug: #1618673
Change-Id: I24ea39813ad30ec095ea18baad3a7b088fa8108f
This commit is contained in:
Eyal Posener
2016-08-30 10:09:10 +03:00
parent 4ae7562ff4
commit f55e785448
2 changed files with 28 additions and 8 deletions

View File

@@ -61,14 +61,10 @@ class CommandManager(object):
"""Given an argument list, find a command and
return the processor and any remaining arguments.
"""
search_args = argv[:]
name = ''
while search_args:
if search_args[0].startswith('-'):
name = '%s %s' % (name, search_args[0])
raise ValueError('Invalid command %r' % name)
next_val = search_args.pop(0)
name = '%s %s' % (name, next_val) if name else next_val
start = self._get_last_possible_command_index(argv)
for i in range(start, 0, -1):
name = ' '.join(argv[:i])
search_args = argv[i:]
if name in self.commands:
cmd_ep = self.commands[name]
if hasattr(cmd_ep, 'resolve'):
@@ -85,3 +81,12 @@ class CommandManager(object):
else:
raise ValueError('Unknown command %r' %
(argv,))
def _get_last_possible_command_index(self, argv):
"""Returns the index after the last argument
in argv that can be a command word
"""
for i, arg in enumerate(argv):
if arg.startswith('-'):
return i
return len(argv)

View File

@@ -70,6 +70,21 @@ def test_add_command():
assert found_cmd is mock_cmd
def test_intersected_commands():
def foo(arg):
pass
def foo_bar():
pass
mgr = utils.TestCommandManager(utils.TEST_NAMESPACE)
mgr.add_command('foo', foo)
mgr.add_command('foo bar', foo_bar)
assert mgr.find_command(['foo', 'bar'])[0] is foo_bar
assert mgr.find_command(['foo', 'arg0'])[0] is foo
def test_load_commands():
testcmd = mock.Mock(name='testcmd')
testcmd.name.replace.return_value = 'test'