1#!/usr/bin/env python 2# 3# Copyright 2015 The Chromium Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7import argparse 8import itertools 9import os 10import shutil 11import sys 12import tempfile 13 14REPOSITORY_ROOT = os.path.abspath( 15 os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)) 16 17sys.path.insert(0, os.path.join(REPOSITORY_ROOT, 'build/android/gyp')) 18sys.path.insert(0, os.path.join(REPOSITORY_ROOT, 'net/tools/net_docs')) 19# pylint: disable=wrong-import-position 20from util import build_utils 21import action_helpers # build_utils adds //build to sys.path. 22import net_docs 23from markdown.postprocessors import Postprocessor 24from markdown.extensions import Extension 25# pylint: enable=wrong-import-position 26 27DOCLAVA_DIR = os.path.join(REPOSITORY_ROOT, 'buildtools', 'android', 'doclava') 28SDK_DIR = os.path.join(REPOSITORY_ROOT, 'third_party', 'android_sdk', 'public') 29# TODO(b/260694901) Remove this usage of Java 11 as soon as Doclava supports it. 30# Doclava support for JDK17 was actively being worked on as of Jan 2023. 31JAVA_11_HOME = os.path.join(REPOSITORY_ROOT, 'third_party', 'jdk11', 'current') 32JAVADOC_PATH = os.path.join(JAVA_11_HOME, 'bin', 'javadoc') 33JAR_PATH = os.path.join(JAVA_11_HOME, 'bin', 'jar') 34 35JAVADOC_WARNING = """\ 36javadoc: warning - The old Doclet and Taglet APIs in the packages 37com.sun.javadoc, com.sun.tools.doclets and their implementations 38are planned to be removed in a future JDK release. These 39components have been superseded by the new APIs in jdk.javadoc.doclet. 40Users are strongly recommended to migrate to the new APIs. 41""" 42 43class CronetPostprocessor(Postprocessor): 44 def run(self, text): 45 return text.replace('@Override', '@Override') 46 47 48class CronetExtension(Extension): 49 def extendMarkdown(self, md, md_globals): 50 md.postprocessors.add('CronetPostprocessor', CronetPostprocessor(md), 51 '_end') 52 53 54def GenerateJavadoc(args, src_dir, output_dir): 55 working_dir = os.path.join(args.input_dir, 'android', 'api') 56 overview_file = os.path.abspath(args.overview_file) 57 58 android_sdk_jar = args.android_sdk_jar 59 if not android_sdk_jar: 60 android_sdk_jar = os.path.join(SDK_DIR, 'platforms', 'android-27', 61 'android.jar') 62 63 build_utils.DeleteDirectory(output_dir) 64 build_utils.MakeDirectory(output_dir) 65 classpath = ([android_sdk_jar] + args.support_annotations_jars + 66 args.classpath_jars) 67 javadoc_cmd = [ 68 os.path.abspath(JAVADOC_PATH), 69 '-d', 70 output_dir, 71 '-quiet', 72 '-overview', 73 overview_file, 74 '-doclet', 75 'com.google.doclava.Doclava', 76 '-docletpath', 77 '%s:%s' % (os.path.join(DOCLAVA_DIR, 'jsilver.jar'), 78 os.path.join(DOCLAVA_DIR, 'doclava.jar')), 79 '-title', 80 'Cronet API', 81 '-federate', 82 'Android', 83 'https://developer.android.com/', 84 '-federationapi', 85 'Android', 86 os.path.join(DOCLAVA_DIR, 'current.txt'), 87 '-classpath', 88 ':'.join(os.path.abspath(p) for p in classpath), 89 ] 90 for subdir, _, files in os.walk(src_dir): 91 for filename in files: 92 if filename.endswith(".java"): 93 javadoc_cmd += [os.path.join(subdir, filename)] 94 try: 95 96 def stderr_filter(stderr): 97 return stderr.replace(JAVADOC_WARNING, '') 98 99 build_utils.CheckOutput(javadoc_cmd, 100 cwd=working_dir, 101 stderr_filter=stderr_filter) 102 except build_utils.CalledProcessError: 103 build_utils.DeleteDirectory(output_dir) 104 raise 105 106 # Create an index.html file at the root as this is the accepted format. 107 # Do this by copying reference/index.html and adjusting the path. 108 with open(os.path.join(output_dir, 'reference', 'index.html'), 'r') as \ 109 old_index, open(os.path.join(output_dir, 'index.html'), 'w') as new_index: 110 for line in old_index: 111 new_index.write( 112 line.replace('classes.html', os.path.join('reference', 113 'classes.html'))) 114 115 116def main(argv): 117 parser = argparse.ArgumentParser() 118 action_helpers.add_depfile_arg(parser) 119 parser.add_argument('--output-dir', help='Directory to put javadoc') 120 parser.add_argument('--input-dir', help='Root of cronet source') 121 parser.add_argument('--input-src-jar', help='Cronet api source jar') 122 parser.add_argument('--overview-file', help='Path of the overview page') 123 parser.add_argument('--readme-file', help='Path of the README.md') 124 parser.add_argument('--zip-file', help='Path to ZIP archive of javadocs.') 125 parser.add_argument('--android-sdk-jar', help='Path to android.jar') 126 parser.add_argument('--support-annotations-jars', 127 help='Path to support-annotations-$VERSION.jar', 128 action='append', 129 nargs='*') 130 parser.add_argument('--classpath-jars', 131 help='Paths to jars needed by support-annotations-jar.', 132 action='append', 133 nargs='*') 134 expanded_argv = build_utils.ExpandFileArgs(argv) 135 args, _ = parser.parse_known_args(expanded_argv) 136 137 args.classpath_jars = action_helpers.parse_gn_list(args.classpath_jars) 138 139 args.support_annotations_jars = list( 140 itertools.chain(*args.support_annotations_jars)) 141 # A temporary directory to put the output of cronet api source jar files. 142 unzipped_jar_path = tempfile.mkdtemp(dir=args.output_dir) 143 if os.path.exists(args.input_src_jar): 144 jar_cmd = [ 145 os.path.relpath(JAR_PATH, unzipped_jar_path), 'xf', 146 os.path.abspath(args.input_src_jar) 147 ] 148 build_utils.CheckOutput(jar_cmd, cwd=unzipped_jar_path) 149 else: 150 raise Exception('Jar file does not exist: %s' % args.input_src_jar) 151 152 net_docs.ProcessDocs([args.readme_file], 153 args.input_dir, 154 args.output_dir, 155 extensions=[CronetExtension()]) 156 157 output_dir = os.path.abspath(os.path.join(args.output_dir, 'javadoc')) 158 GenerateJavadoc(args, os.path.abspath(unzipped_jar_path), output_dir) 159 160 if args.zip_file: 161 assert args.zip_file.endswith('.zip') 162 shutil.make_archive(args.zip_file[:-4], 'zip', output_dir) 163 if args.depfile: 164 assert args.zip_file 165 deps = [] 166 for root, _, filenames in os.walk(args.input_dir): 167 # Ignore .pyc files here, it might be re-generated during build. 168 deps.extend( 169 os.path.join(root, f) for f in filenames if not f.endswith('.pyc')) 170 if args.support_annotations_jars: 171 deps.extend(args.support_annotations_jars) 172 if args.classpath_jars: 173 deps.extend(args.classpath_jars) 174 action_helpers.write_depfile(args.depfile, args.zip_file, deps) 175 # Clean up temporary output directory. 176 build_utils.DeleteDirectory(unzipped_jar_path) 177 178 179if __name__ == '__main__': 180 sys.exit(main(sys.argv[1:])) 181