00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 from __future__ import with_statement
00037
00038 from subprocess import Popen, PIPE
00039 import tempfile
00040
00041 import roslib.msgs
00042 import roslib.srvs
00043 import roslib.rospack
00044
00045 from rosdoc.rdcore import *
00046
00047
00048
00049
00050 def _msg_srv_tmpl(ext, type, text):
00051 tmpl = '<h2>%s.%s</h2><div style="border: 1px solid #333;"><p style="font-family: monospace;">'%(type, ext)
00052 for line in text.split('\n'):
00053 parts = line.split('#')
00054 if len(parts) > 1:
00055 tmpl = tmpl + parts[0]+'<font color="blue">#%s</font><br/>'%('#'.join(parts[1:]))
00056 else:
00057 tmpl = tmpl + "%s<br />"%parts[0]
00058 return tmpl+"</p></div>"
00059
00060
00061 def generate_msg_srv_includes(package, tmp, to_delete):
00062 for ext, list_types, spec_file in [('msg', roslib.msgs.list_msg_types, roslib.msgs.msg_file),\
00063 ('srv', roslib.srvs.list_srv_types, roslib.srvs.srv_file)]:
00064 for type_ in list_types(package, False):
00065 with open(spec_file(package, type_), 'r') as f:
00066 p = os.path.join(tmp, '%s.%s.html'%(type_, ext))
00067 with open(p, 'w') as html_file:
00068 to_delete.append(p)
00069 html_file.write(_msg_srv_tmpl(ext, type_, f.read()))
00070
00071
00072
00073
00074
00075 def create_package_template(package, rd_config, m, path, html_dir,
00076 header_filename, footer_filename, example_path):
00077
00078
00079
00080 file_patterns = '*.c *.cpp *.h *.cc *.hh *.hpp *.py *.dox *.java'
00081 excludes = '%s/build/'%path
00082 exclude_patterns = ''
00083
00084
00085 for e in m.get_export('doxygen', 'excludes'):
00086
00087 excludes = '%s/%s'%(path, e)
00088
00089
00090 for e in m.get_export('doxygen', 'file-patterns'):
00091 file_patterns = e
00092
00093
00094 if not rd_config:
00095 rd_config = {}
00096
00097 include_path = roslib.rospack.rospackexec(['cflags-only-I',package])
00098
00099
00100 dvars = { '$INPUT': path, '$PROJECT_NAME': package,
00101 '$EXAMPLE_PATH': "%s %s"%(path, example_path),
00102 '$EXCLUDE_PROP': rd_config.get('exclude', excludes),
00103 '$FILE_PATTERNS': rd_config.get('file_patterns', file_patterns),
00104 '$EXCLUDE_PATTERNS': rd_config.get('exclude_patterns', ''),
00105 '$HTML_OUTPUT': os.path.abspath(html_dir),
00106 '$HTML_HEADER': header_filename, '$HTML_FOOTER': footer_filename,
00107 '$OUTPUT_DIRECTORY': html_dir,
00108 '$INCLUDE_PATH': include_path,
00109
00110 '$JAVADOC_AUTOBRIEF': rd_config.get('javadoc_autobrief', 'NO'),
00111 '$MULTILINE_CPP_IS_BRIEF': rd_config.get('multiline_cpp_is_brief', 'NO'),
00112 '$TAB_SIZE': rd_config.get('tab_size', '8'),
00113 '$ALIASES': rd_config.get('aliases', ''),
00114 '$EXAMPLE_PATTERNS': rd_config.get('example_patterns', ''),
00115 '$IMAGE_PATH': rd_config.get('image_path', path),
00116 '$EXCLUDE_SYMBOLS': rd_config.get('exclude_symbols', ''),
00117 }
00118 return instantiate_template(doxy_template, dvars)
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 def load_manifest_vars(ctx, rd_config, package, path, docdir, package_htmldir, m):
00133 author = license = dependencies = description = usedby = status = notes = li_vc = li_url = brief = ''
00134
00135
00136 home_url = 'http://ros.org/wiki/%s'%package
00137
00138 if rd_config:
00139 if 'homepage' in rd_config:
00140 home_url = rd_config['homepage']
00141
00142 project_link = '<a href="%s">%s</a>'%(home_url, package)
00143 if m is not None:
00144 license = m.license or ''
00145 author = m.author or ''
00146 description = m.description or ''
00147 status = m.status or ''
00148 notes = m.notes or ''
00149
00150 if m.brief:
00151 brief = ": "+m.brief
00152
00153 li_url = '<li>Homepage: <a href=\"%s\">%s</a></li>'%(m.url, m.url)
00154 if m.versioncontrol:
00155 vcurl = m.versioncontrol.url
00156 li_vc = '<li>Version Control (%s): <a href="%s">%s</a></li>'%(m.versioncontrol.type, vcurl, vcurl)
00157
00158 if m.depends:
00159 dependencies = "<ul>\n" + \
00160 li_package_links(ctx, package, [d.package for d in m.depends], docdir, package_htmldir)
00161 else:
00162 dependencies = "None<br />"
00163 else:
00164 print "no manifest [%s]"%(package)
00165
00166 dependson1 = roslib.rospack.rospackexec(['depends-on1', package]).split('\n')
00167
00168 dependson1 = [d for d in dependson1 if d and ctx.should_document(d)]
00169 if dependson1:
00170 usedby = "<ul>\n"+li_package_links(ctx, package, dependson1, docdir, package_htmldir)
00171 else:
00172 usedby = "None<br />"
00173
00174
00175 msgs = roslib.msgs.list_msg_types(package, False)
00176 srvs = roslib.srvs.list_srv_types(package, False)
00177
00178 return {'$package': package,
00179 '$projectlink': project_link, '$license': license,
00180 '$dependencies': dependencies, '$usedby': usedby,
00181 '$description': description, '$brief': brief,
00182 '$author': author, '$status':status,
00183 '$notes':notes, '$li_vc': li_vc, '$li_url': li_url,
00184 }
00185
00186
00187 def _write_to_file(f, tmpl):
00188 try:
00189 if type(tmpl) == str:
00190 f.write(tmpl)
00191 else:
00192 f.write(tmpl.encode('utf-8'))
00193 f.flush()
00194 except:
00195 print "ERROR, f[%s], tmpl[%s]"%(f, tmpl)
00196 raise
00197
00198 def get_doxygen_version():
00199 try:
00200 command = ['doxygen', '--version']
00201 version = Popen(command, stdout=PIPE, stderr=PIPE).communicate()[0].strip()
00202 except:
00203 version = None
00204 return version
00205
00206
00207
00208
00209 def header_template_name():
00210 doxygen_version = get_doxygen_version()
00211
00212 if doxygen_version is None:
00213 return None
00214 major, minor, patch = doxygen_version.split('.')
00215
00216 if int(major) > 1 or int(minor) > 7 or int(patch) > 3:
00217 return 'header-1.7.4.html'
00218 else:
00219 return 'header.html'
00220
00221
00222 def run_doxygen(package, doxygen_file, quiet=False):
00223 try:
00224 command = ['doxygen', doxygen_file]
00225 if quiet:
00226 Popen(command, stdout=PIPE, stderr=PIPE).communicate()
00227 else:
00228 print "doxygen-ating %s [%s]"%(package, ' '.join(command))
00229 Popen(command, stdout=PIPE).communicate()
00230 except OSError, (errno, strerr):
00231
00232 print """\nERROR: It appears that you do not have doxygen installed.
00233 If you are on Ubuntu/Debian, you can install doxygen by typing:
00234
00235 sudo apt-get install doxygen
00236 """
00237 sys.exit(1)
00238
00239
00240 def run_rxdeps(package, pkg_doc_dir):
00241 try:
00242 command = ['rxdeps', '-s', '--target=%s'%package, '--cluster', '-o', os.path.join(pkg_doc_dir, '%s_deps.pdf'%package)]
00243 print "rxdeping %s [%s]"%(package, ' '.join(command))
00244 Popen(command, stdout=PIPE).communicate()
00245 except OSError, (errno, strerr):
00246 print >> sys.stderr, """\nERROR: It appears that you do not have rxdeps installed.
00247 Package dependency tree links will not work properly.
00248 """
00249 except:
00250 print >> sys.stderr, "ERROR: rxdeps failed"
00251
00252
00253
00254
00255
00256 def generate_doxygen(ctx, disable_rxdeps=False):
00257 quiet = ctx.quiet
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 tmp = '/tmp/rosdoc'
00270 if not os.path.exists(tmp):
00271 os.mkdir(tmp)
00272 example_path = tmp
00273
00274 success = []
00275
00276 dir = ctx.docdir
00277
00278 packages = ctx.packages
00279
00280 doc_packages = ctx.doc_packages
00281 external_docs = ctx.external_docs
00282 rd_configs = ctx.rd_configs
00283 manifests = ctx.manifests
00284
00285 tmpls = [header_template, footer_template, manifest_template]
00286 try:
00287 for package, path in packages.iteritems():
00288 if not package in doc_packages or \
00289 not ctx.has_builder(package, 'doxygen'):
00290 continue
00291
00292
00293
00294
00295 rd_config = rd_configs.get(package, None)
00296 if rd_config:
00297
00298
00299 rd_config = [d for d in ctx.rd_configs[package] if d['builder'] == 'doxygen'][0]
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 pkg_doc_dir = html_path(package, ctx.docdir)
00312
00313
00314 html_dir = html_path(package, ctx.docdir)
00315 if rd_config and 'output_dir' in rd_config:
00316 html_dir = os.path.join(html_dir, rd_config['output_dir'])
00317
00318
00319 if not os.path.exists(pkg_doc_dir):
00320 os.makedirs(pkg_doc_dir)
00321
00322 files = []
00323 try:
00324 header_file = tempfile.NamedTemporaryFile('w+')
00325 footer_file = tempfile.NamedTemporaryFile('w+')
00326 doxygen_file = tempfile.NamedTemporaryFile('w+')
00327 manifest_file = open(os.path.join(example_path, 'manifest.html'), 'w')
00328 files = [header_file, footer_file, manifest_file, doxygen_file]
00329 to_delete = [manifest_file]
00330
00331
00332
00333 generate_msg_srv_includes(package, example_path, to_delete)
00334
00335
00336 manifest_ = manifests[package] if package in manifests else None
00337
00338 vars = load_manifest_vars(ctx, rd_config, package, path, dir, html_dir, manifest_)
00339 header, footer, manifest_html = [instantiate_template(t, vars) for t in tmpls]
00340
00341 if not disable_rxdeps:
00342 run_rxdeps(package, pkg_doc_dir)
00343 if package not in external_docs:
00344 doxy = \
00345 create_package_template(package, rd_config, manifest_,
00346 path, html_dir,
00347 header_file.name, footer_file.name,
00348 example_path)
00349 for f, tmpl in zip(files, [header, footer, manifest_html, doxy]):
00350 _write_to_file(f, tmpl)
00351
00352 run_doxygen(package, doxygen_file.name, quiet=quiet)
00353 else:
00354
00355
00356
00357
00358 external_link = ctx.external_docs[package]
00359
00360
00361 title = 'Main Page'
00362 if rd_config:
00363 title = rd_config.get('name', title)
00364 vars = { '$package': package, '$external_link': external_link,
00365 '$header': header, '$footer': footer,
00366 '$manifest': manifest_html,
00367
00368 '$relpath$': '../../',
00369 '$title': package+': '+title,
00370 }
00371
00372 with open(os.path.join(pkg_doc_dir, 'index.html'), 'w') as ext_html_file:
00373 _write_to_file(ext_html_file, instantiate_template(external_template, vars))
00374
00375
00376 import shutil
00377 dstyles_in = os.path.join(ctx.template_dir, 'doxygen.css')
00378 dstyles_css = os.path.join(html_dir, 'doxygen.css')
00379 shutil.copyfile(dstyles_in, dstyles_css)
00380
00381 success.append(package)
00382 except Exception as e:
00383 print >> sys.stderr, "ERROR: Doxygen of package [%s] failed: %s"%(package, str(e))
00384 finally:
00385 for f in files:
00386 f.close()
00387 finally:
00388 pass
00389 return success
00390
00391
00392
00393
00394 doxy_template = load_tmpl('doxy.template')
00395 external_template = load_tmpl('external.html')
00396
00397 header_template = load_tmpl(header_template_name())
00398 footer_template = load_tmpl('footer.html')
00399 manifest_template = load_tmpl('manifest.html')
00400
00401