Merge pull request #44 from mesosphere/refactor-cmd-execution
Refactor cmd execution
This commit is contained in:
49
dcos/api/cmds.py
Normal file
49
dcos/api/cmds.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import collections
|
||||
|
||||
from dcos.api import errors
|
||||
|
||||
Command = collections.namedtuple(
|
||||
'Command',
|
||||
['hierarchy', 'arg_keys', 'function'])
|
||||
"""Describe a CLI command.
|
||||
|
||||
:param hierarchy: the noun and verbs that need to be set for the command to
|
||||
execute
|
||||
:type hierarchy: list of str
|
||||
:param arg_keys: the arguments that must get passed to the function; the order
|
||||
of the keys determines the order in which they get passed to
|
||||
the function
|
||||
:type arg_keys: list of str
|
||||
:param function: the function to execute
|
||||
:type function: func(args) -> int
|
||||
"""
|
||||
|
||||
|
||||
def execute(cmds, args):
|
||||
"""Executes one of the commands based on the arguments passed.
|
||||
|
||||
:param cmds: commands to try to execute; the order determines the order of
|
||||
evaluation
|
||||
:type cmds: list of Command
|
||||
:param args: command line arguments
|
||||
:type args: dict
|
||||
:returns: the process status
|
||||
:rtype: (int, dcos.errors.Error)
|
||||
"""
|
||||
|
||||
for hierarchy, arg_keys, function in cmds:
|
||||
# Let's find if the function matches the command
|
||||
match = True
|
||||
for positional in hierarchy:
|
||||
if not args[positional]:
|
||||
match = False
|
||||
|
||||
if match:
|
||||
params = [args[name] for name in arg_keys]
|
||||
return (function(*params), None)
|
||||
|
||||
return (
|
||||
None,
|
||||
errors.DefaultError(
|
||||
'Could not find a command with the passed arguments')
|
||||
)
|
||||
@@ -41,8 +41,8 @@ import sys
|
||||
|
||||
import docopt
|
||||
import pkg_resources
|
||||
from dcos.api import (config, constants, emitting, errors, jsonitem, marathon,
|
||||
options, util)
|
||||
from dcos.api import (cmds, config, constants, emitting, errors, jsonitem,
|
||||
marathon, options, util)
|
||||
|
||||
logger = util.get_logger(__name__)
|
||||
emitter = emitting.FlatEmitter()
|
||||
@@ -62,39 +62,63 @@ def main():
|
||||
emitter.publish(options.make_generic_usage_error(__doc__))
|
||||
return 1
|
||||
|
||||
if args['info']:
|
||||
return _info()
|
||||
returncode, err = cmds.execute(_cmds(), args)
|
||||
if err is not None:
|
||||
emitter.publish(err)
|
||||
emitter.publish(options.make_generic_usage_error(__doc__))
|
||||
return 1
|
||||
|
||||
if args['add']:
|
||||
return _add()
|
||||
return returncode
|
||||
|
||||
if args['version'] and args['list']:
|
||||
return _version_list(args['<app-id>'], args['--max-count'])
|
||||
|
||||
if args['list']:
|
||||
return _list()
|
||||
def _cmds():
|
||||
"""
|
||||
:returns: all the supported commands
|
||||
:rtype: dcos.api.cmds.Command
|
||||
"""
|
||||
|
||||
if args['remove']:
|
||||
return _remove(args['<app-id>'], args['--force'])
|
||||
return [
|
||||
cmds.Command(hierarchy=['info'], arg_keys=[], function=_info),
|
||||
|
||||
if args['show']:
|
||||
return _show(args['<app-id>'], args['--app-version'])
|
||||
cmds.Command(hierarchy=['add'], arg_keys=[], function=_add),
|
||||
|
||||
if args['start']:
|
||||
return _start(args['<app-id>'], args['<instances>'], args['--force'])
|
||||
cmds.Command(
|
||||
hierarchy=['version', 'list'],
|
||||
arg_keys=['<app-id>', '--max-count'],
|
||||
function=_version_list),
|
||||
|
||||
if args['stop']:
|
||||
return _stop(args['<app-id>'], args['--force'])
|
||||
cmds.Command(hierarchy=['list'], arg_keys=[], function=_list),
|
||||
|
||||
if args['update']:
|
||||
return _update(args['<app-id>'], args['<properties>'], args['--force'])
|
||||
cmds.Command(
|
||||
hierarchy=['remove'],
|
||||
arg_keys=['<app-id>', '--force'],
|
||||
function=_remove),
|
||||
|
||||
if args['restart']:
|
||||
return _restart(args['<app-id>'], args['--force'])
|
||||
cmds.Command(
|
||||
hierarchy=['show'],
|
||||
arg_keys=['<app-id>', '--app-version'],
|
||||
function=_show),
|
||||
|
||||
emitter.publish(options.make_generic_usage_error(__doc__))
|
||||
cmds.Command(
|
||||
hierarchy=['start'],
|
||||
arg_keys=['<app-id>', '<instances>', '--force'],
|
||||
function=_start),
|
||||
|
||||
return 1
|
||||
cmds.Command(
|
||||
hierarchy=['stop'],
|
||||
arg_keys=['<app-id>', '--force'],
|
||||
function=_stop),
|
||||
|
||||
cmds.Command(
|
||||
hierarchy=['update'],
|
||||
arg_keys=['<app-id>', '<properties>', '--force'],
|
||||
function=_update),
|
||||
|
||||
cmds.Command(
|
||||
hierarchy=['restart'],
|
||||
arg_keys=['<app-id>', '--force'],
|
||||
function=_restart),
|
||||
]
|
||||
|
||||
|
||||
def _info():
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
API Documentation
|
||||
=================
|
||||
|
||||
The :mod:`dcos.api.cmds` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: dcos.api.cmds
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
||||
The :mod:`dcos.api.config` Module
|
||||
---------------------------------
|
||||
|
||||
|
||||
100
tests/test_cmds.py
Normal file
100
tests/test_cmds.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import pytest
|
||||
from dcos.api import cmds, errors
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def args():
|
||||
return {
|
||||
'cmd-a': True,
|
||||
'cmd-b': True,
|
||||
'cmd-c': False,
|
||||
'arg-1': 'arg-1',
|
||||
'arg-2': 'arg-2',
|
||||
'arg-0': 'arg-0',
|
||||
}
|
||||
|
||||
|
||||
def test_single_cmd(args):
|
||||
commands = [
|
||||
cmds.Command(
|
||||
hierarchy=['cmd-a', 'cmd-b'],
|
||||
arg_keys=['arg-0', 'arg-1', 'arg-2'],
|
||||
function=function),
|
||||
]
|
||||
|
||||
assert cmds.execute(commands, args) == (1, None)
|
||||
|
||||
|
||||
def test_multiple_cmd(args):
|
||||
commands = [
|
||||
cmds.Command(
|
||||
hierarchy=['cmd-c'],
|
||||
arg_keys=['arg-0', 'arg-1', 'arg-2'],
|
||||
function=pytest.fail),
|
||||
cmds.Command(
|
||||
hierarchy=['cmd-a', 'cmd-b'],
|
||||
arg_keys=['arg-0', 'arg-1', 'arg-2'],
|
||||
function=function),
|
||||
]
|
||||
|
||||
assert cmds.execute(commands, args) == (1, None)
|
||||
|
||||
|
||||
def test_no_matching_cmd(args):
|
||||
commands = [
|
||||
cmds.Command(
|
||||
hierarchy=['cmd-c'],
|
||||
arg_keys=['arg-0', 'arg-1', 'arg-2'],
|
||||
function=pytest.fail),
|
||||
]
|
||||
|
||||
returncode, err = cmds.execute(commands, args)
|
||||
|
||||
assert returncode is None
|
||||
assert isinstance(err, errors.Error)
|
||||
|
||||
|
||||
def test_similar_cmds(args):
|
||||
commands = [
|
||||
cmds.Command(
|
||||
hierarchy=['cmd-a', 'cmd-b'],
|
||||
arg_keys=['arg-0', 'arg-1', 'arg-2'],
|
||||
function=function),
|
||||
cmds.Command(
|
||||
hierarchy=['cmd-a'],
|
||||
arg_keys=['arg-0', 'arg-1', 'arg-2'],
|
||||
function=pytest.fail),
|
||||
]
|
||||
|
||||
assert cmds.execute(commands, args) == (1, None)
|
||||
|
||||
|
||||
def test_missing_cmd(args):
|
||||
commands = [
|
||||
cmds.Command(
|
||||
hierarchy=['cmd-d'],
|
||||
arg_keys=['arg-0', 'arg-1', 'arg-2'],
|
||||
function=pytest.fail),
|
||||
]
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
returncode, err = cmds.execute(commands, args)
|
||||
|
||||
|
||||
def test_missing_arg(args):
|
||||
commands = [
|
||||
cmds.Command(
|
||||
hierarchy=['cmd-a'],
|
||||
arg_keys=['arg-3'],
|
||||
function=pytest.fail),
|
||||
]
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
returncode, err = cmds.execute(commands, args)
|
||||
|
||||
|
||||
def function(*args):
|
||||
for i in range(len(args)):
|
||||
assert args[i] == 'arg-{}'.format(i)
|
||||
|
||||
return 1
|
||||
Reference in New Issue
Block a user