From 6214af8a8d74066e6ba0c36dd0c4e57c395f4117 Mon Sep 17 00:00:00 2001 From: Jan Zeleny Date: Mon, 20 Dec 2010 15:42:04 +0100 Subject: Changed concept of ipa help The concept is now following: topic: either a module or a group of modules containing registered commands. All these commands will usually handle common entity type (e.g. hbac rules) subtopic: each topic can have a number of subtopics. In this case topic is a group of modules and each module represents a subtopic. grouping modules to topics is possible by assigning a 2-tuple to module variable: topic = ('topic-name','topic description') The topic description has to be the same in all modules in the topic. These are examples of commands now available in IPA help: ipa help - display a list of all topics ipa help hbac - display help for hbac topic ipa help hbacrule - display help for a subtopic of hbac ipa help hbacrule-add - display help for a particular command https://fedorahosted.org/freeipa/ticket/410 --- ipalib/cli.py | 117 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 20 deletions(-) (limited to 'ipalib') diff --git a/ipalib/cli.py b/ipalib/cli.py index 2ac3926f3..436607f27 100644 --- a/ipalib/cli.py +++ b/ipalib/cli.py @@ -619,8 +619,26 @@ class help(frontend.Local): end = r.find('.', start) return r[start:end] + def _get_module_topic(self, module_name): + if not sys.modules[module_name]: + __import__(module_name) + module = sys.modules[module_name] + + dir_list = dir(module) + if 'topic' in dir_list: + topic = module.topic + else: + topic = (self._get_command_module(module_name), None) + + return topic + + def _count_topic_mcl(self, topic_name, mod_name): + mcl = max((self._topics[topic_name][1], len(mod_name))) + self._topics[topic_name][1] = mcl + def finalize(self): - # {plugin_module: [mcl, commands]} + # {topic: ["description", mcl, {"subtopic": ["description", mcl, [commands]]}]} + # {topic: ["description", mcl, [commands]]} self._topics = {} # [builtin_commands] self._builtins = [] @@ -629,12 +647,35 @@ class help(frontend.Local): for c in self.Command(): if c.INTERNAL: continue - topic = self._get_command_module(c.module) - if topic: - self._topics.setdefault(topic, [0]).append(c) - # compute maximum length of command in topic - mcl = max((self._topics[topic][0], len(c.name))) - self._topics[topic][0] = mcl + + topic = self._get_module_topic(c.module) + topic_name = topic[0] + + if topic_name: + if topic[1] is None: # a module without grouping + if topic_name in self._topics: + self._topics[topic_name][2].append(c) + else: + m = '%s.%s' % (self._PLUGIN_BASE_MODULE, topic_name) + doc = (sys.modules[m].__doc__ or '').strip().split('\n', 1)[0] + self._topics[topic_name] = [doc, 0, [c]] + mcl = max((self._topics[topic_name][1], len(c.name))) + self._topics[topic_name][1] = mcl + else: # a module grouped in a topic + doc = (sys.modules[c.module].__doc__ or '').strip().split('\n', 1)[0] + mod_name = c.module.rsplit('.',1)[1] + if topic_name in self._topics: + if mod_name in self._topics[topic_name][2]: + self._topics[topic_name][2][mod_name][2].append(c) + else: + self._topics[topic_name][2][mod_name] = [doc, 0, [c]] + self._count_topic_mcl(topic_name, mod_name) + # count mcl for for the subtopic + mcl = max((self._topics[topic_name][2][mod_name][1], len(c.name))) + self._topics[topic_name][2][mod_name][1] = mcl + else: + self._topics[topic_name] = [topic[1], 0, {mod_name: [doc, 0, [c]]}] + self._count_topic_mcl(topic_name, mod_name) else: self._builtins.append(c) @@ -647,6 +688,7 @@ class help(frontend.Local): def run(self, key): name = from_cli(key) + mod_name = '%s.%s' % (self._PLUGIN_BASE_MODULE, name) if key is None or name == "topics": self.print_topics() return @@ -656,6 +698,8 @@ class help(frontend.Local): cmd = self.Command[name] print 'Purpose: %s' % cmd.doc self.Backend.cli.build_parser(cmd).print_help() + elif mod_name in sys.modules: + self.print_commands(name) elif name == "commands": mcl = max(len(s) for s in (self.Command)) for cname in self.Command: @@ -673,28 +717,61 @@ class help(frontend.Local): print '' print 'Built-in commands:' for c in self._builtins: + print 'Help subtopics:' print ' %s %s' % (to_cli(c.name).ljust(self._mtl), c.summary) print '' print 'Help topics:' for t in topics: - m = '%s.%s' % (self._PLUGIN_BASE_MODULE, t) - doc = (sys.modules[m].__doc__ or '').strip().split('\n', 1)[0] - print ' %s %s' % (to_cli(t).ljust(self._mtl), doc) + topic = self._topics[t] + print ' %s %s' % (to_cli(t).ljust(self._mtl), topic[0]) + + if False: + topic_commands = self._topics[t][2] + mod_list = [self._get_command_module(c.module) for c in topic_commands] + mod_list = list(set(mod_list)) + + for mod in mod_list: + m = '%s.%s' % (self._PLUGIN_BASE_MODULE, mod) + if 'topic' in dir(sys.modules[m]): + doc = sys.modules[m].topic[1] + else: + doc = (sys.modules[m].__doc__ or '').strip().split('\n', 1)[0] + print ' %s %s' % (to_cli(t).ljust(self._mtl), doc) print '' print 'Try `ipa --help` for a list of global options.' def print_commands(self, topic): - mcl = self._topics[topic][0] - commands = self._topics[topic][1:] - m = '%s.%s' % (self._PLUGIN_BASE_MODULE, topic) - doc = (sys.modules[m].__doc__ or '').strip() + if topic in self._topics and type(self._topics[topic][2]) is dict: + # we want to display topic which has subtopics + for subtopic in self._topics[topic][2]: + doc = self._topics[topic][2][subtopic][0] + mcl = self._topics[topic][1] + print ' %s %s' % (to_cli(subtopic).ljust(mcl), doc) + else: + # we want to display subtopic or a topic which has no subtopics + if topic in self._topics: + mcl = self._topics[topic][1] + commands = self._topics[topic][2] + else: + for t in self._topics: + if type(self._topics[t][2]) is not dict: + continue + if topic not in self._topics[t][2]: + continue + mcl = self._topics[t][2][topic][1] + commands = self._topics[t][2][topic][2] + break + + m = '%s.%s' % (self._PLUGIN_BASE_MODULE, topic) + doc = (sys.modules[m].__doc__ or '').strip() - print doc - print '' - if len(commands) > 1: - print 'Topic commands:' - for c in commands: - print ' %s %s' % (to_cli(c.name).ljust(mcl), c.summary) + print doc + print '' + if len(commands) > 1: + print 'Topic commands:' + for c in commands: + print ' %s %s' % (to_cli(c.name).ljust(mcl), c.summary) + print "\n" class console(frontend.Command): -- cgit