blob: 0b61c397e433cdfe21982c8846869522ed374963 [file] [log] [blame]
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -04001"""Script to generate doxygen documentation.
2"""
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -05003from __future__ import print_function
4from devtools import tarball
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -04005import re
6import os
7import os.path
8import sys
9import shutil
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040010
11def 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
26def 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:
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050036 print("Can't read source file %s"%sourcefile)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040037 raise
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050038 for (k,v) in list(dict.items()):
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040039 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:
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050046 print("Can't write target file %s"%targetfile)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040047 raise
48
49def 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]
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050056 print('Running:', ' '.join( cmd ))
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040057 try:
58 import subprocess
59 except:
60 if os.system( ' '.join( cmd ) ) != 0:
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050061 print('Documentation generation failed')
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040062 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:
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050070 print('Documentation generation failed:')
71 print(stdout)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040072 return False
73 return True
74 finally:
75 os.chdir( old_cwd )
76
77def 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 ):
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500110 print('Deleting directory:', output_dir)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400111 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:
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500118 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)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400122 if options.open:
123 import webbrowser
124 webbrowser.open( 'file://' + index_path )
125 if options.make_tarball:
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500126 print('Generating doc tarball to', tarball_path)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400127 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
138def 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
168if __name__ == '__main__':
169 main()