From f55e785448ac98a829e1df95d05c34adc3da7757 Mon Sep 17 00:00:00 2001 From: Eyal Posener Date: Tue, 30 Aug 2016 10:09:10 +0300 Subject: [PATCH] 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 --- cliff/commandmanager.py | 21 +++++++++++++-------- cliff/tests/test_commandmanager.py | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/cliff/commandmanager.py b/cliff/commandmanager.py index ec6918a..ff213e5 100644 --- a/cliff/commandmanager.py +++ b/cliff/commandmanager.py @@ -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) diff --git a/cliff/tests/test_commandmanager.py b/cliff/tests/test_commandmanager.py index f131712..ffa7d62 100644 --- a/cliff/tests/test_commandmanager.py +++ b/cliff/tests/test_commandmanager.py @@ -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'