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