Home | History | Annotate | Download | only in jsoncpp
      1 """Script to generate doxygen documentation.
      2 """
      3 from __future__ import print_function
      4 from devtools import tarball
      5 import re
      6 import os
      7 import os.path
      8 import sys
      9 import shutil
     10 
     11 def find_program(*filenames):
     12     """find a program in folders path_lst, and sets env[var]
     13     @param filenames: a list of possible names of the program to search for
     14     @return: the full path of the filename if found, or '' if filename could not be found
     15 """
     16     paths = os.environ.get('PATH', '').split(os.pathsep)
     17     suffixes = ('win32' in sys.platform ) and '.exe .com .bat .cmd' or ''
     18     for filename in filenames:
     19         for name in [filename+ext for ext in suffixes.split()]:
     20             for directory in paths:
     21                 full_path = os.path.join(directory, name)
     22                 if os.path.isfile(full_path):
     23                     return full_path
     24     return ''
     25 
     26 def do_subst_in_file(targetfile, sourcefile, dict):
     27     """Replace all instances of the keys of dict with their values.
     28     For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
     29     then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
     30     """
     31     try:
     32         f = open(sourcefile, 'rb')
     33         contents = f.read()
     34         f.close()
     35     except:
     36         print("Can't read source file %s"%sourcefile)
     37         raise
     38     for (k,v) in list(dict.items()):
     39         v = v.replace('\\','\\\\') 
     40         contents = re.sub(k, v, contents)
     41     try:
     42         f = open(targetfile, 'wb')
     43         f.write(contents)
     44         f.close()
     45     except:
     46         print("Can't write target file %s"%targetfile)
     47         raise
     48 
     49 def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
     50     config_file = os.path.abspath( config_file )
     51     doxygen_path = doxygen_path
     52     old_cwd = os.getcwd()
     53     try:
     54         os.chdir( working_dir )
     55         cmd = [doxygen_path, config_file]
     56         print('Running:', ' '.join( cmd ))
     57         try:
     58             import subprocess
     59         except:
     60             if os.system( ' '.join( cmd ) ) != 0:
     61                 print('Documentation generation failed')
     62                 return False
     63         else:
     64             if is_silent:
     65                 process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
     66             else:
     67                 process = subprocess.Popen( cmd )
     68             stdout, _ = process.communicate()
     69             if process.returncode:
     70                 print('Documentation generation failed:')
     71                 print(stdout)
     72                 return False
     73         return True
     74     finally:
     75         os.chdir( old_cwd )
     76 
     77 def build_doc( options,  make_release=False ):
     78     if make_release:
     79         options.make_tarball = True
     80         options.with_dot = True
     81         options.with_html_help = True
     82         options.with_uml_look = True
     83         options.open = False
     84         options.silent = True
     85 
     86     version = open('version','rt').read().strip()
     87     output_dir = 'dist/doxygen' # relative to doc/doxyfile location.
     88     if not os.path.isdir( output_dir ):
     89         os.makedirs( output_dir )
     90     top_dir = os.path.abspath( '.' )
     91     html_output_dirname = 'jsoncpp-api-html-' + version
     92     tarball_path = os.path.join( 'dist', html_output_dirname + '.tar.gz' )
     93     warning_log_path = os.path.join( output_dir, '../jsoncpp-doxygen-warning.log' )
     94     html_output_path = os.path.join( output_dir, html_output_dirname )
     95     def yesno( bool ):
     96         return bool and 'YES' or 'NO'
     97     subst_keys = {
     98         '%JSONCPP_VERSION%': version,
     99         '%DOC_TOPDIR%': '',
    100         '%TOPDIR%': top_dir,
    101         '%HTML_OUTPUT%': os.path.join( '..', output_dir, html_output_dirname ),
    102         '%HAVE_DOT%': yesno(options.with_dot),
    103         '%DOT_PATH%': os.path.split(options.dot_path)[0],
    104         '%HTML_HELP%': yesno(options.with_html_help),
    105         '%UML_LOOK%': yesno(options.with_uml_look),
    106         '%WARNING_LOG_PATH%': os.path.join( '..', warning_log_path )
    107         }
    108 
    109     if os.path.isdir( output_dir ):
    110         print('Deleting directory:', output_dir)
    111         shutil.rmtree( output_dir )
    112     if not os.path.isdir( output_dir ):
    113         os.makedirs( output_dir )
    114 
    115     do_subst_in_file( 'doc/doxyfile', 'doc/doxyfile.in', subst_keys )
    116     ok = run_doxygen( options.doxygen_path, 'doc/doxyfile', 'doc', is_silent=options.silent )
    117     if not options.silent:
    118         print(open(warning_log_path, 'rb').read())
    119     index_path = os.path.abspath(os.path.join('doc', subst_keys['%HTML_OUTPUT%'], 'index.html'))
    120     print('Generated documentation can be found in:')
    121     print(index_path)
    122     if options.open:
    123         import webbrowser
    124         webbrowser.open( 'file://' + index_path )
    125     if options.make_tarball:
    126         print('Generating doc tarball to', tarball_path)
    127         tarball_sources = [
    128             output_dir,
    129             'README.txt',
    130             'LICENSE',
    131             'NEWS.txt',
    132             'version'
    133             ]
    134         tarball_basedir = os.path.join( output_dir, html_output_dirname )
    135         tarball.make_tarball( tarball_path, tarball_sources, tarball_basedir, html_output_dirname )
    136     return tarball_path, html_output_dirname
    137 
    138 def main():
    139     usage = """%prog
    140     Generates doxygen documentation in build/doxygen.
    141     Optionaly makes a tarball of the documentation to dist/.
    142 
    143     Must be started in the project top directory.    
    144     """
    145     from optparse import OptionParser
    146     parser = OptionParser(usage=usage)
    147     parser.allow_interspersed_args = False
    148     parser.add_option('--with-dot', dest="with_dot", action='store_true', default=False,
    149         help="""Enable usage of DOT to generate collaboration diagram""")
    150     parser.add_option('--dot', dest="dot_path", action='store', default=find_program('dot'),
    151         help="""Path to GraphViz dot tool. Must be full qualified path. [Default: %default]""")
    152     parser.add_option('--doxygen', dest="doxygen_path", action='store', default=find_program('doxygen'),
    153         help="""Path to Doxygen tool. [Default: %default]""")
    154     parser.add_option('--with-html-help', dest="with_html_help", action='store_true', default=False,
    155         help="""Enable generation of Microsoft HTML HELP""")
    156     parser.add_option('--no-uml-look', dest="with_uml_look", action='store_false', default=True,
    157         help="""Generates DOT graph without UML look [Default: False]""")
    158     parser.add_option('--open', dest="open", action='store_true', default=False,
    159         help="""Open the HTML index in the web browser after generation""")
    160     parser.add_option('--tarball', dest="make_tarball", action='store_true', default=False,
    161         help="""Generates a tarball of the documentation in dist/ directory""")
    162     parser.add_option('-s', '--silent', dest="silent", action='store_true', default=False,
    163         help="""Hides doxygen output""")
    164     parser.enable_interspersed_args()
    165     options, args = parser.parse_args()
    166     build_doc( options )
    167 
    168 if __name__ == '__main__':
    169     main()
    170