blob: 84aa41b78ec5b44bb5f33db1c12a27db1f52a97f [file] [log] [blame]
/*
* Copyright (C) 2017 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 com.android.build.gradle.internal.plugins
import com.android.build.gradle.BasePlugin
import com.android.build.gradle.internal.tasks.structureplugin.CombineModuleInfoTask
import com.android.build.gradle.internal.tasks.structureplugin.GatherModuleInfoTask
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ConfigurationVariant
import org.gradle.api.attributes.Usage
import org.gradle.api.plugins.JavaLibraryPlugin
import org.gradle.api.plugins.JavaPlugin
const val USAGE_STRUCTURE = "android-debug-structure"
const val ARTIFACT_TYPE_MODULE_INFO = "android-debug-module-info"
const val ELEMENT_CONFIG_NAME = "structureElements"
const val CLASSPATH_CONFIG_NAME = "structureClasspath"
/**
* Plugin to gather the project structure of modules
*/
class StructurePlugin: Plugin<Project> {
private var combineModuleTask: CombineModuleInfoTask? = null
private var gatherModuleTask: GatherModuleInfoTask? = null
override fun apply(project: Project) {
if (project == project.rootProject) {
// create a configuration to consume the files
val structureConfig = project.configurations.create(CLASSPATH_CONFIG_NAME).apply {
isCanBeConsumed = false
attributes.attribute(
Usage.USAGE_ATTRIBUTE,
project.objects.named(Usage::class.java, USAGE_STRUCTURE))
}
// go through all the sub modules add add as a dependencies
val depHandler = project.dependencies
project.subprojects.forEach {
depHandler.add(CLASSPATH_CONFIG_NAME, it)
}
// create the task
combineModuleTask = project.tasks.create(
"getStructure",
CombineModuleInfoTask::class.java,
CombineModuleInfoTask.ConfigAction(project, structureConfig))
}
// we have to do the following in afterEvaluate because we want to see all the plugins
// in one go. Using [PluginContainer.withType] doesn't really work because we have
// to do some conditional work depending on which plugins are applied, or not applied.
project.afterEvaluate {
if (it.plugins.count {
it is BasePlugin || it is JavaPlugin || it is JavaLibraryPlugin
} > 0) createTask(it)
if (gatherModuleTask == null) {
// no plugin? still create the configuration.
createPublishingConfiguration(it)
}
}
}
private fun createTask(project: Project) {
// create a configuration to publish the file
val structureConfig = createPublishingConfiguration(project)
gatherModuleTask = project.tasks.create(
"gatherModuleInfo",
GatherModuleInfoTask::class.java,
GatherModuleInfoTask.ConfigAction(project))
// publish the json file as an artifact
structureConfig.outgoing.variants(
{ variants: NamedDomainObjectContainer<ConfigurationVariant> ->
variants.create(ARTIFACT_TYPE_MODULE_INFO) { variant ->
variant.artifact(gatherModuleTask!!.outputProvider) { artifact ->
artifact.type = ARTIFACT_TYPE_MODULE_INFO
artifact.builtBy(gatherModuleTask)
}
}
})
// if this the root project, register this output as an input to the combine task
combineModuleTask?.let {
it.localModuleInfo = gatherModuleTask!!.outputProvider
it.dependsOn(gatherModuleTask)
}
}
private fun createPublishingConfiguration(project: Project): Configuration {
return project.configurations.create(ELEMENT_CONFIG_NAME).apply {
isCanBeResolved = false
attributes.attribute(
Usage.USAGE_ATTRIBUTE,
project.objects.named(Usage::class.java, USAGE_STRUCTURE))
}
}
}