1/* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package androidx.build.doclava 18 19import org.gradle.api.tasks.Input 20import org.gradle.api.tasks.InputFiles 21import org.gradle.api.tasks.Optional 22import org.gradle.api.tasks.OutputDirectory 23import org.gradle.api.tasks.OutputFile 24import org.gradle.api.tasks.javadoc.Javadoc 25import org.gradle.external.javadoc.CoreJavadocOptions 26import java.io.File 27 28// external/doclava/src/com/google/doclava/Errors.java 29val DEFAULT_DOCLAVA_CONFIG = ChecksConfig( 30 errors = listOf( 31 101, // unresolved link 32 103, // unknown tag 33 104 // unknown param name 34 ), 35 warnings = listOf(121 /* hidden type param */), 36 hidden = listOf( 37 111, // hidden super class 38 113 // @deprecation mismatch 39 ) 40) 41 42private fun <E> CoreJavadocOptions.addMultilineMultiValueOption( 43 name: String, 44 values: Collection<E> 45) { 46 addMultilineMultiValueOption(name).value = values.map { listOf(it.toString()) } 47} 48 49open class DoclavaTask : Javadoc() { 50 51 // All lowercase name to match MinimalJavadocOptions#docletpath 52 private var docletpath: List<File> = emptyList() 53 54 @Input 55 var checksConfig: ChecksConfig = DEFAULT_DOCLAVA_CONFIG 56 57 /** 58 * If non-null, the list of packages that will be treated as if they were 59 * marked with {@literal @hide}.<br> 60 * Packages names will be matched exactly; sub-packages are not automatically recognized. 61 */ 62 @Optional 63 @Input 64 var hiddenPackages: Collection<String>? = null 65 66 /** 67 * If non-null and not-empty, the whitelist of packages that will be present in the generated 68 * stubs; if null or empty, then all packages have stubs generated.<br> 69 * Wildcards are accepted. 70 */ 71 @Optional 72 @Input 73 var stubPackages: Set<String>? = null 74 75 @Input 76 var generateDocs = true 77 78 /** 79 * If non-null, the location of where to place the generated api file. 80 * If this is non-null, then {@link #removedApiFile} must be non-null as well. 81 */ 82 @Optional 83 @OutputFile 84 var apiFile: File? = null 85 86 /** 87 * If non-null, the location of where to place the generated removed api file. 88 * If this is non-null, then {@link #apiFile} must be non-null as well. 89 */ 90 @Optional 91 @OutputFile 92 var removedApiFile: File? = null 93 94 /** 95 * If non-null, the location of the generated keep list. 96 */ 97 @Optional 98 @OutputFile 99 var keepListFile: File? = null 100 101 /** 102 * If non-null, the location to put the generated stub sources. 103 */ 104 @Optional 105 @OutputDirectory 106 var stubsDir: File? = null 107 108 init { 109 setFailOnError(true) 110 options.doclet = "com.google.doclava.Doclava" 111 options.encoding("UTF-8") 112 options.quiet() 113 // doclava doesn't understand '-doctitle' 114 title = null 115 maxMemory = "1280m" 116 // If none of generateDocs, apiFile, keepListFile, or stubJarsDir are true, then there is 117 // no work to do. 118 onlyIf({ generateDocs || apiFile != null || keepListFile != null || stubsDir != null }) 119 } 120 121 /** 122 * The doclet path which has the {@code com.gogole.doclava.Doclava} class. 123 * This option will override any doclet path set in this instance's 124 * {@link #options JavadocOptions}. 125 * @see MinimalJavadocOptions#getDocletpath() 126 */ 127 @InputFiles 128 fun getDocletpath(): List<File> { 129 return docletpath 130 } 131 132 /** 133 * Sets the doclet path which has the {@code com.gogole.doclava.Doclava} class. 134 * This option will override any doclet path set in this instance's 135 * {@link #options JavadocOptions}. 136 * @see MinimalJavadocOptions#setDocletpath(java.util.List) 137 */ 138 fun setDocletpath(docletpath: Collection<File>) { 139 this.docletpath = docletpath.toList() 140 // Go ahead and keep the docletpath in our JavadocOptions object in sync. 141 options.docletpath = docletpath.toList() 142 } 143 144 /** 145 * "Configures" this DoclavaTask with parameters that might not be at their final values 146 * until this task is run. 147 */ 148 private fun configureDoclava() = (options as CoreJavadocOptions).apply { 149 150 docletpath = this@DoclavaTask.docletpath 151 152 // configure doclava error/warning/hide levels 153 addMultilineMultiValueOption("hide", checksConfig.hidden) 154 addMultilineMultiValueOption("warning", checksConfig.warnings) 155 addMultilineMultiValueOption("error", checksConfig.errors) 156 157 if (hiddenPackages != null) { 158 addMultilineMultiValueOption("hidePackage", hiddenPackages!!) 159 } 160 161 if (!generateDocs) { 162 addBooleanOption("nodocs", true) 163 } 164 165 // If requested, generate the API files. 166 if (apiFile != null) { 167 addFileOption("api", apiFile) 168 addFileOption("removedApi", removedApiFile) 169 } 170 171 // If requested, generate the keep list. 172 addFileOption("proguard", keepListFile) 173 174 // If requested, generate stubs. 175 if (stubsDir != null) { 176 addFileOption("stubs", stubsDir) 177 val stubs = stubPackages 178 if (stubs != null) { 179 addStringOption("stubpackages", stubs.joinToString(":")) 180 } 181 } 182 // Always treat this as an Android docs task. 183 addBooleanOption("android", true) 184 } 185 186 fun coreJavadocOptions(configure: CoreJavadocOptions.() -> Unit) = 187 (options as CoreJavadocOptions).configure() 188 189 override fun generate() { 190 configureDoclava() 191 super.generate() 192 } 193} 194