blob: 0161039999067627513647e4c938c7f9553a92af [file] [log] [blame]
/*
* 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
import androidx.build.gmaven.GMavenVersionChecker
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.tasks.Upload
import org.gradle.api.tasks.bundling.Zip
import java.io.File
/**
* Simple description for an artifact that is released from this project.
*/
data class Artifact(
val mavenGroup: String,
val projectName: String,
val version: String
)
/**
* Zip task that zips all artifacts from given [candidates].
*
* Unless [includeReleased] is set to `true`, this task does not include any library artifact
* that is already shipped to maven.google.com.
*/
open class GMavenZipTask : Zip() {
/**
* The version checker which is used to check if a library is already released.
*/
lateinit var versionChecker: GMavenVersionChecker
/**
* If `true`, all libraries will be included in the zip. Otherwise, only those which are not
* in maven.google.com are included.
*/
var includeReleased = false
/**
* Set to true to include maven-metadata.xml
*/
var includeMetadata: Boolean = false
/**
* List of artifacts that might be included in the generated zip.
*/
val candidates = arrayListOf<Artifact>()
/**
* Config action that configures the task when necessary.
*/
class ConfigAction(private val params: Params) : Action<GMavenZipTask> {
data class Params(
/**
* Maven group for the task. "" if for all projects
*/
val mavenGroup: String,
/**
* Set to true to include maven-metadata.xml
*/
var includeMetadata: Boolean,
/**
* The out folder for uploadArchives.
*/
val supportRepoOut: File,
/**
* The out folder where the zip will be created
*/
val distDir: File,
/**
* The build number specified by the server
*/
val buildNumber: String,
/**
* The version checker that queries maven.google.com
*/
val gMavenVersionChecker: GMavenVersionChecker,
/**
* Set to true to include all libraries even if they are released
*/
val includeReleased: Boolean
)
override fun execute(task: GMavenZipTask) {
params.apply {
val descSuffix = if (includeReleased) {
"."
} else {
" without any libraries that are already on maven.google.com. " +
"If you need a full repo, use ${Release.FULL_ARCHIVE_TASK_NAME} task."
}
task.description =
"""
Creates a maven repository that includes just the libraries compiled in
this project$descSuffix.
Group: ${if (mavenGroup != "") mavenGroup else "All"}
""".trimIndent()
task.versionChecker = gMavenVersionChecker
task.from(supportRepoOut)
task.destinationDir = distDir
task.includeReleased = params.includeReleased
task.includeMetadata = params.includeMetadata
task.into("m2repository")
val fileSuffix = if (mavenGroup == "") {
"all"
} else {
mavenGroup
.split(".")
.joinToString("-")
} + "-$buildNumber"
if (includeReleased) {
task.baseName = "top-of-tree-m2repository-$fileSuffix"
} else {
task.baseName = "gmaven-diff-$fileSuffix"
}
task.onlyIf { _ ->
task.setupIncludes()
}
}
}
}
/**
* Decides which files should be included in the zip. Should be invoked right before task
* runs as an `onlyIf` block. Returns `false` if there is nothing to zip.
*/
private fun setupIncludes(): Boolean {
// have 1 default include so that by default, nothing is included
val includes = candidates.flatMap {
val mavenGroupPath = it.mavenGroup.replace('.', '/')
when {
includeReleased -> listOfNotNull(
"$mavenGroupPath/${it.projectName}/${it.version}" + "/**",
if (includeMetadata)
"$mavenGroupPath/${it.projectName}" + "/maven-metadata.*"
else null)
versionChecker.isReleased(it.mavenGroup, it.projectName, it.version) -> {
// query maven.google to check if it is released.
logger.info("looks like $it is released, skipping")
emptyList()
}
else -> {
logger.info("adding $it to partial maven zip because it cannot be found " +
"on maven.google.com")
listOfNotNull(
"$mavenGroupPath/${it.projectName}/${it.version}" + "/**",
if (includeMetadata)
"$mavenGroupPath/${it.projectName}" + "/maven-metadata.*"
else null)
}
}
}
includes.forEach {
include(it)
}
return includes.isNotEmpty()
}
}
/**
* Handles creating various release tasks that create zips for the maven upload and local use.
*/
object Release {
@Suppress("MemberVisibilityCanBePrivate")
const val DIFF_TASK_PREFIX = "createDiffArchive"
const val FULL_ARCHIVE_TASK_NAME = "createArchive"
const val DEFAULT_PUBLISH_CONFIG = "minDepVersionsRelease"
// lazily created config action params so that we don't keep re-creating them
private var configActionParams: GMavenZipTask.ConfigAction.Params? = null
/**
* Creates the global [FULL_ARCHIVE_TASK_NAME] that create the zip for all available libraries.
*/
@JvmStatic
fun createGlobalArchiveTask(project: Project) {
getGlobalFullZipTask(project)
}
/**
* Registers the project to be included in its group's zip file as well as the global zip files.
*/
fun register(project: Project, extension: SupportLibraryExtension) {
if (!extension.publish) {
throw IllegalArgumentException(
"Cannot register ${project.path} into the release" +
" because publish is false!"
)
}
val mavenGroup = extension.mavenGroup ?: throw IllegalArgumentException(
"Cannot register a project to release if it does not have a mavenGroup set up"
)
val version = extension.mavenVersion ?: throw IllegalArgumentException(
"Cannot register a project to release if it does not have a mavenVersion set up"
)
val zipTasks = listOf(
getGroupReleaseZipTask(project, mavenGroup),
getGlobalReleaseZipTask(project),
getGlobalFullZipTask(project))
val artifact = Artifact(
mavenGroup = mavenGroup,
projectName = project.name,
version = version.toString()
)
val uploadTask = project.tasks.getByName("uploadArchives") as Upload
zipTasks.forEach {
it.candidates.add(artifact)
it.dependsOn(uploadTask)
}
}
/**
* Create config action parameters for the project and group. If group is `null`, parameters
* are created for the global tasks.
*/
private fun getParams(
project: Project,
group: String? = null
): GMavenZipTask.ConfigAction.Params {
val projectDist = project.getDistributionDirectory()
val params = configActionParams ?: GMavenZipTask.ConfigAction.Params(
mavenGroup = "",
includeMetadata = false,
supportRepoOut = project.property("supportRepoOut") as File,
gMavenVersionChecker =
project.property("versionChecker") as GMavenVersionChecker,
distDir = projectDist,
includeReleased = false,
buildNumber = getBuildId()
).also {
configActionParams = it
}
return params.copy(
mavenGroup = group ?: "",
distDir = if (group == null) {
projectDist
} else {
File(projectDist, "per-group-zips").also {
it.mkdirs()
}
}
)
}
/**
* Creates and returns the task that generates the combined gmaven diff file for all projects.
*/
private fun getGlobalReleaseZipTask(project: Project): GMavenZipTask {
val taskName = "${DIFF_TASK_PREFIX}ForAll"
return project.rootProject.tasks.findByName(taskName) as? GMavenZipTask
?: project.rootProject.tasks.create(
taskName, GMavenZipTask::class.java,
GMavenZipTask.ConfigAction(getParams(project))
)
}
/**
* Creates and returns the task that includes all projects regardless of their release status.
*/
private fun getGlobalFullZipTask(project: Project): GMavenZipTask {
val taskName = FULL_ARCHIVE_TASK_NAME
return project.rootProject.tasks.findByName(taskName) as? GMavenZipTask
?: project.rootProject.tasks.create(
taskName, GMavenZipTask::class.java,
GMavenZipTask.ConfigAction(getParams(project).copy(
includeReleased = true,
includeMetadata = true
))
)
}
/**
* Creates and returns the zip task that includes artifacts only in the given maven group.
*/
private fun getGroupReleaseZipTask(project: Project, group: String): GMavenZipTask {
val taskName = "${DIFF_TASK_PREFIX}For${groupToTaskNameSuffix(group)}"
return project.rootProject.tasks.findByName(taskName) as? GMavenZipTask
?: project.rootProject.tasks.create(
taskName, GMavenZipTask::class.java,
GMavenZipTask.ConfigAction(getParams(project, group))
)
}
}
/**
* Converts the maven group into a readable task name.
*/
private fun groupToTaskNameSuffix(group: String): String {
return group
.split('.')
.joinToString("") {
it.capitalize()
}
}