add support for legacy command name translation

Add add_legacy_command() method to the command manager and update the
command search logic to try translating the old legacy name to the new
name.

Change-Id: I0c0cdbfcb1612ec3975864fc7f730ff186879027
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
Doug Hellmann 2017-11-22 15:09:18 -05:00
parent c471e7a92a
commit c6fc228a25
2 changed files with 70 additions and 2 deletions

View File

@ -45,13 +45,15 @@ class CommandManager(object):
"""
def __init__(self, namespace, convert_underscores=True):
self.commands = {}
self._legacy = {}
self.namespace = namespace
self.convert_underscores = convert_underscores
self._load_commands()
def _load_commands(self):
# NOTE(jamielennox): kept for compatibility.
self.load_commands(self.namespace)
if self.namespace:
self.load_commands(self.namespace)
def load_commands(self, namespace):
"""Load all the commands from an entrypoint"""
@ -69,6 +71,17 @@ class CommandManager(object):
def add_command(self, name, command_class):
self.commands[name] = EntryPointWrapper(name, command_class)
def add_legacy_command(self, old_name, new_name):
"""Map an old command name to the new name.
:param old_name: The old command name.
:type old_name: str
:param new_name: The new command name.
:type new_name: str
"""
self._legacy[old_name] = new_name
def find_command(self, argv):
"""Given an argument list, find a command and
return the processor and any remaining arguments.
@ -77,6 +90,12 @@ class CommandManager(object):
for i in range(start, 0, -1):
name = ' '.join(argv[:i])
search_args = argv[i:]
# The legacy command handling may modify name, so remember
# the value we actually found in argv so we can return it.
return_name = name
# Convert the legacy command name to its new name.
if name in self._legacy:
name = self._legacy[name]
if name in self.commands:
cmd_ep = self.commands[name]
if hasattr(cmd_ep, 'resolve'):
@ -89,7 +108,7 @@ class CommandManager(object):
cmd_factory = cmd_ep.load(require=False)
else:
cmd_factory = cmd_ep.load()
return (cmd_factory, name, search_args)
return (cmd_factory, return_name, search_args)
else:
raise ValueError('Unknown command %r' %
(argv,))

View File

@ -13,6 +13,7 @@
import mock
import testscenarios
from cliff import command
from cliff import commandmanager
from cliff.tests import base
from cliff.tests import utils
@ -150,3 +151,51 @@ class TestLoad(base.TestBase):
iter_entry_points.assert_called_once_with('test')
names = [n for n, v in mgr]
self.assertEqual(['test cmd'], names)
class FauxCommand(command.Command):
def take_action(self, parsed_args):
return 0
class FauxCommand2(FauxCommand):
pass
class TestLegacyCommand(base.TestBase):
def test_find_legacy(self):
mgr = utils.TestCommandManager(None)
mgr.add_command('new name', FauxCommand)
mgr.add_legacy_command('old name', 'new name')
cmd, name, remaining = mgr.find_command(['old', 'name'])
self.assertIs(cmd, FauxCommand)
self.assertEqual(name, 'old name')
def test_legacy_overrides_new(self):
mgr = utils.TestCommandManager(None)
mgr.add_command('cmd1', FauxCommand)
mgr.add_command('cmd2', FauxCommand2)
mgr.add_legacy_command('cmd2', 'cmd1')
cmd, name, remaining = mgr.find_command(['cmd2'])
self.assertIs(cmd, FauxCommand)
self.assertEqual(name, 'cmd2')
def test_no_legacy(self):
mgr = utils.TestCommandManager(None)
mgr.add_command('cmd1', FauxCommand)
self.assertRaises(
ValueError,
mgr.find_command,
['cmd2'],
)
def test_no_command(self):
mgr = utils.TestCommandManager(None)
mgr.add_legacy_command('cmd2', 'cmd1')
self.assertRaises(
ValueError,
mgr.find_command,
['cmd2'],
)