blob: ea6ba3eb2616d15f98d400c2dd657e076ac55b0c [file] [log] [blame]
/*
* Copyright 2020 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.resources
import androidx.build.AndroidXImplPlugin.Companion.TASK_GROUP_API
import androidx.build.addToBuildOnServer
import androidx.build.addToCheckTask
import androidx.build.checkapi.ApiLocation
import androidx.build.checkapi.getRequiredCompatibilityApiLocation
import androidx.build.dependencyTracker.AffectedModuleDetector
import androidx.build.metalava.UpdateApiTask
import androidx.build.uptodatedness.cacheEvenIfNoOutputs
import org.gradle.api.Project
import java.util.Locale
object ResourceTasks {
private const val GENERATE_RESOURCE_API_TASK = "generateResourceApi"
private const val CHECK_RESOURCE_API_RELEASE_TASK = "checkResourceApiRelease"
private const val CHECK_RESOURCE_API_TASK = "checkResourceApi"
private const val UPDATE_RESOURCE_API_TASK = "updateResourceApi"
fun setupProject(
project: Project,
variantName: String,
builtApiLocation: ApiLocation,
outputApiLocations: List<ApiLocation>
) {
@OptIn(ExperimentalStdlibApi::class)
val packageResTask = project.tasks
.named(
"package${variantName.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString()
}}Resources"
)
@Suppress("UnstableApiUsage") // flatMap
val builtApiFile = packageResTask.flatMap { task ->
(task as com.android.build.gradle.tasks.MergeResources).publicFile
}
val outputApiFiles = outputApiLocations.map { location ->
location.resourceFile
}
val generateResourceApi = project.tasks.register(
GENERATE_RESOURCE_API_TASK,
GenerateResourceApiTask::class.java
) { task ->
task.group = "API"
task.description = "Generates resource API files from source"
task.builtApi.set(builtApiFile)
task.apiLocation.set(builtApiLocation)
AffectedModuleDetector.configureTaskGuard(task)
}
// Policy: If the artifact has previously been released, e.g. has a beta or later API file
// checked in, then we must verify "release compatibility" against the work-in-progress
// API file.
@Suppress("UnstableApiUsage") // flatMap
val checkResourceApiRelease = project.getRequiredCompatibilityApiLocation()?.let {
lastReleasedApiFile ->
project.tasks.register(
CHECK_RESOURCE_API_RELEASE_TASK,
CheckResourceApiReleaseTask::class.java
) { task ->
task.referenceApiFile.set(lastReleasedApiFile.resourceFile)
task.apiLocation.set(generateResourceApi.flatMap { it.apiLocation })
// Since apiLocation isn't a File, we have to manually set up the dependency.
task.dependsOn(generateResourceApi)
task.cacheEvenIfNoOutputs()
AffectedModuleDetector.configureTaskGuard(task)
}
}
// Policy: All changes to API surfaces for which compatibility is enforced must be
// explicitly confirmed by running the updateApi task. To enforce this, the implementation
// checks the "work-in-progress" built API file against the checked in current API file.
@Suppress("UnstableApiUsage") // flatMap
val checkResourceApi = project.tasks.register(
CHECK_RESOURCE_API_TASK,
CheckResourceApiTask::class.java
) { task ->
task.group = TASK_GROUP_API
task.description = "Checks that the resource API generated from source matches the " +
"checked in resource API file"
task.apiLocation.set(generateResourceApi.flatMap { it.apiLocation })
// Since apiLocation isn't a File, we have to manually set up the dependency.
task.dependsOn(generateResourceApi)
task.cacheEvenIfNoOutputs()
task.checkedInApiFiles.set(outputApiFiles)
checkResourceApiRelease?.let {
task.dependsOn(it)
}
AffectedModuleDetector.configureTaskGuard(task)
}
@Suppress("UnstableApiUsage") // flatMap
val updateResourceApi = project.tasks.register(
UPDATE_RESOURCE_API_TASK,
UpdateResourceApiTask::class.java
) { task ->
task.group = TASK_GROUP_API
task.description = "Updates the checked in resource API files to match source code API"
task.apiLocation.set(generateResourceApi.flatMap { it.apiLocation })
// Since apiLocation isn't a File, we have to manually set up the dependency.
task.dependsOn(generateResourceApi)
task.outputApiLocations.set(outputApiLocations)
task.forceUpdate.set(project.hasProperty("force"))
checkResourceApiRelease?.let {
// If a developer (accidentally) makes a non-backwards compatible change to an
// API, the developer will want to be informed of it as soon as possible.
// So, whenever a developer updates an API, if backwards compatibility checks are
// enabled in the library, then we want to check that the changes are backwards
// compatible
task.dependsOn(it)
}
AffectedModuleDetector.configureTaskGuard(task)
}
// Ensure that this task runs as part of "updateApi" task from MetalavaTasks.
project.tasks.withType(UpdateApiTask::class.java).configureEach { task ->
task.dependsOn(updateResourceApi)
}
project.addToCheckTask(checkResourceApi)
project.addToBuildOnServer(checkResourceApi)
}
}