From 8bcd068e876ddd48ae61c1803449d666f5e28ba0 Mon Sep 17 00:00:00 2001 From: Andrey Volkov Date: Wed, 14 Mar 2018 19:30:06 +0300 Subject: Allow finding command by partial name This small improvement helps to decrease the amount of typing. $ openstack resource provider list ... ^ too long? $ alias os=openstack $ os r p l ... ^ much better! Change-Id: I713eab2bd9f949da01c03b65ff16a01de92e3e62 --- cliff/commandmanager.py | 23 +++++++++++++++- cliff/tests/test_commandmanager.py | 54 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) (limited to 'cliff') diff --git a/cliff/commandmanager.py b/cliff/commandmanager.py index a0a9bb3..8ee733d 100644 --- a/cliff/commandmanager.py +++ b/cliff/commandmanager.py @@ -22,6 +22,18 @@ import pkg_resources LOG = logging.getLogger(__name__) +def _get_commands_by_partial_name(args, commands): + n = len(args) + candidates = [] + for command_name in commands: + command_parts = command_name.split() + if len(command_parts) != n: + continue + if all(command_parts[i].startswith(args[i]) for i in range(n)): + candidates.append(command_name) + return candidates + + class EntryPointWrapper(object): """Wrap up a command class already imported to make it look like a plugin. """ @@ -96,8 +108,17 @@ class CommandManager(object): # Convert the legacy command name to its new name. if name in self._legacy: name = self._legacy[name] + + found = None if name in self.commands: - cmd_ep = self.commands[name] + found = name + else: + candidates = _get_commands_by_partial_name( + argv[:i], self.commands) + if len(candidates) == 1: + found = candidates[0] + if found: + cmd_ep = self.commands[found] if hasattr(cmd_ep, 'resolve'): cmd_factory = cmd_ep.resolve() else: diff --git a/cliff/tests/test_commandmanager.py b/cliff/tests/test_commandmanager.py index 5a3f928..fae9d0a 100644 --- a/cliff/tests/test_commandmanager.py +++ b/cliff/tests/test_commandmanager.py @@ -199,3 +199,57 @@ class TestLegacyCommand(base.TestBase): mgr.find_command, ['cmd2'], ) + + +class TestLookupAndFindPartialName(base.TestBase): + + scenarios = [ + ('one-word', {'argv': ['o']}), + ('two-words', {'argv': ['t', 'w']}), + ('three-words', {'argv': ['t', 'w', 'c']}), + ] + + def test(self): + mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) + cmd, name, remaining = mgr.find_command(self.argv) + self.assertTrue(cmd) + self.assertEqual(' '.join(self.argv), name) + self.assertFalse(remaining) + + +class TestGetByPartialName(base.TestBase): + + def setUp(self): + super(TestGetByPartialName, self).setUp() + self.commands = { + 'resource provider list': 1, + 'resource class list': 2, + 'server list': 3, + 'service list': 4} + + def test_no_candidates(self): + self.assertEqual( + [], commandmanager._get_commands_by_partial_name( + ['r', 'p'], self.commands)) + self.assertEqual( + [], commandmanager._get_commands_by_partial_name( + ['r', 'p', 'c'], self.commands)) + + def test_multiple_candidates(self): + self.assertEqual( + 2, len(commandmanager._get_commands_by_partial_name( + ['se', 'li'], self.commands))) + + def test_one_candidate(self): + self.assertEqual( + ['resource provider list'], + commandmanager._get_commands_by_partial_name( + ['r', 'p', 'l'], self.commands)) + self.assertEqual( + ['resource provider list'], + commandmanager._get_commands_by_partial_name( + ['resource', 'provider', 'list'], self.commands)) + self.assertEqual( + ['server list'], + commandmanager._get_commands_by_partial_name( + ['serve', 'l'], self.commands)) -- cgit v1.2.1