Implement OCSP stapling in Windows BoringSSL port.
[chromium-blink-merge.git] / native_client_sdk / src / doc / doxygen / generate_docs.py
blobc28b6b260fe57f4ebab506ff839472aec1af2f6e
1 #!/usr/bin/python
3 # Copyright (c) 2014 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
7 import collections
8 import json
9 import optparse
10 import os
11 import shutil
12 import subprocess
13 import sys
14 import tempfile
15 import urllib2
18 if sys.version_info < (2, 7, 0):
19 sys.stderr.write("python 2.7 or later is required run this script\n")
20 sys.exit(1)
23 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
24 DOC_DIR = os.path.dirname(SCRIPT_DIR)
27 ChannelInfo = collections.namedtuple('ChannelInfo', ['branch', 'version'])
30 def Trace(msg):
31 if Trace.verbose:
32 sys.stderr.write(str(msg) + '\n')
34 Trace.verbose = False
37 def GetChannelInfo():
38 url = 'http://omahaproxy.appspot.com/json'
39 u = urllib2.urlopen(url)
40 try:
41 data = json.loads(u.read())
42 finally:
43 u.close()
45 channel_info = {}
46 for os_row in data:
47 osname = os_row['os']
48 if osname not in ('win', 'mac', 'linux'):
49 continue
50 for version_row in os_row['versions']:
51 channel = version_row['channel']
52 # We don't display canary docs.
53 if channel == 'canary':
54 continue
56 version = version_row['version'].split('.')[0] # Major version
57 branch = version_row['true_branch']
58 if branch is None:
59 branch = 'trunk'
61 if channel in channel_info:
62 existing_info = channel_info[channel]
63 if branch != existing_info.branch:
64 sys.stderr.write('Warning: found different branch numbers for '
65 'channel %s: %s vs %s. Using %s.\n' % (
66 channel, branch, existing_info.branch, existing_info.branch))
67 else:
68 channel_info[channel] = ChannelInfo(branch, version)
70 return channel_info
73 def RemoveFile(filename):
74 if os.path.exists(filename):
75 os.remove(filename)
78 def RemoveDir(dirname):
79 if os.path.exists(dirname):
80 shutil.rmtree(dirname)
83 def HasBranchHeads():
84 cmd = ['git', 'for-each-ref', '--format=%(refname)',
85 'refs/remotes/branch-heads']
86 output = subprocess.check_output(cmd).splitlines()
87 return output != []
90 def CheckoutDirectories(dest_dirname, refname, root_path, patterns=None):
91 treeish = '%s:%s' % (refname, root_path)
92 cmd = ['git', 'ls-tree', '--full-tree', '-r', treeish]
93 if patterns:
94 cmd.extend(patterns)
96 Trace('Running \"%s\":' % ' '.join(cmd))
97 output = subprocess.check_output(cmd)
98 for line in output.splitlines():
99 info, rel_filename = line.split('\t')
100 sha = info.split(' ')[2]
102 Trace(' %s %s' % (sha, rel_filename))
104 cmd = ['git', 'show', sha]
105 blob = subprocess.check_output(cmd)
106 filename = os.path.join(dest_dirname, rel_filename)
107 dirname = os.path.dirname(filename)
108 if not os.path.exists(dirname):
109 os.makedirs(dirname)
111 Trace(' writing to %s' % filename)
112 with open(filename, 'w') as f:
113 f.write(blob)
116 def CheckoutPepperDocs(branch, doc_dirname):
117 Trace('Removing directory %s' % doc_dirname)
118 RemoveDir(doc_dirname)
120 if branch == 'master':
121 refname = 'refs/remotes/origin/master'
122 else:
123 refname = 'refs/remotes/branch-heads/%s' % branch
125 Trace('Checking out docs into %s' % doc_dirname)
126 subdirs = ['api', 'generators', 'cpp', 'utility']
127 CheckoutDirectories(doc_dirname, refname, 'ppapi', subdirs)
129 # The IDL generator needs PLY (a python lexing library); check it out into
130 # generators.
131 ply_dirname = os.path.join(doc_dirname, 'generators', 'ply')
132 Trace('Checking out PLY into %s' % ply_dirname)
133 CheckoutDirectories(ply_dirname, refname, 'third_party/ply')
136 def FixPepperDocLinks(doc_dirname):
137 # TODO(binji): We can remove this step when the correct links are in the
138 # stable branch.
139 Trace('Looking for links to fix in Pepper headers...')
140 for root, dirs, filenames in os.walk(doc_dirname):
141 # Don't recurse into .svn
142 if '.svn' in dirs:
143 dirs.remove('.svn')
145 for filename in filenames:
146 header_filename = os.path.join(root, filename)
147 Trace(' Checking file %r...' % header_filename)
148 replacements = {
149 '<a href="/native-client/{{pepperversion}}/devguide/coding/audio">':
150 '<a href="/native-client/devguide/coding/audio.html">',
151 '<a href="/native-client/devguide/coding/audio">':
152 '<a href="/native-client/devguide/coding/audio.html">',
153 '<a href="/native-client/{{pepperversion}}/pepperc/globals_defs"':
154 '<a href="globals_defs.html"',
155 '<a href="../pepperc/ppb__image__data_8h.html">':
156 '<a href="../c/ppb__image__data_8h.html">'}
158 with open(header_filename) as f:
159 lines = []
160 replaced = False
161 for line in f:
162 for find, replace in replacements.iteritems():
163 pos = line.find(find)
164 if pos != -1:
165 Trace(' Found %r...' % find)
166 replaced = True
167 line = line[:pos] + replace + line[pos + len(find):]
168 lines.append(line)
170 if replaced:
171 Trace(' Writing new file.')
172 with open(header_filename, 'w') as f:
173 f.writelines(lines)
176 def GenerateCHeaders(pepper_version, doc_dirname):
177 script = os.path.join(os.pardir, 'generators', 'generator.py')
178 cwd = os.path.join(doc_dirname, 'api')
179 out_dirname = os.path.join(os.pardir, 'c')
180 cmd = [sys.executable, script, '--cgen', '--release', 'M' + pepper_version,
181 '--wnone', '--dstroot', out_dirname]
182 Trace('Generating C Headers for version %s\n %s' % (
183 pepper_version, ' '.join(cmd)))
184 subprocess.check_call(cmd, cwd=cwd)
187 def GenerateDoxyfile(template_filename, out_dirname, doc_dirname, doxyfile):
188 Trace('Writing Doxyfile "%s" (from template %s)' % (
189 doxyfile, template_filename))
191 with open(template_filename) as f:
192 data = f.read()
194 with open(doxyfile, 'w') as f:
195 f.write(data % {
196 'out_dirname': out_dirname,
197 'doc_dirname': doc_dirname,
198 'script_dirname': SCRIPT_DIR})
201 def RunDoxygen(out_dirname, doxyfile):
202 Trace('Removing old output directory %s' % out_dirname)
203 RemoveDir(out_dirname)
205 Trace('Making new output directory %s' % out_dirname)
206 os.makedirs(out_dirname)
208 doxygen = os.environ.get('DOXYGEN', 'doxygen')
209 cmd = [doxygen, doxyfile]
210 Trace('Running Doxygen:\n %s' % ' '.join(cmd))
211 subprocess.check_call(cmd)
214 def RunDoxyCleanup(out_dirname):
215 script = os.path.join(SCRIPT_DIR, 'doxy_cleanup.py')
216 cmd = [sys.executable, script, out_dirname]
217 if Trace.verbose:
218 cmd.append('-v')
219 Trace('Running doxy_cleanup:\n %s' % ' '.join(cmd))
220 subprocess.check_call(cmd)
223 def RunRstIndex(kind, channel, pepper_version, out_dirname, out_rst_filename):
224 assert kind in ('root', 'c', 'cpp')
225 script = os.path.join(SCRIPT_DIR, 'rst_index.py')
226 cmd = [sys.executable, script,
227 '--' + kind,
228 '--channel', channel,
229 '--version', pepper_version,
230 out_dirname,
231 '-o', out_rst_filename]
232 Trace('Running rst_index:\n %s' % ' '.join(cmd))
233 subprocess.check_call(cmd)
236 def GetRstName(kind, channel):
237 if channel == 'stable':
238 filename = '%s-api.rst' % kind
239 else:
240 filename = '%s-api-%s.rst' % (kind, channel)
241 return os.path.join(DOC_DIR, filename)
244 def GenerateDocs(root_dirname, channel, pepper_version, branch):
245 Trace('Generating docs for %s (branch %s)' % (channel, branch))
246 pepper_dirname = 'pepper_%s' % channel
247 out_dirname = os.path.join(root_dirname, pepper_dirname)
249 try:
250 svn_dirname = tempfile.mkdtemp(prefix=pepper_dirname)
251 doxyfile_dirname = tempfile.mkdtemp(prefix='%s_doxyfiles' % pepper_dirname)
253 CheckoutPepperDocs(branch, svn_dirname)
254 FixPepperDocLinks(svn_dirname)
255 GenerateCHeaders(pepper_version, svn_dirname)
257 doxyfile_c = ''
258 doxyfile_cpp = ''
260 # Generate Root index
261 rst_index_root = os.path.join(DOC_DIR, pepper_dirname, 'index.rst')
262 RunRstIndex('root', channel, pepper_version, out_dirname, rst_index_root)
264 # Generate C docs
265 out_dirname_c = os.path.join(out_dirname, 'c')
266 doxyfile_c = os.path.join(doxyfile_dirname, 'Doxyfile.c.%s' % channel)
267 doxyfile_c_template = os.path.join(SCRIPT_DIR, 'Doxyfile.c.template')
268 rst_index_c = GetRstName('c', channel)
269 GenerateDoxyfile(doxyfile_c_template, out_dirname_c, svn_dirname,
270 doxyfile_c)
271 RunDoxygen(out_dirname_c, doxyfile_c)
272 RunDoxyCleanup(out_dirname_c)
273 RunRstIndex('c', channel, pepper_version, out_dirname_c, rst_index_c)
275 # Generate C++ docs
276 out_dirname_cpp = os.path.join(out_dirname, 'cpp')
277 doxyfile_cpp = os.path.join(doxyfile_dirname, 'Doxyfile.cpp.%s' % channel)
278 doxyfile_cpp_template = os.path.join(SCRIPT_DIR, 'Doxyfile.cpp.template')
279 rst_index_cpp = GetRstName('cpp', channel)
280 GenerateDoxyfile(doxyfile_cpp_template, out_dirname_cpp, svn_dirname,
281 doxyfile_cpp)
282 RunDoxygen(out_dirname_cpp, doxyfile_cpp)
283 RunDoxyCleanup(out_dirname_cpp)
284 RunRstIndex('cpp', channel, pepper_version, out_dirname_cpp, rst_index_cpp)
285 finally:
286 # Cleanup
287 RemoveDir(svn_dirname)
288 RemoveDir(doxyfile_dirname)
291 def main(argv):
292 parser = optparse.OptionParser(usage='Usage: %prog [options] <out_directory>')
293 parser.add_option('-v', '--verbose',
294 help='Verbose output', action='store_true')
295 options, dirs = parser.parse_args(argv)
297 if options.verbose:
298 Trace.verbose = True
300 if len(dirs) != 1:
301 parser.error('Expected an output directory')
303 channel_info = GetChannelInfo()
304 for channel, info in channel_info.iteritems():
305 GenerateDocs(dirs[0], channel, info.version, info.branch)
307 return 0
310 if __name__ == '__main__':
311 try:
312 rtn = main(sys.argv[1:])
313 except KeyboardInterrupt:
314 sys.stderr.write('%s: interrupted\n' % os.path.basename(__file__))
315 rtn = 1
316 sys.exit(rtn)