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