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 distutils.version import StrictVersion
00037 from subprocess import Popen, PIPE
00038 import shutil
00039 import tempfile
00040 import shutil
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 = description = 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 else:
00158 print "no manifest [%s]"%(package)
00159
00160
00161 msgs = roslib.msgs.list_msg_types(package, False)
00162 srvs = roslib.srvs.list_srv_types(package, False)
00163
00164 return {'$package': package,
00165 '$projectlink': project_link, '$license': license,
00166 '$description': description, '$brief': brief,
00167 '$author': author, '$status':status,
00168 '$notes':notes, '$li_vc': li_vc, '$li_url': li_url,
00169 }
00170
00171
00172 def _write_to_file(f, tmpl):
00173 try:
00174 if type(tmpl) == str:
00175 f.write(tmpl)
00176 else:
00177 f.write(tmpl.encode('utf-8'))
00178 f.flush()
00179 except:
00180 print "ERROR, f[%s], tmpl[%s]"%(f, tmpl)
00181 raise
00182
00183 def get_doxygen_version():
00184 try:
00185 command = ['doxygen', '--version']
00186 version = Popen(command, stdout=PIPE, stderr=PIPE).communicate()[0].strip()
00187 except:
00188 version = None
00189 return version
00190
00191
00192
00193
00194 def header_template_name():
00195 doxygen_version = get_doxygen_version()
00196
00197 if doxygen_version is None:
00198 return None
00199 doxygen_version_splitted = doxygen_version.split('.')
00200 major = doxygen_version_splitted[0]
00201 minor = doxygen_version_splitted[1]
00202 patch = doxygen_version_splitted[2]
00203 if len(doxygen_version_splitted) > 3:
00204 build = doxygen_version_splitted[3]
00205
00206 if StrictVersion('%s.%s.%s'%(major, minor, patch)) > StrictVersion('1.7.3'):
00207 return 'header-1.7.4.html'
00208 else:
00209 return 'header.html'
00210
00211
00212 def run_doxygen(package, doxygen_file, quiet=False):
00213 try:
00214 command = ['doxygen', doxygen_file]
00215 if quiet:
00216 Popen(command, stdout=PIPE, stderr=PIPE).communicate()
00217 else:
00218 print "doxygen-ating %s [%s]"%(package, ' '.join(command))
00219 Popen(command, stdout=PIPE).communicate()
00220 except OSError, (errno, strerr):
00221
00222 print """\nERROR: It appears that you do not have doxygen installed.
00223 If you are on Ubuntu/Debian, you can install doxygen by typing:
00224
00225 sudo apt-get install doxygen
00226 """
00227 sys.exit(1)
00228
00229
00230
00231 def generate_doxygen(ctx):
00232 quiet = ctx.quiet
00233
00234
00235
00236
00237
00238
00239
00240
00241 example_path = tempfile.mkdtemp(prefix='rosdoc_doxygen')
00242
00243 success = []
00244
00245 dir = ctx.docdir
00246
00247 packages = ctx.packages
00248
00249 doc_packages = ctx.doc_packages
00250 external_docs = ctx.external_docs
00251 rd_configs = ctx.rd_configs
00252 manifests = ctx.manifests
00253
00254 tmpls = [header_template, footer_template, manifest_template]
00255 try:
00256 for package, path in packages.iteritems():
00257 if not package in doc_packages or \
00258 not ctx.has_builder(package, 'doxygen'):
00259 continue
00260
00261
00262
00263
00264 rd_config = rd_configs.get(package, None)
00265 if rd_config:
00266
00267
00268 rd_config = [d for d in ctx.rd_configs[package] if d['builder'] == 'doxygen'][0]
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 pkg_doc_dir = html_path(package, ctx.docdir)
00281
00282
00283 html_dir = html_path(package, ctx.docdir)
00284 if rd_config and 'output_dir' in rd_config:
00285 html_dir = os.path.join(html_dir, rd_config['output_dir'])
00286
00287
00288 if not os.path.exists(pkg_doc_dir):
00289 os.makedirs(pkg_doc_dir)
00290
00291 files = []
00292 try:
00293 header_file = tempfile.NamedTemporaryFile('w+')
00294 footer_file = tempfile.NamedTemporaryFile('w+')
00295 doxygen_file = tempfile.NamedTemporaryFile('w+')
00296 manifest_file = open(os.path.join(example_path, 'manifest.html'), 'w')
00297 files = [header_file, footer_file, manifest_file, doxygen_file]
00298 to_delete = [manifest_file]
00299
00300
00301
00302 generate_msg_srv_includes(package, example_path, to_delete)
00303
00304
00305 manifest_ = manifests[package] if package in manifests else None
00306
00307 vars = load_manifest_vars(ctx, rd_config, package, path, dir, html_dir, manifest_)
00308 header, footer, manifest_html = [instantiate_template(t, vars) for t in tmpls]
00309
00310 if package not in external_docs:
00311 doxy = \
00312 create_package_template(package, rd_config, manifest_,
00313 path, html_dir,
00314 header_file.name, footer_file.name,
00315 example_path)
00316 for f, tmpl in zip(files, [header, footer, manifest_html, doxy]):
00317 _write_to_file(f, tmpl)
00318
00319 run_doxygen(package, doxygen_file.name, quiet=quiet)
00320
00321
00322 dstyles_in = os.path.join(ctx.template_dir, 'doxygen.css')
00323 dstyles_css = os.path.join(html_dir, 'doxygen.css')
00324 shutil.copyfile(dstyles_in, dstyles_css)
00325
00326 success.append(package)
00327 except Exception as e:
00328 print >> sys.stderr, "ERROR: Doxygen of package [%s] failed: %s"%(package, str(e))
00329 finally:
00330 for f in files:
00331 f.close()
00332 finally:
00333 shutil.rmtree(example_path)
00334 return success
00335
00336
00337 doxy_template = load_tmpl('doxy.template')
00338
00339 header_template_filename = header_template_name()
00340 if header_template_filename is None:
00341 raise Exception("Doxygen is not installed. Please install it to continue.")
00342 else:
00343 header_template = load_tmpl(header_template_filename)
00344 footer_template = load_tmpl('footer.html')
00345 manifest_template = load_tmpl('manifest.html')