Skip to content

Commit

Permalink
Merge "Task to regenerate previous api files" into androidx-master-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
mathjeff authored and Gerrit Code Review committed Jul 1, 2019
2 parents 32dd94b + d811f02 commit 5e7a875
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 38 deletions.
6 changes: 3 additions & 3 deletions buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import androidx.build.SupportConfig.DEFAULT_MIN_SDK_VERSION
import androidx.build.SupportConfig.INSTRUMENTATION_RUNNER
import androidx.build.SupportConfig.TARGET_SDK_VERSION
import androidx.build.checkapi.ApiType
import androidx.build.checkapi.getCurrentApiLocation
import androidx.build.checkapi.getApiLocation
import androidx.build.checkapi.getRequiredCompatibilityApiFileFromDir
import androidx.build.checkapi.hasApiFolder
import androidx.build.dependencyTracker.AffectedModuleDetector
Expand Down Expand Up @@ -668,7 +668,7 @@ private fun Project.createCheckResourceApiTask(): DefaultTask {
return tasks.createWithConfig("checkResourceApi",
CheckResourceApiTask::class.java) {
newApiFile = getGenerateResourceApiFile()
oldApiFile = getCurrentApiLocation().resourceFile
oldApiFile = getApiLocation().resourceFile
}
}

Expand All @@ -685,7 +685,7 @@ private fun Project.createUpdateResourceApiTask(): DefaultTask {
newApiFile = getGenerateResourceApiFile()
oldApiFile = getRequiredCompatibilityApiFileFromDir(File(projectDir, "api/"),
version(), ApiType.RESOURCEAPI)
destApiFile = getCurrentApiLocation().resourceFile
destApiFile = getApiLocation().resourceFile
}
}

