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
This commit is contained in:
Andrey Volkov
2018-03-14 19:30:06 +03:00
parent fa5303f058
commit 8bcd068e87
2 changed files with 76 additions and 1 deletions

View File

@@ -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:

View File

@@ -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))