| /* |
| * 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 com.android.build.gradle.LibraryExtension |
| import com.android.build.gradle.api.LibraryVariant |
| import org.gradle.api.Action |
| import org.gradle.api.Project |
| import org.gradle.api.tasks.Input |
| import org.gradle.api.tasks.Nested |
| import org.gradle.api.tasks.TaskProvider |
| import org.gradle.api.tasks.bundling.Zip |
| import java.io.File |
| import java.util.TreeSet |
| |
| /** |
| * Simple description for an artifact that is released from this project. |
| */ |
| data class Artifact( |
| @get:Input |
| val mavenGroup: String, |
| @get:Input |
| val projectName: String, |
| @get:Input |
| val version: String |
| ) { |
| override fun toString() = "$mavenGroup:$projectName:$version" |
| } |
| |
| /** |
| * Zip task that zips all artifacts from given [candidates]. |
| */ |
| open class GMavenZipTask : Zip() { |
| /** |
| * Set to true to include maven-metadata.xml |
| */ |
| @get:Input |
| var includeMetadata: Boolean = false |
| /** |
| * List of artifacts that might be included in the generated zip. |
| */ |
| @get:Nested |
| val candidates = TreeSet<Artifact>(compareBy { it.toString() }) |
| |
| /** |
| * 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 publishing libraries. |
| */ |
| val supportRepoOut: File, |
| /** |
| * The out folder where the zip will be created |
| */ |
| val distDir: File, |
| /** |
| * Prefix of file name to create |
| */ |
| val fileNamePrefix: String, |
| /** |
| * The build number specified by the server |
| */ |
| val buildNumber: String |
| ) |
| |
| override fun execute(task: GMavenZipTask) { |
| params.apply { |
| task.description = |
| """ |
| Creates a maven repository that includes just the libraries compiled in |
| this project. |
| Group: ${if (mavenGroup != "") mavenGroup else "All"} |
| """.trimIndent() |
| task.from(supportRepoOut) |
| task.destinationDirectory.set(distDir) |
| task.includeMetadata = params.includeMetadata |
| task.into("m2repository") |
| task.archiveBaseName.set(getZipName(fileNamePrefix, mavenGroup)) |
| task.onlyIf { |
| // always run top diff zip as it is required by build on server task |
| 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('.', '/') |
| 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 PROJECT_ARCHIVE_ZIP_TASK_NAME = "createProjectZip" |
| const val DIFF_TASK_PREFIX = "createDiffArchive" |
| const val FULL_ARCHIVE_TASK_NAME = "createArchive" |
| const val DEFAULT_PUBLISH_CONFIG = "release" |
| const val GROUP_ZIPS_FOLDER = "per-group-zips" |
| const val PROJECT_ZIPS_FOLDER = "per-project-zips" |
| const val GROUP_ZIP_PREFIX = "gmaven" |
| // lazily created config action params so that we don't keep re-creating them |
| private var configActionParams: GMavenZipTask.ConfigAction.Params? = null |
| |
| /** |
| * Registers the project to be included in its group's zip file as well as the global zip files. |
| */ |
| fun register(project: Project, extension: AndroidXExtension) { |
| if (extension.publish == Publish.NONE) { |
| project.logger.info( |
| "project ${project.name} isn't part of release," + |
| " because its \"publish\" property is explicitly set to Publish.NONE" |
| ) |
| return |
| } |
| if (extension.publish == Publish.UNSET) { |
| project.logger.info( |
| "project ${project.name} isn't part of release, because" + |
| " it does not set the \"publish\" property or the \"type\" property" |
| ) |
| return |
| } |
| if (extension.publish == Publish.SNAPSHOT_ONLY && !isSnapshotBuild()) { |
| project.logger.info( |
| "project ${project.name} isn't part of release, because its" + |
| " \"publish\" property is SNAPSHOT_ONLY, but it is not a snapshot build" |
| ) |
| return |
| } |
| |
| val mavenGroup = extension.mavenGroup?.group ?: throw IllegalArgumentException( |
| "Cannot register a project to release if it does not have a mavenGroup set up" |
| ) |
| if (!extension.isVersionSet()) { |
| throw IllegalArgumentException( |
| "Cannot register a project to release if it does not have a mavenVersion set up" |
| ) |
| } |
| val version = project.version |
| |
| var zipTasks = listOf( |
| getProjectZipTask(project), |
| getGroupReleaseZipTask(project, mavenGroup), |
| getGlobalFullZipTask(project) |
| ) |
| val artifact = Artifact( |
| mavenGroup = mavenGroup, |
| projectName = project.name, |
| version = version.toString() |
| ) |
| val publishTask = project.tasks.named("publish") |
| zipTasks.forEach { |
| it.configure { |
| it.candidates.add(artifact) |
| it.dependsOn(publishTask) |
| } |
| } |
| } |
| |
| /** |
| * 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, |
| distDir: File, |
| fileNamePrefix: String = "", |
| group: String? = null |
| ): GMavenZipTask.ConfigAction.Params { |
| val params = configActionParams ?: GMavenZipTask.ConfigAction.Params( |
| mavenGroup = "", |
| includeMetadata = false, |
| supportRepoOut = project.getRepositoryDirectory(), |
| distDir = distDir, |
| fileNamePrefix = fileNamePrefix, |
| buildNumber = getBuildId() |
| ).also { |
| configActionParams = it |
| } |
| distDir.mkdirs() |
| |
| return params.copy( |
| mavenGroup = group ?: "", |
| distDir = distDir, |
| fileNamePrefix = fileNamePrefix |
| ) |
| } |
| |
| /** |
| * Creates and returns the task that includes all projects regardless of their release status. |
| */ |
| fun getGlobalFullZipTask(project: Project): TaskProvider<GMavenZipTask> { |
| return project.rootProject.maybeRegister( |
| name = FULL_ARCHIVE_TASK_NAME, |
| onConfigure = { |
| GMavenZipTask.ConfigAction( |
| getParams( |
| project, |
| project.getDistributionDirectory(), |
| "top-of-tree-m2repository" |
| ).copy( |
| includeMetadata = true |
| ) |
| ).execute(it) |
| }, |
| onRegister = { |
| } |
| ) |
| } |
| |
| /** |
| * Creates and returns the zip task that includes artifacts only in the given maven group. |
| */ |
| private fun getGroupReleaseZipTask( |
| project: Project, |
| group: String |
| ): TaskProvider<GMavenZipTask> { |
| val taskProvider: TaskProvider<GMavenZipTask> = project.rootProject.maybeRegister( |
| name = "${DIFF_TASK_PREFIX}For${groupToTaskNameSuffix(group)}", |
| onConfigure = { |
| GMavenZipTask.ConfigAction( |
| getParams( |
| project = project, |
| distDir = File(project.getDistributionDirectory(), GROUP_ZIPS_FOLDER), |
| fileNamePrefix = GROUP_ZIP_PREFIX, |
| group = group |
| ) |
| ).execute(it) |
| }, |
| onRegister = { |
| } |
| ) |
| project.addToBuildOnServer(taskProvider) |
| return taskProvider |
| } |
| |
| private fun getProjectZipTask( |
| project: Project |
| ): TaskProvider<GMavenZipTask> { |
| val taskName = "$PROJECT_ARCHIVE_ZIP_TASK_NAME" |
| val taskProvider: TaskProvider<GMavenZipTask> = project.maybeRegister( |
| name = taskName, |
| onConfigure = { |
| GMavenZipTask.ConfigAction( |
| getParams( |
| project = project, |
| distDir = File( |
| project.getDistributionDirectory(), |
| PROJECT_ZIPS_FOLDER |
| ), |
| fileNamePrefix = project.projectZipPrefix() |
| ).copy( |
| includeMetadata = true |
| ) |
| ).execute(it) |
| }, |
| onRegister = { |
| } |
| ) |
| project.addToBuildOnServer(taskProvider) |
| return taskProvider |
| } |
| } |
| |
| /** |
| * Let you configure a library variant associated with [Release.DEFAULT_PUBLISH_CONFIG] |
| */ |
| fun LibraryExtension.defaultPublishVariant(config: (LibraryVariant) -> Unit) { |
| libraryVariants.all { variant -> |
| if (variant.name == Release.DEFAULT_PUBLISH_CONFIG) { |
| config(variant) |
| } |
| } |
| } |
| |
| /** |
| * Converts the maven group into a readable task name. |
| */ |
| private fun groupToTaskNameSuffix(group: String): String { |
| return group |
| .split('.') |
| .joinToString("") { |
| it.capitalize() |
| } |
| } |
| /** |
| * Converts the project name into a readable task name |
| */ |
| private fun projectToNameSuffix(project: Project): String { |
| return project.path |
| .split(":", "-") |
| .joinToString("") { |
| it.capitalize() |
| } |
| } |
| |
| private fun Project.projectZipPrefix(): String { |
| return "${project.group}-${project.name}" |
| } |
| |
| private fun getZipName(fileNamePrefix: String, mavenGroup: String): String { |
| val fileSuffix = if (mavenGroup == "") { |
| "all" |
| } else { |
| mavenGroup |
| .split(".") |
| .joinToString("-") |
| } + "-${getBuildId()}" |
| return "$fileNamePrefix-$fileSuffix" |
| } |
| |
| fun Project.getProjectZipPath(): String { |
| return distSubdir() + Release.PROJECT_ZIPS_FOLDER + "/" + |
| // We pass in a "" because that mimics not passing the group to getParams() inside |
| // the getProjectZipTask function |
| getZipName(projectZipPrefix(), "") + "-${project.version}.zip" |
| } |
| |
| fun Project.getGroupZipPath(): |
| String { |
| return distSubdir() + Release.GROUP_ZIPS_FOLDER + "/" + |
| getZipName(Release.GROUP_ZIP_PREFIX, project.group.toString()) + ".zip" |
| } |