aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Gaston <jeffrygaston@google.com>2018-04-20 14:41:49 -0400
committerJeff Gaston <jeffrygaston@google.com>2018-06-29 17:15:00 -0400
commit7bb29b86f70985bf5ab969bd87f3253cec426486 (patch)
treedaa2ad1b0d9cb9be6d29f70556a7a79f02e65b2e
parent5cdc7604694626cd9e6da6c0f9523072e7d48455 (diff)
downloadsupport-7bb29b86f70985bf5ab969bd87f3253cec426486.tar.gz
Consolidate api diff html report into one
Bug: 77807117 Test: ./gradlew generateDiffs && \ chrome ../../out/host/gradle/frameworks/support/build/javadoc/public/online/sdk/support_api_diff/support/current/changes.html Change-Id: I95bc5e73274724b790a1154f00724297e9a7d076
-rw-r--r--buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt192
-rw-r--r--buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt2
-rw-r--r--buildSrc/src/main/kotlin/androidx/build/docs/ConcatenateFilesTask.kt58
-rw-r--r--buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt4
4 files changed, 176 insertions, 80 deletions
diff --git a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
index 40ed9c4d5d6..e74ee0c5c82 100644
--- a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
@@ -27,6 +27,7 @@ import androidx.build.doclava.CHECK_API_CONFIG_DEVELOP
import androidx.build.doclava.CHECK_API_CONFIG_RELEASE
import androidx.build.doclava.CHECK_API_CONFIG_PATCH
import androidx.build.doclava.ChecksConfig
+import androidx.build.docs.ConcatenateFilesTask
import androidx.build.docs.GenerateDocsTask
import androidx.build.jdiff.JDiffTask
import com.android.build.gradle.AppExtension
@@ -46,6 +47,8 @@ import org.gradle.api.tasks.bundling.Zip
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import java.io.File
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
import kotlin.collections.Collection
import kotlin.collections.List
import kotlin.collections.MutableMap
@@ -69,7 +72,13 @@ object DiffAndDocs {
private lateinit var rules: List<PublishDocsRules>
private val docsTasks: MutableMap<String, GenerateDocsTask> = mutableMapOf()
+ private lateinit var aggregateOldApiTxtsTask: ConcatenateFilesTask
+ private lateinit var aggregateNewApiTxtsTask: ConcatenateFilesTask
+ private lateinit var generateDiffsTask: JDiffTask
+ /**
+ * Initialization that should happen only once (and on the root project)
+ */
@JvmStatic
fun configureDiffAndDocs(
root: Project,
@@ -82,6 +91,10 @@ object DiffAndDocs {
anchorTask = root.tasks.create("anchorDocsTask")
val doclavaConfiguration = root.configurations.getByName("doclava")
val generateSdkApiTask = createGenerateSdkApiTask(root, doclavaConfiguration)
+ val now = LocalDateTime.now()
+ // The diff output assumes that each library is of the same version, but our libraries may each be of different versions
+ // So, we display the date as the new version
+ val newVersion = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
rules.forEach {
val task = createGenerateDocsTask(
project = root, generateSdkApiTask = generateSdkApiTask,
@@ -95,7 +108,41 @@ object DiffAndDocs {
root.tasks.create("generateDocs").dependsOn(docsTasks[TIP_OF_TREE.name])
+ val docletClasspath = doclavaConfiguration.resolve()
+
+ aggregateOldApiTxtsTask = root.tasks.create("aggregateOldApiTxts", ConcatenateFilesTask::class.java)
+ aggregateOldApiTxtsTask.Output = File(root.docsDir(), "previous.txt")
+
+ val oldApisTask = root.tasks.createWithConfig("oldApisXml", ApiXmlConversionTask::class.java) {
+ classpath = root.files(docletClasspath)
+ dependsOn(doclavaConfiguration)
+
+ inputApiFile = aggregateOldApiTxtsTask.Output
+ dependsOn(aggregateOldApiTxtsTask)
+
+ outputApiXmlFile = File(root.docsDir(), "previous.xml")
+ }
+
+ aggregateNewApiTxtsTask = root.tasks.create("aggregateNewApiTxts", ConcatenateFilesTask::class.java)
+ aggregateNewApiTxtsTask.Output = File(root.docsDir(), "$newVersion")
+
+ val newApisTask = root.tasks.createWithConfig("newApisXml", ApiXmlConversionTask::class.java) {
+ classpath = root.files(docletClasspath)
+
+ inputApiFile = aggregateNewApiTxtsTask.Output
+ dependsOn(aggregateNewApiTxtsTask)
+
+ outputApiXmlFile = File(root.docsDir(), "$newVersion.xml")
+ }
+
+ val jdiffConfiguration = root.configurations.getByName("jdiff")
+ generateDiffsTask = createGenerateDiffsTask(root,
+ oldApisTask,
+ newApisTask,
+ jdiffConfiguration)
+
setupDocsProject()
+
return anchorTask
}
@@ -185,7 +232,7 @@ object DiffAndDocs {
}
/**
- * Registers a Java project for global docs generation, local API file generation, and
+ * Registers a Java project to be included in docs generation, local API file generation, and
* local API diff generation tasks.
*/
fun registerJavaProject(project: Project, extension: SupportLibraryExtension) {
@@ -205,16 +252,16 @@ object DiffAndDocs {
"ignoring API tasks.")
return
}
- val tasks = initializeApiChecksForProject(project)
+ val tasks = initializeApiChecksForProject(project, aggregateOldApiTxtsTask, aggregateNewApiTxtsTask)
registerJavaProjectForDocsTask(tasks.generateApi, compileJava)
- registerJavaProjectForDocsTask(tasks.generateDiffs, compileJava)
+ registerJavaProjectForDocsTask(generateDiffsTask, compileJava)
setupDocsTasks(project, tasks)
anchorTask.dependsOn(tasks.checkApiTask)
}
/**
- * Registers an Android project for global docs generation, local API file generation, and
- * local API diff generation tasks.
+ * Registers an Android project to be included in global docs generation, local API file
+ * generation, and local API diff generation tasks.
*/
fun registerAndroidProject(
project: Project,
@@ -248,9 +295,9 @@ object DiffAndDocs {
"an api folder, ignoring API tasks.")
return@all
}
- val tasks = initializeApiChecksForProject(project)
+ val tasks = initializeApiChecksForProject(project, aggregateOldApiTxtsTask, aggregateNewApiTxtsTask)
registerAndroidProjectForDocsTask(tasks.generateApi, variant)
- registerAndroidProjectForDocsTask(tasks.generateDiffs, variant)
+ registerAndroidProjectForDocsTask(generateDiffsTask, variant)
setupDocsTasks(project, tasks)
anchorTask.dependsOn(tasks.checkApiTask)
}
@@ -259,7 +306,7 @@ object DiffAndDocs {
private fun setupDocsTasks(project: Project, tasks: Tasks) {
docsTasks.values.forEach { docs ->
- tasks.generateDiffs.dependsOn(docs)
+ generateDiffsTask.dependsOn(docs)
// Track API change history.
docs.addSinceFilesFrom(project.projectDir)
// Associate current API surface with the Maven artifact.
@@ -281,21 +328,20 @@ private fun stripExtension(fileName: String) = fileName.substringBeforeLast('.')
private fun getLastReleasedApiFile(rootFolder: File, refVersion: Version?): File? {
val apiDir = File(rootFolder, "api")
- val lastFile = getLastReleasedApiFileFromDir(apiDir, refVersion)
- if (lastFile != null) {
- return lastFile
- }
-
- return null
+ return getLastReleasedApiFileFromDir(apiDir, refVersion)
}
+/**
+ * Returns the api file with highest version among those having version less than refVersion
+ */
private fun getLastReleasedApiFileFromDir(apiDir: File, refVersion: Version?): File? {
var lastFile: File? = null
var lastVersion: Version? = null
apiDir.listFiles().forEach { file ->
- Version.parseOrNull(file)?.let { version ->
- if ((lastFile == null || lastVersion!! < version) &&
- (refVersion == null || version < refVersion)) {
+ val parsed = Version.parseOrNull(file)
+ parsed?.let { version ->
+ if ((lastFile == null || lastVersion!! < version)
+ && (refVersion == null || version < refVersion)) {
lastFile = file
lastVersion = version
}
@@ -327,7 +373,8 @@ private fun getApiFile(rootDir: File, refVersion: Version, forceRelease: Boolean
return File(apiDir, "current.txt")
}
-// Generates API files
+
+// Creates a new task on the project for generating API files
private fun createGenerateApiTask(project: Project, docletpathParam: Collection<File>) =
project.tasks.createWithConfig("generateApi", DoclavaTask::class.java) {
setDocletpath(docletpathParam)
@@ -345,6 +392,7 @@ private fun createGenerateApiTask(project: Project, docletpathParam: Collection<
exclude("**/R.java")
}
+// Creates a new task on the project for verifying the API
private fun createCheckApiTask(
project: Project,
taskName: String,
@@ -437,57 +485,37 @@ private fun createUpdateApiTask(project: Project, checkApiRelease: CheckApiTask)
}
/**
- * Converts the <code>fromApi</code>.txt file (or the most recently released
- * X.Y.Z.txt if not explicitly defined using -PfromAPi=<file>) to XML format
- * for use by JDiff.
+ * Returns the filepath of the previous API txt file (for computing diffs against)
*/
-private fun createOldApiXml(project: Project, doclavaConfig: Configuration) =
- project.tasks.createWithConfig("oldApiXml", ApiXmlConversionTask::class.java) {
- val toApi = project.processProperty("toApi")?.let {
- Version.parseOrNull(it)
- }
- val fromApi = project.processProperty("fromApi")
- classpath = project.files(doclavaConfig.resolve())
- val rootFolder = project.projectDir
- inputApiFile = if (fromApi != null) {
- // Use an explicit API file.
- File(rootFolder, "api/$fromApi.txt")
- } else {
- // Use the most recently released API file bounded by toApi.
- getLastReleasedApiFile(rootFolder, toApi)
- }
+private fun getOldApiTxt(project: Project): File? {
+ val toApi = project.processProperty("toApi")?.let {
+ Version.parseOrNull(it)
+ }
+ val fromApi = project.processProperty("fromApi")
+ val rootFolder = project.projectDir
+ if (fromApi != null) {
+ // Use an explicit API file.
+ return File(rootFolder, "api/$fromApi.txt")
+ } else {
+ // Use the most recently released API file bounded by toApi.
+ return getLastReleasedApiFile(rootFolder, toApi)
+ }
+}
- outputApiXmlFile = File(project.docsDir(),
- "release/${stripExtension(inputApiFile?.name ?: "creation")}.xml")
- dependsOn(doclavaConfig)
- }
+data class FileProvider(val file: File, val task: Task?)
-/**
- * Converts the <code>toApi</code>.txt file (or current.txt if not explicitly
- * defined using -PtoApi=<file>) to XML format for use by JDiff.
- */
-private fun createNewApiXmlTask(
- project: Project,
- generateApi: DoclavaTask,
- doclavaConfig: Configuration
-) =
- project.tasks.createWithConfig("newApiXml", ApiXmlConversionTask::class.java) {
- classpath = project.files(doclavaConfig.resolve())
- val toApi = project.processProperty("toApi")
-
- if (toApi != null) {
- // Use an explicit API file.
- inputApiFile = File(project.projectDir, "api/$toApi.txt")
- } else {
- // Use the current API file (e.g. current.txt).
- inputApiFile = generateApi.apiFile!!
- dependsOn(generateApi, doclavaConfig)
- }
+private fun getNewApiTxt(project: Project, generateApi: DoclavaTask): FileProvider {
+ val toApi = project.processProperty("toApi")
+ if (toApi != null) {
+ // Use an explicit API file.
+ return FileProvider(File(project.projectDir, "api/$toApi.txt"), null)
+ } else {
+ // Use the current API file (e.g. current.txt).
+ return FileProvider(generateApi.apiFile!!, generateApi)
+ }
- outputApiXmlFile = File(project.docsDir(),
- "release/${stripExtension(inputApiFile?.name ?: "creation")}.xml")
- }
+}
/**
* Generates API diffs.
@@ -532,7 +560,7 @@ private fun createGenerateDiffsTask(
newApiXmlFile = newApiTask.outputApiXmlFile
val newApi = newApiXmlFile.name.substringBeforeLast('.')
- val docsDir = project.rootProject.docsDir()
+ val docsDir = File(project.rootProject.docsDir(), "public")
newJavadocPrefix = "../../../../../reference/"
destinationDir = File(docsDir, "online/sdk/support_api_diff/${project.name}/$newApi")
@@ -543,6 +571,9 @@ private fun createGenerateDiffsTask(
exclude("**/BuildConfig.java", "**/R.java")
dependsOn(oldApiTask, newApiTask, jdiffConfig)
+ doLast {
+ project.logger.lifecycle("generated diffs into $destinationDir")
+ }
}
// Generates a distribution artifact for online docs.
@@ -642,11 +673,13 @@ private fun createGenerateDocsTask(
private data class Tasks(
val generateApi: DoclavaTask,
- val generateDiffs: JDiffTask,
val checkApiTask: CheckApiTask
)
-private fun initializeApiChecksForProject(project: Project): Tasks {
+/**
+ * Sets up api tasks for the given project
+ */
+private fun initializeApiChecksForProject(project: Project, aggregateOldApiTxtsTask: ConcatenateFilesTask, aggregateNewApiTxtsTask:ConcatenateFilesTask): Tasks {
if (!project.hasProperty("docsDir")) {
project.extensions.add("docsDir", File(project.rootProject.docsDir(), project.name))
}
@@ -658,7 +691,7 @@ private fun initializeApiChecksForProject(project: Project): Tasks {
val generateApi = createGenerateApiTask(project, docletClasspath)
generateApi.dependsOn(doclavaConfiguration)
- // Make sure the API surface has not broken since the last release.
+ // for verifying that the API surface has not broken since the last release
val lastReleasedApiFile = getLastReleasedApiFile(workingDir, version)
val whitelistFile = lastReleasedApiFile?.let { apiFile ->
@@ -696,15 +729,20 @@ private fun initializeApiChecksForProject(project: Project): Tasks {
val updateApiTask = createUpdateApiTask(project, checkApiRelease)
updateApiTask.dependsOn(checkApiRelease)
- val newApiTask = createNewApiXmlTask(project, generateApi, doclavaConfiguration)
- val oldApiTask = createOldApiXml(project, doclavaConfiguration)
-
- val jdiffConfiguration = project.rootProject.configurations.getByName("jdiff")
- val generateDiffTask = createGenerateDiffsTask(project,
- oldApiTask,
- newApiTask,
- jdiffConfiguration)
- return Tasks(generateApi, generateDiffTask, checkApi)
+
+
+ val oldApiTxt = getOldApiTxt(project)
+ if (oldApiTxt != null) {
+ aggregateOldApiTxtsTask.addInput(project.name, oldApiTxt)
+ }
+ val newApiTxtProvider = getNewApiTxt(project, generateApi)
+ aggregateNewApiTxtsTask.inputs.file(newApiTxtProvider.file)
+ aggregateNewApiTxtsTask.addInput(project.name, newApiTxtProvider.file)
+ if (newApiTxtProvider.task != null) {
+ aggregateNewApiTxtsTask.dependsOn(newApiTxtProvider.task)
+ }
+
+ return Tasks(generateApi, checkApi)
}
fun hasApiTasks(project: Project, extension: SupportLibraryExtension): Boolean {
diff --git a/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt b/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt
index f66706ca732..b191d56ec2f 100644
--- a/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt
@@ -23,7 +23,7 @@ import org.gradle.api.tasks.OutputFile
import java.io.File
/**
- * Task that converts the given API file to XML format.
+ * Task that converts the given API txt file to XML format.
*/
open class ApiXmlConversionTask : JavaExec() {
@Optional
diff --git a/buildSrc/src/main/kotlin/androidx/build/docs/ConcatenateFilesTask.kt b/buildSrc/src/main/kotlin/androidx/build/docs/ConcatenateFilesTask.kt
new file mode 100644
index 00000000000..d97c7019df8
--- /dev/null
+++ b/buildSrc/src/main/kotlin/androidx/build/docs/ConcatenateFilesTask.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.build.docs
+
+import org.gradle.api.Action
+import org.gradle.api.DefaultTask
+import org.gradle.api.tasks.TaskAction
+import org.gradle.api.tasks.OutputFile
+import java.io.File
+import java.util.SortedMap
+
+open class ConcatenateFilesTask : DefaultTask() {
+ private var keyedInputs: MutableMap<String, File> = mutableMapOf()
+
+ @get:OutputFile
+ lateinit var Output: File
+
+ // Adds the given input file
+ // The order that files are concatenated in is based on sorting the corresponding keys
+ fun addInput(key: String, inputFile: File) {
+ if (this.keyedInputs.containsKey(key)) {
+ throw IllegalArgumentException("Key $key already exists")
+ }
+ this.inputs.file(inputFile)
+ this.keyedInputs[key] = inputFile
+ }
+
+ @TaskAction
+ fun aggregate() {
+ val destFile = this.Output
+
+ // sort the input files to make sure this task always concatenates them in the same order
+ val sortedInputs = this.keyedInputs.toSortedMap()
+
+ val inputFiles = sortedInputs.values
+ if (inputFiles.contains(destFile)) {
+ throw IllegalArgumentException("Output file $destFile is also an input file")
+ }
+
+ val text = inputFiles.joinToString(separator = "") { file -> file.readText() }
+ this.project.logger.info("Joining ${inputFiles.count()} files, and storing the result in ${destFile.path}")
+ destFile.writeText(text)
+ }
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt b/buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt
index 10466ea5182..54e9ec6c033 100644
--- a/buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt
@@ -33,7 +33,7 @@ import java.util.ArrayList
open class JDiffTask : Javadoc() {
/**
- * Sets the doclet path which has the `com.google.doclava.Doclava` class.
+ * Sets the doclet path, which will be used to locate the `com.google.doclava.Doclava` class.
*
*
* This option will override any doclet path set in this instance's
@@ -82,7 +82,7 @@ open class JDiffTask : Javadoc() {
}
/**
- * "Configures" this JDiffTask with parameters that might not be at their final values
+ * Configures this JDiffTask with parameters that might not be at their final values
* until this task is run.
*/
private fun configureJDiffTask() {