Skip to content

Commit

Permalink
CLI: ansible-doc shows lists of modules & module docs on command-line
Browse files Browse the repository at this point in the history
check path is directory
added manpage & setup
small cleanup
shut up module_formatter in utils to avoid trace print on crud files in library
  • Loading branch information
jpmens authored and mpdehaan committed Dec 1, 2012
1 parent b8d6dec commit 17f31a2
Show file tree
Hide file tree
Showing 6 changed files with 346 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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()")

Expand Down
203 changes: 203 additions & 0 deletions bin/ansible-doc
Original file line number Diff line number Diff line change
@@ -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()
72 changes: 72 additions & 0 deletions docs/man/man1/ansible-doc.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
'\" t
.\" Title: ansible-doc
.\" Author: :doctype:manpage
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
.\" 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
65 changes: 65 additions & 0 deletions docs/man/man1/ansible-doc.1.asciidoc.in
Original file line number Diff line number Diff line change
@@ -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: <https://ansible.github.com/>
5 changes: 3 additions & 2 deletions lib/ansible/utils/module_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
scripts=[
'bin/ansible',
'bin/ansible-playbook',
'bin/ansible-pull'
'bin/ansible-pull',
'bin/ansible-doc'
],
data_files=data_files
)

0 comments on commit 17f31a2

Please sign in to comment.