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')