From fcda5f921ef463c23d94785d1d25ede1600884cd Mon Sep 17 00:00:00 2001
From: Ken Conley
Date: Wed, 23 Sep 2009 03:18:01 +0000
Subject: [PATCH] rosdoc: ported rosdoc to new config-style system for
non-doxygen builds and added landing page for packages with multiple
documentation sets. Also removed msgenator from doxygenator build. Much still
to do with rosdoc in terms of refactoring doxygenator and also giving landing
page better look and feel
---
core/roslib/manifest.xml | 3 +-
core/roslib/rosdoc.yaml | 6 +
core/rospy/manifest.xml | 2 +-
core/rospy/rosdoc.yaml | 1 +
tools/rosdoc/src/rosdoc/__init__.py | 13 +-
tools/rosdoc/src/rosdoc/doxygenator.py | 152 ++++++++++++------------
tools/rosdoc/src/rosdoc/epyenator.py | 27 +++--
tools/rosdoc/src/rosdoc/landing_page.py | 130 ++++++++++++++++++++
tools/rosdoc/src/rosdoc/rdcore.py | 44 +++++--
tools/rosdoc/src/rosdoc/sphinxenator.py | 15 ++-
tools/rosdoc/templates/doxy.template | 4 +-
tools/rosdoc/templates/landing.template | 17 +++
tools/rosdoc/templates/manifest.html | 3 -
tools/rosservice/manifest.xml | 2 +-
tools/rosservice/rosdoc.yaml | 1 +
tools/rostopic/manifest.xml | 2 +-
tools/rostopic/rosdoc.yaml | 1 +
17 files changed, 311 insertions(+), 112 deletions(-)
create mode 100644 core/roslib/rosdoc.yaml
create mode 100644 core/rospy/rosdoc.yaml
create mode 100644 tools/rosdoc/src/rosdoc/landing_page.py
create mode 100644 tools/rosdoc/templates/landing.template
create mode 100644 tools/rosservice/rosdoc.yaml
create mode 100644 tools/rostopic/rosdoc.yaml
diff --git a/core/roslib/manifest.xml b/core/roslib/manifest.xml
index 849e1c2f..98001bc1 100644
--- a/core/roslib/manifest.xml
+++ b/core/roslib/manifest.xml
@@ -7,9 +7,10 @@
Ken Conley/kwc@willowgarage.com, Morgan Quigley/mquigley@cs.stanford.eduBSD
- http://pr.willowgarage.com/wiki/roslib
+ http://ros.org/wiki/roslib
+
diff --git a/core/roslib/rosdoc.yaml b/core/roslib/rosdoc.yaml
new file mode 100644
index 00000000..97bf9687
--- /dev/null
+++ b/core/roslib/rosdoc.yaml
@@ -0,0 +1,6 @@
+ - builder: epydoc
+ output_dir: python
+ - builder: doxygen
+ name: C++ API
+ output_dir: c++
+ file_patterns: '*.c *.cpp *.h *.cc *.hh *.dox'
\ No newline at end of file
diff --git a/core/rospy/manifest.xml b/core/rospy/manifest.xml
index 4dcd357b..cadb95c0 100644
--- a/core/rospy/manifest.xml
+++ b/core/rospy/manifest.xml
@@ -31,7 +31,7 @@
-
+
diff --git a/core/rospy/rosdoc.yaml b/core/rospy/rosdoc.yaml
new file mode 100644
index 00000000..0bdea97f
--- /dev/null
+++ b/core/rospy/rosdoc.yaml
@@ -0,0 +1 @@
+ - builder: epydoc
diff --git a/tools/rosdoc/src/rosdoc/__init__.py b/tools/rosdoc/src/rosdoc/__init__.py
index e03f0794..66099ee1 100644
--- a/tools/rosdoc/src/rosdoc/__init__.py
+++ b/tools/rosdoc/src/rosdoc/__init__.py
@@ -84,11 +84,10 @@ def main():
else:
sphinx_success = set()
- # Generate Doxygen on remainder
+ # Generate Doxygen
if 1:
print "building doxygen packages"
import doxygenator
- ctx.packages = dict([(p, ctx.packages[p]) for p in (set(ctx.packages) - sphinx_success - epyenator_success)])
doxy_success = doxygenator.generate_doxygen(ctx, quiet=options.quiet)
else:
doxy_success = []
@@ -109,6 +108,11 @@ def main():
traceback.print_exc()
print >> sys.stderr, "msgenator failed"
+ if 1:
+ # Generate landing page
+ import landing_page
+ landing_page.generate_landing_page(ctx)
+
if 1:
# Generate Documentation Index
import docindex
@@ -128,10 +132,5 @@ def main():
styles_css = os.path.join(ctx.docdir, 'styles.css')
print "copying",styles_in, "to", styles_css
shutil.copyfile(styles_in, styles_css)
-
- # have to copy doxygen.css for external packages that we fake-doxygenate
- dstyles_in = os.path.join(ctx.template_dir, 'doxygen.css')
- dstyles_css = os.path.join(ctx.docdir, 'doxygen.css')
- shutil.copyfile(dstyles_in, dstyles_css)
except:
traceback.print_exc()
diff --git a/tools/rosdoc/src/rosdoc/doxygenator.py b/tools/rosdoc/src/rosdoc/doxygenator.py
index 6bb928ab..7d4a3c44 100644
--- a/tools/rosdoc/src/rosdoc/doxygenator.py
+++ b/tools/rosdoc/src/rosdoc/doxygenator.py
@@ -49,46 +49,6 @@ external_template = load_tmpl('external.html')
header_template = load_tmpl('header.html')
footer_template = load_tmpl('footer.html')
manifest_template = load_tmpl('manifest.html')
-wiki_header_template = load_tmpl('wiki-header.html')
-
-# routines for including links to msgenator files
-def _href(url, text):
- return '%(text)s'%locals()
-def msg_link(msg):
- return _href('msg/%(msg)s.html'%locals(), msg)
-def srv_link(srv):
- return _href('srv/%(srv)s.html'%locals(), srv)
-
-# table of msgs/srvs provided by package. this is a duplicate of the
-# PackageHeader.py code in the roswiki Moin
-def msgenator_html(msgs, srvs):
- # include table of msgs/srvs
- msg_str = ''
- if msgs or srvs:
- if msgs and srvs:
- msg_str += '
ROS Message and Service Types
'
- elif msgs:
- msg_str += '
ROS Message Types
\n'
- elif srvs:
- msg_str += '
ROS Service Types
\n'
- msg_str += '
\n
\n'
- if msgs:
- if srvs:
- msg_str += '
ROS Message Types
\n'
- if srvs:
- if msgs:
- msg_str += '
ROS Service Types
\n'
- msg_str += '
'
- if msgs:
- msg_str += '
\n'+\
- ' \n'.join([msg_link(m) for m in msgs])+\
- '
\n'
- if srvs:
- msg_str += '
\n'+\
- ' \n'.join([srv_link(s) for s in srvs])+\
- '
\n'
- msg_str += '
'
- return msg_str
# other templates
@@ -117,14 +77,14 @@ def generate_msg_srv_includes(package, tmp, to_delete):
html_file.write(_msg_srv_tmpl(ext, type_, f.read()))
## @param package str: package name
+## @param rd_config dict: rosdoc configuration parameters for this doxygen build
## @param m Manifest : package manifest
-## @param docdir str: directory to store documentation in
-def create_package_template(package, m, path, docdir, header_filename, footer_filename):
- #replace vars in the template file to point to package we are documenting
- if not os.path.exists(docdir):
- os.mkdir(docdir)
-
- #TODO: replace with general purpose key/value parser/substitution to enable feature
+## @param html_dir str: directory to store doxygen files
+def create_package_template(package, rd_config, m, path, html_dir,
+ header_filename, footer_filename):
+ # TODO: allow rd_config to specify excludes and whatnot
+
+ # TODO: replace with general purpose key/value parser/substitution to enable feature
# determine the value of overridable keys
file_patterns = '*.c *.cpp *.h *.cc *.hh *.py *.dox'
@@ -133,16 +93,22 @@ def create_package_template(package, m, path, docdir, header_filename, footer_fi
for e in m.get_export('doxygen', 'excludes'):
# prepend the packages path
excludes = '%s/%s'%(path, e)
+ # rd_config wins
+ if rd_config and 'excludes' in rd_config:
+ excludes = rd_config['excludes']
+
# last one wins
for e in m.get_export('doxygen', 'file-patterns'):
file_patterns = e
+ # rd_config wins
+ if rd_config and 'file_patterns' in rd_config:
+ file_patterns = rd_config['file_patterns']
- html_output = html_path(package, docdir)
-
vars = { '$INPUT': path, '$PROJECT_NAME': package,
'$EXCLUDE_PROP': excludes, '$FILE_PATTERNS': file_patterns,
+ '$HTML_OUTPUT': os.path.abspath(html_dir),
'$HTML_HEADER': header_filename, '$HTML_FOOTER': footer_filename,
- '$OUTPUT_DIRECTORY': os.path.join(docdir, package), '$HTML_OUTPUT': html_output}
+ '$OUTPUT_DIRECTORY': html_dir}
return instantiate_template(doxy_template, vars)
## Processes manifest for package and then generates templates for
@@ -153,7 +119,7 @@ def create_package_template(package, m, path, docdir, header_filename, footer_fi
## @return (str, str, str): header, footer, manifest
def load_manifest_vars(ctx, package, path, docdir, m):
author = license = dependencies = description = usedby = status = notes = li_vc = li_url = brief = ''
- wiki_url = 'http://pr.willowgarage.com/wiki/%s'%package
+ wiki_url = 'http://ros.org/wiki/%s'%package
project_link = '%s'%(wiki_url, package)
if m:
license = m.license or ''
@@ -187,9 +153,6 @@ def load_manifest_vars(ctx, package, path, docdir, m):
# include links to msgs/srvs
msgs = roslib.msgs.list_msg_types(package, False)
srvs = roslib.srvs.list_srv_types(package, False)
- msgen = msgenator_html(msgs, srvs)
- if msgen is None:
- raise Exception('msgen is none')
return {'$package': package,
'$projectlink': project_link, '$license': license,
@@ -197,7 +160,7 @@ def load_manifest_vars(ctx, package, path, docdir, m):
'$description': description, '$brief': brief,
'$author': author, '$status':status,
'$notes':notes, '$li_vc': li_vc, '$li_url': li_url,
- '$msgenator': msgen}
+ }
## utility to write string data to files and handle unicode
def _write_to_file(f, tmpl):
@@ -228,10 +191,10 @@ If you are on Ubuntu/Debian, you can install doxygen by typing:
"""
sys.exit(1)
-def run_rxdeps(package, dir):
- if 1: return
+#TODO: move elsewhere
+def run_rxdeps(package, pkg_doc_dir):
try:
- command = ['rxdeps', '-s', '--target=%s'%package, '--cluster', '-o', os.path.join(dir, package, 'html', '%s_deps.pdf'%package)]
+ command = ['rxdeps', '-s', '--target=%s'%package, '--cluster', '-o', os.path.join(pkg_doc_dir, '%s_deps.pdf'%package)]
print "rxdeping %s [%s]"%(package, ' '.join(command))
Popen(command, stdout=PIPE).communicate()
except OSError, (errno, strerr):
@@ -242,6 +205,10 @@ Package dependency tree links will not work properly.
## Main entrypoint into creating doxygen files
## @return [str]: list of packages that were successfully generated
def generate_doxygen(ctx, quiet=False):
+
+ #TODO: move external generator into its own generator
+ #TODO: move rxdeps into its own generator
+
# setup temp directory
tmp = 'tmp'
if not os.path.exists(tmp):
@@ -255,22 +222,47 @@ def generate_doxygen(ctx, quiet=False):
# list of packages that we are documenting
doc_packages = ctx.doc_packages
external_docs = ctx.external_docs
+ rd_configs = ctx.rd_configs
manifests = ctx.manifests
- tmpls = [header_template, footer_template, manifest_template, wiki_header_template]
+ tmpls = [header_template, footer_template, manifest_template]
try:
for package, path in packages.iteritems():
- if not package in doc_packages:
+ if not package in doc_packages or not ctx.has_builder(package, 'doxygen'):
continue
- html_dir = os.path.join(dir, package, 'html')
- # have to makedirs for external packages
- if not os.path.exists(html_dir):
- os.makedirs(html_dir)
+
+ # the logic for the doxygen builder is different from
+ # others as doxygen is the default builder if no config is
+ # declared
+ rd_config = rd_configs.get(package, None)
+ if rd_config:
+ # currently only allow one doxygen build per package. This is not inherent, it
+ # just requires rewriting higher-level logic
+ rd_config = [d for d in ctx.rd_configs[package] if d['builder'] == 'doxygen'][0]
+
+ # Configuration (all are optional)
+ #
+ # name: Documentation set name (e.g. C++ API)
+ # output_dir: Directory to store files (default '.')
+ # file-patterns: override FILE_PATTERNS
+ # excludes: override EXCLUDES
+
+ # doxygenator currently does some non-doxygen work.
+ # pkg_doc_dir is the pointer to the directory for these non-doxygen
+ # tools. html_dir is the path for doxygen
+ pkg_doc_dir = html_path(package, ctx.docdir)
+ # compute the html directory for doxygen
+ html_dir = html_path(package, ctx.docdir)
+ if rd_config and 'output_dir' in rd_config:
+ html_dir = os.path.join(html_dir, rd_config['output_dir'])
+
+ # have to makedirs for external packages
+ if not os.path.exists(pkg_doc_dir):
+ os.makedirs(pkg_doc_dir)
+
files = []
try:
- #TODO: cleanup the temporary files
-
header_file = tempfile.NamedTemporaryFile('w+')
footer_file = tempfile.NamedTemporaryFile('w+')
doxygen_file = tempfile.NamedTemporaryFile('w+')
@@ -285,11 +277,14 @@ def generate_doxygen(ctx, quiet=False):
# - instantiate the templates
manifest_ = manifests[package] if package in manifests else None
vars = load_manifest_vars(ctx, package, path, dir, manifest_)
- header, footer, manifest_html, wiki_header = [instantiate_template(t, vars) for t in tmpls]
+ header, footer, manifest_html = [instantiate_template(t, vars) for t in tmpls]
- run_rxdeps(package, dir)
+ run_rxdeps(package, pkg_doc_dir)
if package not in external_docs:
- doxy = create_package_template(package, manifest_, path, dir, header_file.name, footer_file.name)
+ doxy = \
+ create_package_template(package, rd_config, manifest_,
+ path, html_dir,
+ header_file.name, footer_file.name)
for f, tmpl in zip(files, [header, footer, manifest_html, doxy]):
_write_to_file(f, tmpl)
# doxygenate
@@ -300,18 +295,27 @@ def generate_doxygen(ctx, quiet=False):
# it is time consuming for packages that provide their own docs
external_link = ctx.external_docs[package]
+
+ # Override mainpage title if 'name' is in config
+ title = 'Main Page'
+ if rd_config:
+ title = rd_config.get('name', title)
vars = { '$package': package, '$external_link': external_link,
'$header': header, '$footer': footer,
'$manifest': manifest_html,
# doxygen vars
'$relpath$': '../../',
- '$title': package+': Main Page',
+ '$title': package+': '+title,
}
- with open(os.path.join(html_dir, 'index.html'), 'w') as ext_html_file:
- _write_to_file(ext_html_file, instantiate_template(external_template, vars))
- with open(os.path.join(html_dir, 'wiki_header.html'), 'w') as wiki_header_file:
- _write_to_file(wiki_header_file, wiki_header)
+ with open(os.path.join(pkg_doc_dir, 'index.html'), 'w') as ext_html_file:
+ _write_to_file(ext_html_file, instantiate_template(external_template, vars))
+
+ # support files (stylesheets)
+ import shutil
+ dstyles_in = os.path.join(ctx.template_dir, 'doxygen.css')
+ dstyles_css = os.path.join(html_dir, 'doxygen.css')
+ shutil.copyfile(dstyles_in, dstyles_css)
success.append(package)
finally:
diff --git a/tools/rosdoc/src/rosdoc/epyenator.py b/tools/rosdoc/src/rosdoc/epyenator.py
index 81379d23..13ce6486 100644
--- a/tools/rosdoc/src/rosdoc/epyenator.py
+++ b/tools/rosdoc/src/rosdoc/epyenator.py
@@ -37,19 +37,32 @@ from __future__ import with_statement
import os, sys
from subprocess import Popen, PIPE
-## Main entrypoint into creating Eepydoc documentation
+from rosdoc.rdcore import *
+
+## Main entrypoint into creating Epydoc documentation
## @return [str]: list of packages that were successfully generated
def generate_epydoc(ctx):
success = []
for package, path in ctx.packages.iteritems():
- if package in ctx.doc_packages and ctx.should_document(package):
- builder = ctx.builder[package]
- if builder != 'epydoc':
- continue
+ if package in ctx.doc_packages and ctx.should_document(package) \
+ and ctx.has_builder(package, 'epydoc'):
+
+ # currently only allow one epydoc build per package. This
+ # is not inherent, it just requires rewriting higher-level
+ # logic
+ rd_config = [d for d in ctx.rd_configs[package] if d['builder'] == 'epydoc'][0]
+
+ # Configuration Properties (all optional):
+ #
+ # output_dir: directory_name (default: '.')
+ # name: Documentation Set Name (default: Python API)
try:
- html_dir = os.path.join(ctx.docdir, package, 'html')
+ html_dir = html_path(package, ctx.docdir)
+ if 'output_dir' in rd_config:
+ html_dir = os.path.join(html_dir, rd_config['output_dir'])
if not os.path.isdir(html_dir):
os.makedirs(html_dir)
+
command = ['epydoc', '--html', package, '-o', html_dir]
# determine the python path of the package
@@ -64,5 +77,5 @@ def generate_epydoc(ctx):
Popen(command, stdout=PIPE, env=env).communicate()
success.append(package)
except Exception, e:
- print >> sys.stderr, "Unable to generate eepydoc for [%s]. This is probably because eepydoc is not installed.\nThe exact error is:\n\t%s"%(package, str(e))
+ print >> sys.stderr, "Unable to generate epydoc for [%s]. This is probably because epydoc is not installed.\nThe exact error is:\n\t%s"%(package, str(e))
return success
diff --git a/tools/rosdoc/src/rosdoc/landing_page.py b/tools/rosdoc/src/rosdoc/landing_page.py
new file mode 100644
index 00000000..bf102000
--- /dev/null
+++ b/tools/rosdoc/src/rosdoc/landing_page.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# Software License Agreement (BSD License)
+#
+# Copyright (c) 2008, Willow Garage, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Willow Garage, Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+from __future__ import with_statement
+
+import os, sys
+import time
+
+from subprocess import Popen, PIPE
+
+import roslib.msgs
+import roslib.srvs
+from rosdoc.rdcore import *
+
+def _href(location, text):
+ return '%(text)s'%locals()
+
+def link_name(rd_config):
+ if 'name' in rd_config:
+ n = rd_config['name']
+ else:
+ if rd_config['builder'] == 'doxygen':
+ return 'C++ API'
+ elif rd_config['builder'] in ['epydoc', 'sphinx']:
+ return 'Python API'
+ else:
+ return builder
+ return n
+
+def generate_links(ctx, package, base_dir, rd_configs):
+ output_dirs = [c.get('output_dir', None) for c in rd_configs]
+ # filter out empties
+ output_dirs = [d for d in output_dirs if d and d != '.']
+
+ # length check. if these are unequal, cannot generate landing
+ # page. this is often true if the config is merely generating
+ # local
+ if len(output_dirs) != len(rd_configs):
+ return None
+
+ links = []
+ for c, d in zip(rd_configs, output_dirs):
+ links.append(_href(d, link_name(c)))
+
+ msgs = roslib.msgs.list_msg_types(package, False)
+ srvs = roslib.srvs.list_srv_types(package, False)
+ if msgs or srvs:
+ if msgs and srvs:
+ title = 'msg/srv API'
+ elif msgs and not srvs:
+ title = 'msg API'
+ elif srvs and not msgs:
+ title = 'srv API'
+ #TODO: this shouldn't be hardcoded to index-msg.html
+ links.append(_href('index-msg.html', title))
+
+ url = ctx.manifests[package].url
+ if url:
+ links.append(_href(url, '%s Package Documentation'%package))
+ return links
+
+## Generate landing page in the event that there are multiple documentation sets
+## @return [str]: list of packages for which there are landing pages generated
+def generate_landing_page(ctx):
+ success = []
+ template = load_tmpl('landing.template')
+ for package, path in ctx.packages.iteritems():
+ if package in ctx.doc_packages and ctx.should_document(package) and \
+ package in ctx.rd_configs:
+
+ rd_configs = ctx.rd_configs[package]
+ links = generate_links(ctx, package, ctx.docdir, rd_configs)
+ # if links is empty, it means that the rd_configs builds
+ # to the base directory and no landing page is required
+ # (or it means that the config is corrupt)
+ if not links:
+ print "ignoring landing page for", package
+ return
+
+ try:
+ html_dir = html_path(package, ctx.docdir)
+ if not os.path.isdir(html_dir):
+ os.makedirs(html_dir)
+
+ links_html = '\n'.join(['
%s
'%l for l in links])
+ date = str(time.strftime('%a, %d %b %Y %H:%M:%S'))
+ vars = {
+ '$package': package,
+ '$links': links_html,
+ '$date': date,
+ }
+
+ print "generating landing page", html_dir
+ with open(os.path.join(html_dir, 'index.html'), 'w') as f:
+ f.write(instantiate_template(template, vars))
+ success.append(package)
+ except Exception, e:
+ print >> sys.stderr, "Unable to generate landing_page for [%s]:\n\t%s"%(package, str(e))
+ return success
diff --git a/tools/rosdoc/src/rosdoc/rdcore.py b/tools/rosdoc/src/rosdoc/rdcore.py
index 5153236b..5f8c3aac 100644
--- a/tools/rosdoc/src/rosdoc/rdcore.py
+++ b/tools/rosdoc/src/rosdoc/rdcore.py
@@ -32,6 +32,8 @@
#
# Revision $Id: doxyutil.py 3727 2009-02-06 22:42:26Z sfkwc $
+from __future__ import with_statement
+
import os
import sys
from subprocess import Popen, PIPE
@@ -63,10 +65,23 @@ class RosdocContext(object):
self.stacks = {}
self.external_docs = {}
self.manifests = {}
- self.builder = {}
- self.stack_manifests = {}
+ self.stack_manifests = {}
+ # advanced per-package config
+ self.rd_configs = {}
self.template_dir = None
+
+ ## @return: True if package is configured to use builder. NOTE: if
+ ## there is no config, package is assumed to define a doxygen
+ ## builder
+ def has_builder(self, package, builder):
+ rd_config = self.rd_configs.get(package, None)
+ if not rd_config:
+ return builder == 'doxygen'
+ try:
+ return len([d for d in rd_config if d['builder'] == builder]) > 0
+ except KeyError:
+ print >> sys.stderr, "config file for [%s] is invalid, missing required 'builder' key"%package
## @return bool True if \a package should be document
def should_document(self, package):
@@ -107,9 +122,9 @@ class RosdocContext(object):
## Crawl manifest.xml dependencies
def _crawl_deps(self):
- builder = self.builder
external_docs = self.external_docs
manifests = self.manifests
+ rd_configs = self.rd_configs
stacks = self.stacks = {}
@@ -130,22 +145,29 @@ class RosdocContext(object):
try:
manifests[package] = m = roslib.manifest.parse_file(f)
+ #NOTE: the behavior is undefined if the users uses
+ #both config and export properties directly
+
# #1650 for backwards compatibility, we ready the old
# 'doxymaker' tag, which is deprecated
-
- # this is a loop but we only accept one value
+ # - this is a loop but we only accept one value
for e in m.get_export('doxymaker', 'external'):
external_docs[package] = e
for e in m.get_export('rosdoc', 'external'):
external_docs[package] = e
- builder[package] = 'doxygen'
- for e in m.get_export('rosdoc', 'builder'):
- builder[package] = e.lower()
- if builder[package] not in ['epydoc', 'doxygen', 'sphinx']:
- print >> sys.stderr, "ERROR: unknown builder [%s]. Using doxygen instead"%builder[package]
- builder[package] = 'doxygen'
+ # load in any external config files
+ for e in m.get_export('rosdoc', 'config'):
+ import yaml
+ try:
+ e = e.replace('${prefix}', path)
+ config_p = os.path.join(path, e)
+ with open(config_p, 'r') as config_f:
+ rd_configs[package] = yaml.load(config_f)
+ except Exception, e:
+ print >> sys.stderr, "ERROR: unable to load rosdoc config file [%s]: %s"%(config_p, str(e))
+
except:
print >> sys.stderr, "WARN: Package '%s' does not have a valid manifest.xml file, manifest information will not be included in docs"%package
diff --git a/tools/rosdoc/src/rosdoc/sphinxenator.py b/tools/rosdoc/src/rosdoc/sphinxenator.py
index 3b787dfc..e2536c5c 100644
--- a/tools/rosdoc/src/rosdoc/sphinxenator.py
+++ b/tools/rosdoc/src/rosdoc/sphinxenator.py
@@ -43,11 +43,18 @@ from subprocess import Popen, PIPE
def generate_sphinx(ctx):
success = []
for package, path in ctx.packages.iteritems():
- if package in ctx.doc_packages and ctx.should_document(package):
+ if package in ctx.doc_packages and ctx.should_document(package) and \
+ ctx.has_builder(package, 'sphinx'):
try:
- builder = ctx.builder[package]
- if builder != 'sphinx':
- continue
+
+ # currently only allow one sphinx build per package. This
+ # is not inherent, it just requires rewriting higher-level
+ # logic
+ rd_config = [d for d in ctx.rd_configs[package] if d['builder'] == 'sphinx'][0]
+
+ # rd_config is currently a flag. In the future, I imagine it pointing
+ # to the location of index.rst, among other things
+
if os.access(os.path.join(path, "index.rst"), os.R_OK):
oldcwd = os.getcwd()
os.chdir(path)
diff --git a/tools/rosdoc/templates/doxy.template b/tools/rosdoc/templates/doxy.template
index 08c4ed56..d0d79a98 100644
--- a/tools/rosdoc/templates/doxy.template
+++ b/tools/rosdoc/templates/doxy.template
@@ -106,7 +106,7 @@ IGNORE_PREFIX =
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
-HTML_OUTPUT = html
+HTML_OUTPUT = $HTML_OUTPUT
HTML_FILE_EXTENSION = .html
HTML_HEADER = $HTML_HEADER
HTML_FOOTER = $HTML_FOOTER
@@ -125,7 +125,7 @@ TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
-GENERATE_LATEX = YES
+GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
diff --git a/tools/rosdoc/templates/landing.template b/tools/rosdoc/templates/landing.template
new file mode 100644
index 00000000..c929ad50
--- /dev/null
+++ b/tools/rosdoc/templates/landing.template
@@ -0,0 +1,17 @@
+
+
+$package Documentation
+
+
+
+
+
+