summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xipa4
-rw-r--r--ipalib/cli.py117
-rw-r--r--tests/test_ipalib/test_cli.py105
3 files changed, 125 insertions, 101 deletions
diff --git a/ipa b/ipa
index 9fb302017..39ab81a33 100755
--- a/ipa
+++ b/ipa
@@ -31,5 +31,7 @@ from ipalib.cli import CLI
api.load_plugins()
if __name__ == '__main__':
- cli = CLI(api)
+ cli = CLI(api,
+ (s.decode('utf-8') for s in sys.args[1:])
+ )
sys.exit(cli.run())
diff --git a/ipalib/cli.py b/ipalib/cli.py
index a802f8ef0..21b02299e 100644
--- a/ipalib/cli.py
+++ b/ipalib/cli.py
@@ -84,6 +84,24 @@ class help(frontend.Application):
print 'Purpose: %s' % cmd.doc
self.application.build_parser(cmd).print_help()
+ def print_commands(self):
+ std = set(self.api.Command) - set(self.api.Application)
+ print '\nStandard IPA commands:'
+ for key in sorted(std):
+ cmd = self.api.Command[key]
+ self.print_cmd(cmd)
+ print '\nSpecial CLI commands:'
+ for cmd in self.api.Application():
+ self.print_cmd(cmd)
+ print '\nUse the --help option to see all the global options'
+ print ''
+
+ def print_cmd(self, cmd):
+ print ' %s %s' % (
+ to_cli(cmd.name).ljust(self.mcl),
+ cmd.doc,
+ )
+
class console(frontend.Application):
'Start the IPA interactive Python console.'
@@ -207,32 +225,24 @@ class CLI(object):
__d = None
__mcl = None
- def __init__(self, api):
- self.__api = api
- self.__all_interactive = False
- self.__not_interactive = False
+ def __init__(self, api, argv):
+ self.api = api
+ self.argv = tuple(argv)
+ self.__done = set()
- def __get_api(self):
- return self.__api
- api = property(__get_api)
+ def __doing(self, name):
+ if name in self.__done:
+ raise StandardError(
+ '%s.%s() already called' % (self.__class__.__name__, name)
+ )
+ self.__done.add(name)
- def print_commands(self):
- std = set(self.api.Command) - set(self.api.Application)
- print '\nStandard IPA commands:'
- for key in sorted(std):
- cmd = self.api.Command[key]
- self.print_cmd(cmd)
- print '\nSpecial CLI commands:'
- for cmd in self.api.Application():
- self.print_cmd(cmd)
- print '\nUse the --help option to see all the global options'
- print ''
+ def __do_if_not_done(self, name):
+ if name not in self.__done:
+ getattr(self, name)()
- def print_cmd(self, cmd):
- print ' %s %s' % (
- to_cli(cmd.name).ljust(self.mcl),
- cmd.doc,
- )
+ def isdone(self, name):
+ return name in self.__done
def __contains__(self, key):
assert self.__d is not None, 'you must call finalize() first'
@@ -360,10 +370,11 @@ class CLI(object):
parser.add_option(o)
return parser
- def parse_globals(self, argv=sys.argv[1:]):
+ def parse_globals(self):
+ self.__doing('parse_globals')
parser = optparse.OptionParser()
parser.disable_interspersed_args()
- parser.add_option('-a', dest='interactive', action='store_true',
+ parser.add_option('-a', dest='prompt_all', action='store_true',
help='Prompt for all missing options interactively')
parser.add_option('-n', dest='interactive', action='store_false',
help='Don\'t prompt for any options interactively')
@@ -373,29 +384,39 @@ class CLI(object):
help='Specify or override environment variables')
parser.add_option('-v', dest='verbose', action='store_true',
help='Verbose output')
- (options, args) = parser.parse_args(argv)
-
- if options.interactive == True:
- self.__all_interactive = True
- elif options.interactive == False:
- self.__not_interactive = True
- if options.verbose != None:
- self.api.env.verbose = True
- if options.environment:
- env_dict = {}
- for a in options.environment.split(','):
- a = a.split('=', 1)
- if len(a) < 2:
- parser.error('badly specified environment string,'\
- 'use var1=val1[,var2=val2]..')
- env_dict[a[0].strip()] = a[1].strip()
- self.api.env.update(env_dict, True)
- if options.config_file:
- self.api.env.update(read_config(options.config_file), True)
- else:
- self.api.env.update(read_config(), True)
-
- return args
+ parser.set_defaults(
+ prompt_all=False,
+ interactive=True,
+ verbose=False,
+ )
+ (options, args) = parser.parse_args(list(self.argv))
+ self.options = options
+ self.cmd_argv = tuple(args)
+
+ def bootstrap(self):
+ pass
+
+# if options.interactive == True:
+# self.__all_interactive = True
+# elif options.interactive == False:
+# self.__not_interactive = True
+# if options.verbose != None:
+# self.api.env.verbose = True
+# if options.environment:
+# env_dict = {}
+# for a in options.environment.split(','):
+# a = a.split('=', 1)
+# if len(a) < 2:
+# parser.error('badly specified environment string,'\
+# 'use var1=val1[,var2=val2]..')
+# env_dict[a[0].strip()] = a[1].strip()
+# self.api.env.update(env_dict, True)
+# if options.config_file:
+# self.api.env.update(read_config(options.config_file), True)
+# else:
+# self.api.env.update(read_config(), True)
+
+# return args
def get_usage(self, cmd):
return ' '.join(self.get_usage_iter(cmd))
diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py
index 50bfb932f..10f239897 100644
--- a/tests/test_ipalib/test_cli.py
+++ b/tests/test_ipalib/test_cli.py
@@ -22,7 +22,7 @@ Test the `ipalib.cli` module.
"""
from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker
-from ipalib import cli, plugable
+from ipalib import cli, plugable, frontend, backend
def test_to_cli():
@@ -81,60 +81,61 @@ class test_CLI(ClassChecker):
"""
_cls = cli.CLI
- def test_class(self):
- """
- Test the `ipalib.cli.CLI` class.
- """
- assert type(self.cls.api) is property
-
- def test_api(self):
- """
- Test the `ipalib.cli.CLI.api` property.
- """
- api = 'the plugable.API instance'
- o = self.cls(api)
- assert read_only(o, 'api') is api
-
- def dont_parse(self):
- """
- Test the `ipalib.cli.CLI.parse` method.
- """
- o = self.cls(None)
- args = ['hello', 'naughty', 'nurse']
- kw = dict(
- first_name='Naughty',
- last_name='Nurse',
+ def new(self, argv):
+ api = plugable.API(
+ frontend.Command,
+ frontend.Object,
+ frontend.Method,
+ frontend.Property,
+ frontend.Application,
+ backend.Backend,
)
- opts = ['--%s=%s' % (k.replace('_', '-'), v) for (k, v) in kw.items()]
- assert o.parse(args + []) == (args, {})
- assert o.parse(opts + []) == ([], kw)
- assert o.parse(args + opts) == (args, kw)
- assert o.parse(opts + args) == (args, kw)
+ o = self.cls(api, argv)
+ assert o.api is api
+ return o
- def test_mcl(self):
+ def test_init(self):
"""
- Test the `ipalib.cli.CLI.mcl` property .
+ Test the `ipalib.cli.CLI.__init__` method.
"""
- cnt = 100
- api = DummyAPI(cnt)
- len(api.Command) == cnt
- o = self.cls(api)
- assert o.mcl is None
- o.build_map()
- assert o.mcl == 6 # len('cmd_99')
-
- def test_dict(self):
+ argv = ['-v', 'user-add', '--first=Jonh', '--last=Doe']
+ o = self.new(argv)
+ assert type(o.api) is plugable.API
+ assert o.argv == tuple(argv)
+
+ def test_parse_globals(self):
"""
- Test container emulation of `ipalib.cli.CLI` class.
+ Test the `ipalib.cli.CLI.parse_globals` method.
"""
- cnt = 25
- api = DummyAPI(cnt)
- assert len(api.Command) == cnt
- o = self.cls(api)
- o.build_map()
- for cmd in api.Command():
- key = cli.to_cli(cmd.name)
- assert key in o
- assert o[key] is cmd
- assert cmd.name not in o
- raises(KeyError, getitem, o, cmd.name)
+ # Test with empty argv
+ o = self.new([])
+ assert not hasattr(o, 'options')
+ assert not hasattr(o, 'cmd_argv')
+ assert o.isdone('parse_globals') is False
+ o.parse_globals()
+ assert o.isdone('parse_globals') is True
+ assert o.options.interactive is True
+ assert o.options.verbose is False
+ assert o.options.config_file is None
+ assert o.options.environment is None
+ assert o.cmd_argv == tuple()
+ e = raises(StandardError, o.parse_globals)
+ assert str(e) == 'CLI.parse_globals() already called'
+
+ # Test with a populated argv
+ argv = ('-a', '-n', '-v', '-c', '/my/config.conf', '-e', 'my_key=my_val')
+ cmd_argv = ('user-add', '--first', 'John', '--last', 'Doe')
+ o = self.new(argv + cmd_argv)
+ assert not hasattr(o, 'options')
+ assert not hasattr(o, 'cmd_argv')
+ assert o.isdone('parse_globals') is False
+ o.parse_globals()
+ assert o.isdone('parse_globals') is True
+ assert o.options.prompt_all is True
+ assert o.options.interactive is False
+ assert o.options.verbose is True
+ assert o.options.config_file == '/my/config.conf'
+ assert o.options.environment == 'my_key=my_val'
+ assert o.cmd_argv == cmd_argv
+ e = raises(StandardError, o.parse_globals)
+ assert str(e) == 'CLI.parse_globals() already called'