diff options
author | Jan-Piet Mens <jpmens@gmail.com> | 2012-11-28 09:39:26 +0100 |
---|---|---|
committer | Michael DeHaan <michael.dehaan@gmail.com> | 2012-11-30 21:57:25 -0500 |
commit | 17f31a2a7974e861a6d9530e50bd89ab9db11816 (patch) | |
tree | 6a23672a1fbeca22185df0797cac0c7c7c9ced0e /bin | |
parent | b8d6dec5ad0320d9a5642647f30d6c4edd050250 (diff) | |
download | ansible-17f31a2a7974e861a6d9530e50bd89ab9db11816.tar.gz |
CLI: ansible-doc shows lists of modules & module docs on command-line
check path is directory
added manpage & setup
small cleanup
shut up module_formatter in utils to avoid trace print on crud files in library
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/ansible-doc | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/bin/ansible-doc b/bin/ansible-doc new file mode 100755 index 0000000000..c82b3b1095 --- /dev/null +++ b/bin/ansible-doc @@ -0,0 +1,203 @@ +#!/usr/bin/env python + +# (c) 2012, Jan-Piet Mens <jpmens () gmail.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +import os +import sys +import yaml +import json +import ast +import textwrap +import re +import optparse +import time +import datetime +from ansible import utils +from ansible import errors +from ansible.utils import module_docs +import ansible.constants as C + +MODULEDIR = C.DEFAULT_MODULE_PATH + +_ITALIC = re.compile(r"I\(([^)]+)\)") +_BOLD = re.compile(r"B\(([^)]+)\)") +_MODULE = re.compile(r"M\(([^)]+)\)") +_URL = re.compile(r"U\(([^)]+)\)") +_CONST = re.compile(r"C\(([^)]+)\)") + +def tty_ify(text): + + t = _ITALIC.sub("`" + r"\1" + "'", text) # I(word) => `word' + t = _BOLD.sub("*" + r"\1" + "*", t) # B(word) => *word* + t = _MODULE.sub("[" + r"\1" + "]", t) # M(word) => [word] + t = _URL.sub(r"\1", t) # U(word) => word + t = _CONST.sub("`" + r"\1" + "'", t) # C(word) => `word' + + return t + +def print_man(doc): + + opt_indent=" " + print "> %s\n" % doc['module'].upper() + + desc = "".join(doc['description']) + + print "%s\n" % textwrap.fill(tty_ify(desc), initial_indent=" ", subsequent_indent=" ") + + print "Options (= is mandatory):\n" + + for o in doc['option_keys']: + opt = doc['options'][o] + + if opt.get('required', False): + opt_leadin = "=" + else: + opt_leadin = "-" + + print "%s %s" % (opt_leadin, o) + desc = "".join(opt['description']) + + if 'choices' in opt: + choices = ", ".join(opt['choices']) + desc = desc + " (Choices: " + choices + ")" + print "%s\n" % textwrap.fill(tty_ify(desc), initial_indent=opt_indent, + subsequent_indent=opt_indent) + + if 'notes' in doc: + notes = "".join(doc['notes']) + print "Notes:%s\n" % textwrap.fill(tty_ify(notes), initial_indent=" ", + subsequent_indent=opt_indent) + + + for ex in doc['examples']: + print "%s%s" % (opt_indent, ex['code']) + +def print_snippet(doc): + + desc = tty_ify("".join(doc['short_description'])) + print "- name: %s" % (desc) + print " action: %s" % (doc['module']) + + for o in doc['options']: + opt = doc['options'][o] + desc = tty_ify("".join(opt['description'])) + s = o + "=" + print " %-20s # %s" % (s, desc[0:60]) + +def main(): + + p = optparse.OptionParser( + version='%prog 1.0', + usage='usage: %prog [options] [module...]', + description='Show Ansible module documentation', + ) + + p.add_option("-M", "--module-path", + action="store", + dest="module_path", + default=MODULEDIR, + help="Ansible modules/ directory") + p.add_option("-l", "--list", + action="store_true", + default=False, + dest='list_dir', + help='List available modules') + p.add_option("-s", "--snippet", + action="store_true", + default=False, + dest='show_snippet', + help='Show playbook snippet for specified module(s)') + p.add_option('-v', action='version', help='Show version number and exit') + + (options, args) = p.parse_args() + + if options.module_path is not None: + utils.plugins.vars_loader.add_directory(options.module_path) + + if options.list_dir: + # list all modules + paths = utils.plugins.module_finder._get_paths() + module_list = [] + for path in paths: + # os.system("ls -C %s" % (path)) + if os.path.isdir(path): + for module in os.listdir(path): + module_list.append(module) + + for module in sorted(module_list): + + if module in module_docs.BLACKLIST_MODULES: + continue + + filename = utils.plugins.module_finder.find_plugin(module) + try: + doc = utils.module_docs.get_docstring(filename) + desc = tty_ify(doc.get('short_description', '?')) + if len(desc) > 55: + desc = desc + '...' + print "%-20s %-60.60s" % (module, desc) + except: + sys.stderr.write("ERROR: module %s missing documentation\n" % module) + pass + + sys.exit() + + module_list = [] + + if len(args) == 0: + p.print_help() + + for module in args: + + filename = utils.plugins.module_finder.find_plugin(module) + if filename is None: + sys.stderr.write("module %s not found in %s\n" % (module, + utils.plugins.module_finder.print_paths())) + continue + + if filename.endswith(".swp"): + continue + + try: + doc = utils.module_docs.get_docstring(filename) + except: + sys.stderr.write("ERROR: module %s missing documentation\n" % module) + continue + + if not doc is None: + + all_keys = [] + for (k,v) in doc['options'].iteritems(): + all_keys.append(k) + all_keys = sorted(all_keys) + doc['option_keys'] = all_keys + + doc['filename'] = filename + doc['docuri'] = doc['module'].replace('_', '-') + doc['now_date'] = datetime.date.today().strftime('%Y-%m-%d') + + if options.show_snippet: + print_snippet(doc) + else: + print_man(doc) + else: + sys.stderr.write("ERROR: module %s missing documentation\n" % module) + +if __name__ == '__main__': + main() |