#!/usr/bin/env python
# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Script to generate rst index file doxygen generated html files.
"""
import argparse
import cStringIO
import fnmatch
import os
import re
import sys
VALID_CHANNELS = ('stable', 'beta', 'dev')
ROOT_FILE_CONTENTS = """\
.. _pepper_%(channel)s_index:
:orphan:
.. DO NOT EDIT! This document is auto-generated by doxygen/rst_index.py.
.. include:: /migration/deprecation.inc
########################################
Pepper API Reference (%(channel_title)s)
########################################
This page lists the API for Pepper %(version)s. Apps that use this API can
run in Chrome %(version)s or higher.
:ref:`Pepper C API Reference <pepper_%(channel)s_c_index>`
===========================================================
:ref:`Pepper C++ API Reference <pepper_%(channel)s_cpp_index>`
===============================================================
"""
C_FILE_CONTENTS = """\
.. _pepper_%(channel)s_c_index:
.. _c-api%(channel_alt)s:
.. DO NOT EDIT! This document is auto-generated by doxygen/rst_index.py.
.. include:: /migration/deprecation.inc
##########################################
Pepper C API Reference (%(channel_title)s)
##########################################
This page lists the C API for Pepper %(version)s. Apps that use this API can
run in Chrome %(version)s or higher.
`Interfaces <pepper_%(channel)s/c/group___interfaces.html>`__
=============================================================
%(interfaces)s
`Structures <pepper_%(channel)s/c/group___structs.html>`__
==========================================================
%(structures)s
`Functions <pepper_%(channel)s/c/group___functions.html>`__
===========================================================
`Enums <pepper_%(channel)s/c/group___enums.html>`__
===================================================
`Typedefs <pepper_%(channel)s/c/group___typedefs.html>`__
=========================================================
`Macros <pepper_%(channel)s/c/globals_defs.html>`__
===================================================
Files
=====
%(files)s
"""
C_INTERFACE_WILDCARDS = ['struct_p_p_p__*', 'struct_p_p_b__*']
C_STRUCT_WILDCARDS = ['struct_p_p__*', 'union_p_p__*']
CPP_FILE_CONTENTS = """\
.. _pepper_%(channel)s_cpp_index:
.. _cpp-api%(channel_alt)s:
.. DO NOT EDIT! This document is auto-generated by doxygen/rst_index.py.
.. include:: /migration/deprecation.inc
############################################
Pepper C++ API Reference (%(channel_title)s)
############################################
This page lists the C++ API for Pepper %(version)s. Apps that use this API can
run in Chrome %(version)s or higher.
`Classes <pepper_%(channel)s/cpp/inherits.html>`__
==================================================
%(classes)s
Files
=====
%(files)s
"""
CPP_CLASSES_WILDCARDS = ['classpp_1_1*.html']
CPP_CLASSES_EXCLUDES = ['*-members*']
FILE_WILDCARDS = ['*_8h.html']
def GetName(filename):
filename = os.path.splitext(filename)[0]
out = ''
if filename.startswith('struct_p_p_b__'):
mangle = filename[7:] # skip "struct_"
elif filename.startswith('struct_p_p_p__'):
mangle = filename[7:] # skip "struct_"
elif filename.startswith('struct_p_p__'):
mangle = filename[7:] # skip "struct_"
elif filename.startswith('union_p_p__'):
mangle = filename[6:] # skip "union_"
elif filename.startswith('classpp_1_1_'):
mangle = filename[12:]
elif filename.startswith('classpp_1_1ext_1_1_'):
out = 'Ext::' # maybe 'ext::' ?
mangle = filename[19:]
elif filename.startswith('classpp_1_1internal_1_1_'):
out = 'Internal::' # maybe 'internal::'
mangle = filename[24:]
elif filename.startswith('structpp_1_1internal_1_1_'):
out = 'Internal::'
mangle = filename[25:]
elif filename.endswith('_8h'):
return filename[:-3].replace('__', '_') + '.h'
else:
print 'No match: ' + filename
cap = True
for c in mangle:
if c == '_':
if cap:
# If cap is True, we've already read one underscore. The second means
# that we should insert a literal underscore.
cap = False
else:
cap = True
continue
if cap:
c = c.upper()
cap = False
out += c
# Strip trailing version number (e.g. PPB_Audio_1_1 -> PPB_Audio)
return re.sub(r'_\d_\d$', '', out)
def GetPath(filepath):
if os.path.exists(filepath):
return filepath
raise OSError('Couldn\'t find: ' + filepath)
def MakeReSTListFromFiles(prefix, path, matches, excludes=None):
dir_files = os.listdir(path)
good_files = []
for match in matches:
good_files.extend(fnmatch.filter(dir_files, match))
if excludes:
for exclude in excludes:
good_files = [filename for filename in good_files
if not fnmatch.fnmatch(filename, exclude)]
good_files.sort()
return '\n'.join(' * `%s <%s/%s>`__\n' % (GetName(f), prefix, f)
for f in good_files)
def MakeTitleCase(s):
return s[0].upper() + s[1:]
def MakeChannelAlt(channel):
if channel == 'stable':
return ''
else:
return '-' + channel
def GenerateRootIndex(channel, version, out_filename):
channel_title = MakeTitleCase(channel)
channel_alt = MakeChannelAlt(channel)
# Use StringIO so we don't write out a partial file on error.
output = cStringIO.StringIO()
output.write(ROOT_FILE_CONTENTS % vars())
with open(out_filename, 'w') as f:
f.write(output.getvalue())
def GenerateCIndex(root_dir, channel, version, out_filename):
prefix = 'pepper_%s/c' % channel
interfaces = MakeReSTListFromFiles(prefix, root_dir, C_INTERFACE_WILDCARDS)
structures = MakeReSTListFromFiles(prefix, root_dir, C_STRUCT_WILDCARDS)
files = MakeReSTListFromFiles(prefix, root_dir, FILE_WILDCARDS)
channel_title = MakeTitleCase(channel)
channel_alt = MakeChannelAlt(channel)
# Use StringIO so we don't write out a partial file on error.
output = cStringIO.StringIO()
output.write(C_FILE_CONTENTS % vars())
with open(out_filename, 'w') as f:
f.write(output.getvalue())
def GenerateCppIndex(root_dir, channel, version, out_filename):
prefix = 'pepper_%s/cpp' % channel
classes = MakeReSTListFromFiles(prefix, root_dir, CPP_CLASSES_WILDCARDS,
CPP_CLASSES_EXCLUDES)
files = MakeReSTListFromFiles(prefix, root_dir, FILE_WILDCARDS)
channel_title = MakeTitleCase(channel)
channel_alt = MakeChannelAlt(channel)
# Use StringIO so we don't write out a partial file on error.
output = cStringIO.StringIO()
output.write(CPP_FILE_CONTENTS % vars())
with open(out_filename, 'w') as f:
f.write(output.getvalue())
def main(argv):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--channel', help='pepper channel (stable, beta, dev)')
parser.add_argument('--version', help='pepper version (e.g. 32, 33, etc.)')
parser.add_argument('--root', help='Generate root API index',
action='store_true', default=False)
parser.add_argument('--c', help='Generate C API index', action='store_true',
default=False)
parser.add_argument('--cpp', help='Generate C++ API index',
action='store_true', default=False)
parser.add_argument('directory', help='input directory')
parser.add_argument('output_file', help='output file')
options = parser.parse_args(argv)
if options.channel not in VALID_CHANNELS:
parser.error('Expected channel to be one of %s' % ', '.join(VALID_CHANNELS))
if sum((options.c, options.cpp, options.root)) != 1:
parser.error('Exactly one of --c/--cpp/--root flags is required.')
if options.c:
GenerateCIndex(options.directory, options.channel, options.version,
options.output_file)
elif options.cpp:
GenerateCppIndex(options.directory, options.channel, options.version,
options.output_file)
elif options.root:
GenerateRootIndex(options.channel, options.version,
options.output_file)
else:
assert(False)
return 0
if __name__ == '__main__':
try:
rtn = main(sys.argv[1:])
except KeyboardInterrupt:
sys.stderr.write('%s: interrupted\n' % os.path.basename(__file__))
rtn = 1
sys.exit(rtn)