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