1#!/usr/bin/env python3
2
3# External command, intended to be called with custom_target(),
4# meson.add_install_script() or meson.add_dist_script() in meson.build.
5
6#                     argv[1]      argv[2]     argv[3:]
7# doc-reference.py <subcommand> <MMDOCTOOLDIR> <xxx>...
8
9# <MMDOCTOOLDIR> is an absolute path in the source directory.
10
11import os
12import sys
13import subprocess
14import shutil
15
16subcommand = sys.argv[1]
17MMDOCTOOLDIR = sys.argv[2]
18
19# Invoked from custom_target() in meson.build.
20def doxygen():
21  #    argv[3]         argv[4:]
22  # <doxytagfile> <doc_input_files>...
23
24  # <doxytagfile> is a relative or absolute path in the build directory.
25  # <doc_input_files> are absolute paths in the source or build directory.
26  doxytagfile = sys.argv[3]
27  doc_outdir = os.path.dirname(doxytagfile)
28
29  # Export this variable for use in the Doxygen configuration file.
30  child_env = os.environ.copy()
31  child_env['MMDOCTOOLDIR'] = MMDOCTOOLDIR
32
33  # Remove old files.
34  if os.path.isfile(doxytagfile):
35    os.remove(doxytagfile)
36  shutil.rmtree(os.path.join(doc_outdir, 'html'), ignore_errors=True)
37
38  # Relative paths in Doxyfile assume that Doxygen is run from the
39  # build directory one level above Doxyfile.
40  doxygen_cwd = os.path.join(doc_outdir, '..')
41
42  DOXYGEN = child_env.get('DOXYGEN', None)
43  if not DOXYGEN:
44    DOXYGEN = 'doxygen'
45  doxygen_input = '@INCLUDE = ' + os.path.join('reference', 'Doxyfile') + '\n' \
46                + 'INPUT = "' + '" "'.join(sys.argv[4:]) + '"\n'
47  # (Starting with Python 3.7 text=True is a more understandable equivalent to
48  # universal_newlines=True. Let's use only features in Python 3.5.)
49  result = subprocess.run([DOXYGEN, '-'], input=doxygen_input,
50    universal_newlines=True, env=child_env, cwd=doxygen_cwd)
51  if result.returncode:
52    return result.returncode
53
54  cmd = [
55    'perl',
56    '--',
57    os.path.join(MMDOCTOOLDIR, 'doc-postprocess.pl'),
58    os.path.join(doc_outdir, 'html', '*.html'),
59  ]
60  return subprocess.run(cmd).returncode
61
62# Invoked from custom_target() in meson.build.
63def devhelp():
64  #    argv[3]       argv[4]       argv[5]     argv[6]
65  # <doxytagfile> <devhelpfile> <book_name> <book_title>
66
67  # <doxytagfile> and <devhelpfile> are relative or absolute paths in the build directory.
68  doxytagfile = sys.argv[3]
69  devhelpfile = sys.argv[4]
70  book_name = sys.argv[5]
71  book_title = sys.argv[6]
72  tagfile_to_devhelp = os.path.join(MMDOCTOOLDIR, 'tagfile-to-devhelp2.xsl')
73
74  # The parameters to the Doxygen-to-Devhelp XSLT script.
75  cmd = [
76    'xsltproc',
77    '--stringparam', 'book_title', book_title,
78    '--stringparam', 'book_name', book_name,
79    '--stringparam', 'book_base', 'html',
80    '-o', devhelpfile,
81    tagfile_to_devhelp,
82    doxytagfile,
83  ]
84  return subprocess.run(cmd).returncode
85
86# Invoked from meson.add_install_script().
87def install_doc():
88  #    argv[3]       argv[4]      argv[5]        argv[6:]
89  # <devhelpfile> <devhelpdir> <htmlrefdir> <docinstall_flags>...
90
91  # <devhelpfile> is a relative or absolute path in the build directory.
92  # <htmlrefdir> and <devhelpdir> are installation directories, relative to {prefix}.
93  devhelpfile = sys.argv[3]
94  destdir_devhelpdir = os.path.join(os.getenv('MESON_INSTALL_DESTDIR_PREFIX'), sys.argv[4])
95  destdir_htmlrefdir = os.path.join(os.getenv('MESON_INSTALL_DESTDIR_PREFIX'), sys.argv[5])
96  prefix_htmlrefdir = os.path.join(os.getenv('MESON_INSTALL_PREFIX'), sys.argv[5])
97  build_dir = os.path.dirname(devhelpfile)
98
99  # Create the installation directories, if they do not exist.
100  os.makedirs(destdir_htmlrefdir, exist_ok=True)
101  os.makedirs(destdir_devhelpdir, exist_ok=True)
102
103  # Install html files.
104  cmd = [
105    'perl',
106    '--',
107    os.path.join(MMDOCTOOLDIR, 'doc-install.pl'),
108    '--verbose',
109    '--mode=0644',
110  ] + sys.argv[6:] + [
111    '-t', destdir_htmlrefdir,
112    '--glob',
113    '--',
114    os.path.join(build_dir, 'html', '*'),
115  ]
116  result1 = subprocess.run(cmd)
117
118  # Install the Devhelp file.
119  # rstrip('/') means remove trailing /, if any.
120  cmd = [
121    'perl',
122    '--',
123    os.path.join(MMDOCTOOLDIR, 'doc-install.pl'),
124    '--verbose',
125    '--mode=0644',
126    '--book-base=' + prefix_htmlrefdir.rstrip('/'),
127    '-t', destdir_devhelpdir,
128    '--',
129    devhelpfile,
130  ]
131  result2 = subprocess.run(cmd)
132
133  if result1.returncode:
134    return result1.returncode
135  return result2.returncode
136
137# Invoked from meson.add_dist_script().
138def dist_doc():
139  #      argv[3]              argv[4]       argv[5]     argv[6]
140  # <doctool_dist_dir> <doc_ref_build_dir> <tagfile> <devhelpfile>
141
142  # <doctool_dist_dir> is a distribution directory, relative to MESON_DIST_ROOT.
143  # <doc_ref_build_dir> is a relative or absolute path in the build directory.
144  # <tagfile> and <devhelpfile> are relative or absolute paths in the build directory.
145  doctool_dist_dir = os.path.join(os.getenv('MESON_DIST_ROOT'), sys.argv[3])
146  doc_ref_build_dir = sys.argv[4]
147  tagfile = sys.argv[5]
148  devhelpfile = sys.argv[6]
149
150  # Create the distribution directory, if it does not exist.
151  os.makedirs(os.path.join(doctool_dist_dir, 'reference'), exist_ok=True)
152
153  # Distribute files that mm-common-get has copied to MMDOCTOOLDIR.
154  # shutil.copy() does not copy timestamps.
155  for file in ['doc-install.pl', 'doc-postprocess.pl', 'doxygen-extra.css', 'tagfile-to-devhelp2.xsl']:
156    shutil.copy(os.path.join(MMDOCTOOLDIR, file), doctool_dist_dir)
157
158  # Distribute built files: tag file, devhelp file, html files.
159  for file in [tagfile, devhelpfile]:
160    shutil.copy(file, os.path.join(doctool_dist_dir, 'reference'))
161  shutil.copytree(os.path.join(doc_ref_build_dir, 'html'),
162                  os.path.join(doctool_dist_dir, 'reference', 'html'),
163                  copy_function=shutil.copy)
164  return 0
165
166# ----- Main -----
167if subcommand == 'doxygen':
168  sys.exit(doxygen())
169if subcommand == 'devhelp':
170  sys.exit(devhelp())
171if subcommand == 'install_doc':
172  sys.exit(install_doc())
173if subcommand == 'dist_doc':
174  sys.exit(dist_doc())
175print(sys.argv[0], ': illegal subcommand,', subcommand)
176sys.exit(1)
177