rtdoc.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # -*- Python -*-
00003 # -*- coding: utf-8 -*-
00004 
00005 '''rtshell
00006 
00007 Copyright (C) 2009-2014
00008     Yosuke Matsusaka and Geoffrey Biggs
00009     Intelligent Systems Research Institute,
00010     National Institute of Advanced Industrial Science and Technology (AIST),
00011     Japan
00012     All rights reserved.
00013 Licensed under the Eclipse Public License -v 1.0 (EPL)
00014 http://www.opensource.org/licenses/eclipse-1.0.txt
00015 
00016 Implementation of the command to display component documentation.
00017 
00018 '''
00019 
00020 
00021 import docutils.core
00022 import optparse
00023 import os
00024 import os.path
00025 import rtctree.tree
00026 import rtctree.path
00027 import sys
00028 import traceback
00029 
00030 import path
00031 import rts_exceptions
00032 import rtshell
00033 
00034 
00035 def escape(s):
00036     return s.replace('"', "'")
00037 
00038 
00039 def section(s, level=0):
00040     result = []
00041     if level == 0:
00042         result.append(s)
00043         result.append('=' * len(s))
00044     elif level == 1:
00045         result.append(s)
00046         result.append('-' * len(s))
00047     return result
00048 
00049 
00050 def get_ports_docs(comp):
00051     result = []
00052     result.append('.. csv-table:: Ports')
00053     result.append('   :header: "Name", "Type", "DataType", "Description"')
00054     result.append('   :widths: 8, 8, 8, 26')
00055     result.append('   ')
00056     for p in comp.ports:
00057         if p.porttype == 'DataInPort' or p.porttype == 'DataOutPort':
00058             datatype = p.properties['dataport.data_type']
00059         else:
00060             datatype = ''
00061         if 'description' in p.properties:
00062             description = p.properties['description']
00063         else:
00064             description = ''
00065         result.append('   "{0}", "{1}", "{2}", "{3}"'.format(p.name,
00066             p.porttype, datatype, escape(description)))
00067     return result
00068 
00069 
00070 def get_config_docs(comp):
00071     result = []
00072     result.append('.. csv-table:: Configuration parameters')
00073     result.append('   :header: "Name", "Description"')
00074     result.append('   :widths: 12, 38')
00075     result.append('   ')
00076 
00077     desc_set = None
00078     if '__description__' in comp.conf_sets:
00079         desc_set = comp.conf_sets['__description__']
00080     for n in comp.conf_sets['default'].data:
00081         if desc_set and desc_set.has_param(n):
00082             description = desc_set.data[n]
00083         else:
00084             description = ''
00085         result.append('   "{0}", "{1}"'.format(n, escape(description)))
00086     return result
00087 
00088 
00089 from rtstodot import port_name as dot_port_name
00090 from rtstodot import escape as dot_escape
00091 
00092 def make_comp_graph(comp):
00093     result = []
00094     result.append('.. digraph:: comp')
00095     result.append('')
00096     result.append('   rankdir=LR;')
00097     result.append('   {0} [shape=Mrecord, label="{1}"];'.format(dot_escape(comp.type_name), comp.type_name))
00098     for p in comp.ports:
00099         if p.porttype == 'DataInPort':
00100             pname = dot_port_name(p.name)
00101             result.append('   {0} [shape=plaintext, label="{1}"];'.format(dot_escape(pname), pname))
00102             result.append('   {0} -> {1};'.format(dot_escape(pname), dot_escape(comp.type_name)))
00103         elif p.porttype == 'DataOutPort':
00104             pname = dot_port_name(p.name)
00105             result.append('   {0} [shape=plaintext, label="{1}"];'.format(dot_escape(pname), pname))
00106             result.append('   {0} -> {1};'.format(dot_escape(comp.type_name), dot_escape(pname)))
00107     return result
00108 
00109 
00110 def get_section_title(sec):
00111     if sec == 'intro':
00112         return 'Introduction'
00113     elif sec == 'reqs':
00114         return 'Pre-requisites'
00115     elif sec == 'install':
00116         return 'Installation'
00117     elif sec == 'usage':
00118         return 'Usage'
00119     elif sec == 'misc':
00120         return 'Miscellaneous'
00121     elif sec == 'changelog':
00122         return 'Changelog'
00123     else:
00124         return sec
00125 
00126 
00127 def do_section(result, comp, doc_set, sec, options):
00128     if sec == 'ports' and comp.ports:
00129         result += section('Ports', 1)
00130         result += get_ports_docs(comp)
00131         result.append('')
00132         if options.graph == True:
00133             result += make_comp_graph(comp)
00134             result.append('')
00135     elif (sec == 'config' and
00136             'default' in comp.conf_sets and comp.conf_sets['default'].data):
00137         result += section('Configuration parameters', 1)
00138         result += get_config_docs(comp)
00139         result.append('')
00140     elif doc_set and doc_set.has_param(sec):
00141         title = get_section_title(sec)
00142         body = doc_set.data[sec]
00143         result += section(title, 1)
00144         result.append(doc_set.data[sec])
00145         result.append('')
00146 
00147 
00148 def get_comp_docs(comp, tree, options):
00149     result = []
00150     result += section(comp.type_name, 0)
00151     result.append(comp.description)
00152     result.append('')
00153 
00154     result.append(':Vendor: {0}'.format(comp.vendor))
00155     result.append(':Version: {0}'.format(comp.version))
00156     result.append(':Category: {0}'.format(comp.category))
00157 
00158     doc_set = None
00159     order = ['intro', 'reqs', 'install', 'usage', 'ports', 'config', 'misc',
00160             'changelog']
00161     sections = ['ports', 'config']
00162     if '__doc__' in comp.conf_sets:
00163         doc_set = comp.conf_sets['__doc__']
00164         if doc_set.has_param('__order__') and doc_set.data['__order__']:
00165             order = doc_set.data['__order__'].split(',')
00166         sections += [k for k in doc_set.data.keys() if not k.startswith('__')]
00167 
00168     if doc_set:
00169         if doc_set.has_param('__license__'):
00170             result.append(':License: {0}'.format(
00171                 comp.conf_sets['__doc__'].data['__license__']))
00172         if doc_set.has_param('__contact__'):
00173             result.append(':Contact: {0}'.format(
00174                 comp.conf_sets['__doc__'].data['__contact__']))
00175         if doc_set.has_param('__url__'):
00176             result.append(':URL: {0}'.format(
00177                 comp.conf_sets['__doc__'].data['__url__']))
00178     result.append('')
00179 
00180     # Add sections specified in the ordering first
00181     for s in order:
00182         if s not in sections:
00183             if doc_set:
00184                 print >>sys.stderr, ('{0}: Unknown section in order: '
00185                     '{1}'.format(os.path.basename(sys.argv[0]), s))
00186             continue
00187         do_section(result, comp, doc_set, s, options)
00188 
00189     # Add any sections that were not in the ordering last
00190     for s in [s for s in sections if s not in order]:
00191         do_section(result, comp, doc_set, s, options)
00192 
00193     return result
00194 
00195 
00196 def get_docs(cmd_path, full_path, options, tree=None):
00197     path, port = rtctree.path.parse_path(full_path)
00198     if not path[-1]:
00199         # There was a trailing slash
00200         raise rts_exceptions.NotAComponentError(cmd_path)
00201     if port:
00202         raise rts_exceptions.NotAComponentError(cmd_path)
00203 
00204     if not tree:
00205         tree = rtctree.tree.RTCTree(paths=path)
00206 
00207     if not tree.has_path(path):
00208         raise rts_exceptions.NoSuchObjectError(cmd_path)
00209     object = tree.get_node(path)
00210 
00211     if object.is_component:
00212         return get_comp_docs(object, tree, options)
00213     elif object.is_zombie:
00214         raise rts_exceptions.ZombieObjectError(cmd_path)
00215     else:
00216         raise rts_exceptions.NotAComponentError(cmd_path)
00217 
00218 
00219 def main(argv=None, tree=None):
00220     usage = '''Usage: %prog [options] <path>
00221 Display component documentation.'''
00222     version = rtshell.RTSH_VERSION
00223     parser = optparse.OptionParser(usage=usage, version=version)
00224     parser.add_option('-f', '--format', dest='format', type='choice',
00225             choices=('rst', 'html', 'latex'), default='html',
00226             help='Output format (one of "rst", "html" or "latex"). '
00227             '[Default: %default]')
00228     parser.add_option('-g', '--graph', dest='graph', action='store_true',
00229             default=False,
00230             help='Draw component graph. [Default: %default]')
00231     parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
00232             default=False,
00233             help='Output verbose information. [Default: %default]')
00234 
00235     if argv:
00236         sys.argv = [sys.argv[0]] + argv
00237     try:
00238         options, args = parser.parse_args()
00239     except optparse.OptionError, e:
00240         print >>sys.stderr, 'OptionError:', e
00241         return 1
00242 
00243     if not args:
00244         # If no path given then can't do anything.
00245         print >>sys.stderr, '{0}: No component specified.'.format(
00246                 os.path.basename(sys.argv[0]))
00247         return 1
00248     elif len(args) == 1:
00249         cmd_path = args[0]
00250     else:
00251         print >>sys.stderr, usage
00252         return 1
00253     full_path = path.cmd_path_to_full_path(cmd_path)
00254 
00255     try:
00256         docs = '\n'.join(get_docs(cmd_path, full_path, options, tree=tree))
00257         if options.format == 'rst':
00258             print docs
00259         else:
00260             print docutils.core.publish_string(docs, writer_name=options.format)
00261     except Exception, e:
00262         if options.verbose:
00263             traceback.print_exc()
00264         print >>sys.stderr, '{0}: {1}'.format(os.path.basename(sys.argv[0]), e)
00265         return 1
00266     return 0
00267 
00268 
00269 # vim: tw=79
00270 


rtshell
Author(s): Geoffrey Biggs
autogenerated on Fri Aug 28 2015 12:55:12