Expand Down
20 changes: 16 additions & 4 deletions buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ fun hasApiTasks(project: Project, extension: AndroidXExtension): Boolean {
fun Project.getCurrentApiFile() = getApiFile(project.projectDir, project.version())

/**
* Same as getCurrentApiFile but also contains a restricted API file too
* Returns an ApiLocation with the given version
*/
fun Project.getCurrentApiLocation() = ApiLocation.fromPublicApiFile(project.getCurrentApiFile())
fun Project.getApiLocation(version: Version = project.version()): ApiLocation {
return ApiLocation.fromPublicApiFile(getApiFile(project.projectDir, version))
}

/**
* Returns the API file containing the public API that this library promises to support
Expand Down Expand Up @@ -95,8 +97,8 @@ fun Project.getRequiredCompatibilityApiLocation(): ApiLocation? {
* @param version the API version, ex. 25.0.0-SNAPSHOT
* @return the API file of this version
*/
private fun getApiFile(rootDir: File, version: Version): File {
if (version.patch != 0 && (version.isAlpha() || version.isBeta())) {
fun getApiFile(rootDir: File, version: Version): File {
if (!isValidApiVersion(version)) {
val suggestedVersion = Version("${version.major}.${version.minor}.${version.patch}-rc01")
throw GradleException("Illegal version $version . It is not allowed to have a nonzero " +
"patch number and be alpha or beta at the same time.\n" +
Expand All @@ -111,6 +113,16 @@ private fun getApiFile(rootDir: File, version: Version): File {
return File(apiDir, "${version.major}.${version.minor}.0$extra.txt")
}

/**
* Whether it is allowed to generate an API of the given version
*/
fun isValidApiVersion(version: Version): Boolean {
if (version.patch != 0 && (version.isAlpha() || version.isBeta())) {
return false
}
return true
}

/**
* Returns the api file that version <version> is required to be compatible with.
* If apiType is RESOURCEAPI, it will return the resource api file and if it is CLASSAPI, it will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ data class JavaCompileInputs(
fun fromSourceSet(sourceSet: SourceSet, project: Project): JavaCompileInputs {
val sourcePaths: Collection<File> = sourceSet.allSource.srcDirs
val dependencyClasspath = sourceSet.compileClasspath
return fromSourcesAndDeps(sourcePaths, dependencyClasspath, project)
}

fun fromSourcesAndDeps(
sourcePaths: Collection<File>,
dependencyClasspath: FileCollection,
project: Project
): JavaCompileInputs {
val bootClasspath: Collection<File> = androidJarFile(project).files
return JavaCompileInputs(sourcePaths, dependencyClasspath, bootClasspath)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package androidx.build.metalava

import androidx.build.checkapi.ApiLocation
import androidx.build.checkapi.ApiViolationBaselines
import androidx.build.java.JavaCompileInputs
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
Expand Down Expand Up @@ -60,22 +61,9 @@ abstract class GenerateApiTask : MetalavaTask() {
check(bootClasspath.isNotEmpty()) { "Android boot classpath not set." }
check(sourcePaths.isNotEmpty()) { "Source paths not set." }

project.generateApi(
bootClasspath,
dependencyClasspath,
sourcePaths,
apiLocation.get().publicApiFile,
GenerateApiMode.PublicApi(baselines.get().apiLintFile)
)

if (generateRestrictedAPIs) {
project.generateApi(
bootClasspath,
dependencyClasspath,
sourcePaths,
apiLocation.get().restrictedApiFile,
GenerateApiMode.RestrictedApi
)
}
val inputs = JavaCompileInputs.fromSourcesAndDeps(sourcePaths, dependencyClasspath,
project)
project.generateApi(inputs, apiLocation.get(), apiLocation.get().publicApiFile.parentFile,
ApiLintMode.CheckBaseline(baselines.get().apiLintFile), generateRestrictedAPIs)
}
}
64 changes: 53 additions & 11 deletions buildSrc/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package androidx.build.metalava

import androidx.build.checkapi.ApiLocation
import androidx.build.java.JavaCompileInputs
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
Expand All @@ -36,9 +38,7 @@ fun Project.runMetalavaWithArgs(configuration: Configuration, args: List<String>
it.classpath = checkNotNull(configuration) { "Configuration not set." }
it.main = "com.android.tools.metalava.Driver"
it.args = listOf(
"--no-banner",
"--error",
"DeprecationMismatch" // Enforce deprecation mismatch
"--no-banner"
) + args
}
}
Expand Down Expand Up @@ -91,19 +91,43 @@ val API_LINT_ARGS: List<String> = listOf(
)

sealed class GenerateApiMode {
class PublicApi(val apiLintBaseline: File) : GenerateApiMode()
object PublicApi : GenerateApiMode()
object RestrictedApi : GenerateApiMode()
}

sealed class ApiLintMode {
class CheckBaseline(val apiLintBaseline: File) : ApiLintMode()
object Skip : ApiLintMode()
}

// Generates all of the specified api files
fun Project.generateApi(
files: JavaCompileInputs,
apiLocation: ApiLocation,
tempDir: File,
apiLintMode: ApiLintMode,
includeRestrictedApis: Boolean
) {
generateApi(files.bootClasspath, files.dependencyClasspath, files.sourcePaths,
apiLocation.publicApiFile, tempDir, GenerateApiMode.PublicApi, apiLintMode)
if (includeRestrictedApis) {
generateApi(files.bootClasspath, files.dependencyClasspath, files.sourcePaths,
apiLocation.restrictedApiFile, tempDir, GenerateApiMode.RestrictedApi, ApiLintMode.Skip)
}
}

// Generates the specified api file
fun Project.generateApi(
bootClasspath: Collection<File>,
dependencyClasspath: FileCollection,
sourcePaths: Collection<File>,
outputFile: File,
generateApiMode: GenerateApiMode
tempDir: File,
generateApiMode: GenerateApiMode,
apiLintMode: ApiLintMode
) {
val tempOutputFile = if (generateApiMode is GenerateApiMode.RestrictedApi) {
File(outputFile.path + ".tmp")
File(tempDir, outputFile.name + ".tmp")
} else {
outputFile
}
Expand All @@ -124,18 +148,36 @@ fun Project.generateApi(

when (generateApiMode) {
is GenerateApiMode.PublicApi -> {
args += API_LINT_ARGS
if (generateApiMode.apiLintBaseline.exists()) {
args += listOf("--baseline", generateApiMode.apiLintBaseline.toString())
}
}
is GenerateApiMode.RestrictedApi -> {
args += listOf("--show-annotation", "androidx.annotation.RestrictTo")
}
}

val metalavaConfiguration = getMetalavaConfiguration()
when (apiLintMode) {
is ApiLintMode.CheckBaseline -> {
args += API_LINT_ARGS
if (apiLintMode.apiLintBaseline.exists()) {
args += listOf("--baseline", apiLintMode.apiLintBaseline.toString())
}
args.addAll(listOf(
"--error",
"DeprecationMismatch" // Enforce deprecation mismatch
))
}
is ApiLintMode.Skip -> {
args.addAll(listOf(
"--hide",
"DeprecationMismatch",
"--hide",
"UnhiddenSystemApi",
"--hide",
"ReferencesHidden"
))
}
}

val metalavaConfiguration = getMetalavaConfiguration()
runMetalavaWithArgs(metalavaConfiguration, args)

if (generateApiMode is GenerateApiMode.RestrictedApi) {
Expand Down
16 changes: 13 additions & 3 deletions buildSrc/src/main/kotlin/androidx/build/metalava/MetalavaTasks.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import androidx.build.AndroidXPlugin.Companion.BUILD_ON_SERVER_TASK
import androidx.build.AndroidXExtension
import androidx.build.checkapi.ApiLocation
import androidx.build.checkapi.ApiViolationBaselines
import androidx.build.checkapi.getCurrentApiLocation
import androidx.build.checkapi.getApiLocation
import androidx.build.checkapi.getRequiredCompatibilityApiLocation
import androidx.build.checkapi.hasApiFolder
import androidx.build.checkapi.hasApiTasks
Expand Down Expand Up @@ -96,7 +96,7 @@ object MetalavaTasks {
val metalavaConfiguration = project.getMetalavaConfiguration()

// the api files whose file names contain the version of the library
val libraryVersionApi = project.getCurrentApiLocation()
val libraryVersionApi = project.getApiLocation()
// the api files whose file names contain "current.txt"
val currentTxtApi = ApiLocation.fromPublicApiFile(File(
libraryVersionApi.publicApiFile.parentFile, "current.txt"))
Expand Down Expand Up @@ -173,7 +173,7 @@ object MetalavaTasks {
}
}

project.tasks.register("updateApi", UpdateApiTask::class.java) { task ->
val updateApi = project.tasks.register("updateApi", UpdateApiTask::class.java) { task ->
task.group = "API"
task.description = "Updates the checked in API files to match source code API"
task.inputApiLocation.set(generateApi.flatMap { it.apiLocation })
Expand All @@ -182,6 +182,16 @@ object MetalavaTasks {
task.dependsOn(generateApi)
}

project.tasks.register("regenerateOldApis", RegenerateOldApisTask::class.java) { task ->
task.group = "API"
task.description = "Regenerates current and historic API .txt files using the " +
"corresponding prebuilt and the latest Metalava"
// Technically this doesn't need updateApi to happen first, but adding this dependency
// is a convenient way to make updateApi also happen when the user runs
// `./gradlew regenerateOldApis`
task.dependsOn(updateApi)
}

project.tasks.named("check").configure {
it.dependsOn(checkApi)
}
Expand Down
Loading

0 comments on commit 5e7a875

Please sign in to comment.