diff --git a/Makefile b/Makefile index 75a418d8b83..1d7a0ff4a73 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ OS = $(shell uname -s) # directory of the target file ($@), kinda like `dirname`. ASCII2MAN = a2x -D $(dir $@) -d manpage -f manpage $< ASCII2HTMLMAN = a2x -D docs/html/man/ -d manpage -f xhtml -MANPAGES := docs/man/man1/ansible.1 docs/man/man1/ansible-playbook.1 docs/man/man1/ansible-pull.1 +MANPAGES := docs/man/man1/ansible.1 docs/man/man1/ansible-playbook.1 docs/man/man1/ansible-pull.1 docs/man/man1/ansible-doc.1 SITELIB = $(shell python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()") diff --git a/bin/ansible-doc b/bin/ansible-doc new file mode 100755 index 00000000000..c82b3b1095b --- /dev/null +++ b/bin/ansible-doc @@ -0,0 +1,203 @@ +#!/usr/bin/env python + +# (c) 2012, Jan-Piet Mens +# +# 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 . +# + +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() diff --git a/docs/man/man1/ansible-doc.1 b/docs/man/man1/ansible-doc.1 new file mode 100644 index 00000000000..edee111ec27 --- /dev/null +++ b/docs/man/man1/ansible-doc.1 @@ -0,0 +1,72 @@ +'\" t +.\" Title: ansible-doc +.\" Author: :doctype:manpage +.\" Generator: DocBook XSL Stylesheets v1.76.1 +.\" Date: 11/28/2012 +.\" Manual: System administration commands +.\" Source: Ansible 0.9 +.\" Language: English +.\" +.TH "ANSIBLE\-DOC" "1" "11/28/2012" "Ansible 0\&.9" "System administration commands" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +ansible-doc \- show documentation on Ansible modules +.SH "SYNOPSIS" +.sp +ansible\-doc [\-M module_path] [\-l] [\-s] [module\&...] +.SH "DESCRIPTION" +.sp +\fBansible\-doc\fR displays information on modules installed in Ansible libraries\&. It displays a terse listing of modules and their short descriptions, provides a printout of their DOCUMENTATION strings, and it can create a short "snippet" which can be pasted into a playbook\&. +.SH "OPTIONS" +.PP +\fB\-M\fR \fIdirectory\fR, \fB\-\-module\-path=\fR\fIdirectory\fR +.RS 4 +Add an additional directory to the default path for finding module libraries\&. +.RE +.PP +\fB\-s\fR, \fB\-\-snippet=\fR +.RS 4 +Produce a snippet which can be copied into a playbook for modification, like a kind of task template\&. +.RE +.PP +\fB\-l\fR, \fB\-\-list=\fR +.RS 4 +Produce a terse listing of modules and a short description of each\&. +.RE +.SH "AUTHOR" +.sp +ansible\-doc was originally written by Jan\-Piet Mens\&. See the AUTHORS file for a complete list of contributors\&. +.SH "COPYRIGHT" +.sp +Copyright \(co 2012, Jan\-Piet Mens +.sp +Ansible is released under the terms of the GPLv3 License\&. +.SH "SEE ALSO" +.sp +\fBansible\-playbook\fR(1), \fBansible\fR(1) +.sp +Extensive documentation as well as IRC and mailing list info is available on the ansible home page: https://ansible\&.github\&.com/ +.SH "AUTHOR" +.PP +\fB:doctype:manpage\fR +.RS 4 +Author. +.RE diff --git a/docs/man/man1/ansible-doc.1.asciidoc.in b/docs/man/man1/ansible-doc.1.asciidoc.in new file mode 100644 index 00000000000..39722aa5456 --- /dev/null +++ b/docs/man/man1/ansible-doc.1.asciidoc.in @@ -0,0 +1,65 @@ +ansible-doc(1) +============== +:doctype:manpage +:man source: Ansible +:man version: %VERSION% +:man manual: System administration commands + +NAME +---- +ansible-doc - show documentation on Ansible modules + + +SYNOPSIS +-------- +ansible-doc [-M module_path] [-l] [-s] [module...] + + +DESCRIPTION +----------- + +*ansible-doc* displays information on modules installed in Ansible +libraries. It displays a terse listing of modules and their short +descriptions, provides a printout of their DOCUMENTATION strings, +and it can create a short "snippet" which can be pasted into a +playbook. + + +OPTIONS +------- + +*-M* 'directory', *--module-path=*'directory':: + +Add an additional directory to the default path for finding module libraries. + +*-s*, *--snippet=*:: + +Produce a snippet which can be copied into a playbook for modification, like +a kind of task template. + +*-l*, *--list=*:: + +Produce a terse listing of modules and a short description of each. + +AUTHOR +------ + +ansible-doc was originally written by Jan-Piet Mens. See the AUTHORS file +for a complete list of contributors. + + +COPYRIGHT +--------- + +Copyright © 2012, Jan-Piet Mens + +Ansible is released under the terms of the GPLv3 License. + + +SEE ALSO +-------- + +*ansible-playbook*(1), *ansible*(1) + +Extensive documentation as well as IRC and mailing list info +is available on the ansible home page: diff --git a/lib/ansible/utils/module_docs.py b/lib/ansible/utils/module_docs.py index 7a35fdc99d2..014c5dbcfdf 100755 --- a/lib/ansible/utils/module_docs.py +++ b/lib/ansible/utils/module_docs.py @@ -45,6 +45,7 @@ def get_docstring(filename, verbose=False): doc = yaml.load(child.value.s) except: - traceback.print_exc() - print "unable to parse %s" % filename + if verbose == True: + traceback.print_exc() + print "unable to parse %s" % filename return doc diff --git a/setup.py b/setup.py index dd2d085633b..00018cc4648 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,8 @@ setup(name='ansible', scripts=[ 'bin/ansible', 'bin/ansible-playbook', - 'bin/ansible-pull' + 'bin/ansible-pull', + 'bin/ansible-doc' ], data_files=data_files )