blob: 96de5a761ccbcd6674eb4368ea68e921060f539d [file] [log] [blame]
/*
* Copyright (C) 2019 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.variant
import com.android.build.gradle.internal.BuildTypeData
import com.android.build.gradle.internal.ProductFlavorData
import com.android.build.gradle.internal.api.DefaultAndroidSourceSet
import com.android.build.gradle.internal.core.VariantBuilder.Companion.computeSourceSetName
import com.android.build.gradle.internal.dependency.SourceSetManager
import com.android.build.gradle.internal.dsl.BuildType
import com.android.build.gradle.internal.dsl.SigningConfig
import com.android.build.gradle.internal.plugins.DslContainerProvider
import com.android.builder.core.BuilderConstants
import com.android.builder.core.VariantType
import com.android.builder.core.VariantTypeImpl
/**
* Abstract Class responsible for handling the DSL containers of flavors/build types and processing
* them so that they can be consumed by [com.android.build.gradle.internal.VariantManager]
*
* This is has type parameters to handle different implementations of flavors and build types,
* whether this is legacy or new per-plugin-type versions.
*
* This instantiate the containers and makes them available to the extension classes via
* implementing [DslContainerProvider].
*
* This setups container call back to process new values and validates them.
*
* Then, this exposes the results by implementing [VariantInputModel].
*
* This class does everything, except actually instantiating the containers as this needs
* to be done per flavor/build-type type. This is handled by children classes for each use case.
*/
abstract class AbstractVariantInputManager<
DefaultConfigT : com.android.build.api.dsl.DefaultConfig,
BuildTypeT : com.android.build.api.dsl.BuildType,
ProductFlavorT : com.android.build.api.dsl.ProductFlavor,
SigningConfigT : com.android.build.api.dsl.SigningConfig>(
private val variantType: VariantType,
override val sourceSetManager: SourceSetManager
) : VariantInputModel<DefaultConfigT, BuildTypeT, ProductFlavorT, SigningConfigT>,
DslContainerProvider<DefaultConfigT, BuildTypeT, ProductFlavorT, SigningConfigT> {
override val buildTypes = mutableMapOf<String, BuildTypeData<BuildTypeT>>()
override val productFlavors = mutableMapOf<String, ProductFlavorData<ProductFlavorT>>()
override val signingConfigs = mutableMapOf<String, SigningConfigT>()
protected fun addSigningConfig(signingConfig: SigningConfigT) {
signingConfigs[signingConfig.name] = signingConfig
}
/**
* Adds new BuildType, creating a BuildTypeData, and the associated source set, and adding it to
* the map.
*
* @param buildType the build type.
*/
protected fun addBuildType(buildType: BuildTypeT) {
val name = buildType.name
checkName(name, "BuildType")
if (productFlavors.containsKey(name)) {
throw RuntimeException("BuildType names cannot collide with ProductFlavor names")
}
// FIXME update when we have the newer interfaces for BuildTypes.
if (buildType is BuildType) {
if (variantType.isDynamicFeature) {
// initialize it without the signingConfig for dynamic-features.
buildType.init()
} else {
buildType.init(signingConfigContainer.findByName(BuilderConstants.DEBUG) as SigningConfig)
}
} else {
throw RuntimeException("Unexpected instance of BuildTypeT")
}
// always create the android Test source set even if this is not the buildType that is
// tested. this is because we cannot delay creation without breaking compatibility.
// So for now we create more than we need and we'll migrate to a better way later.
// FIXME b/149489432
val androidTestSourceSet = if (variantType.hasTestComponents) {
sourceSetManager.setUpTestSourceSet(
computeSourceSetName(
buildType.name, VariantTypeImpl.ANDROID_TEST
)
) as DefaultAndroidSourceSet
} else null
val unitTestSourceSet = if (variantType.hasTestComponents) {
sourceSetManager.setUpTestSourceSet(
computeSourceSetName(
buildType.name, VariantTypeImpl.UNIT_TEST
)
) as DefaultAndroidSourceSet
} else null
buildTypes[name] = BuildTypeData<BuildTypeT>(
buildType,
sourceSetManager.setUpSourceSet(buildType.name) as DefaultAndroidSourceSet,
androidTestSourceSet,
unitTestSourceSet
)
}
/**
* Adds a new ProductFlavor, creating a ProductFlavorData and associated source sets, and adding
* it to the map.
*
* @param productFlavor the product flavor
*/
protected fun addProductFlavor(productFlavor: ProductFlavorT) {
val name = productFlavor.name
checkName(name, "ProductFlavor")
if (buildTypes.containsKey(name)) {
throw RuntimeException("ProductFlavor names cannot collide with BuildType names")
}
val mainSourceSet =
sourceSetManager.setUpSourceSet(productFlavor.name) as DefaultAndroidSourceSet
var androidTestSourceSet: DefaultAndroidSourceSet? = null
var unitTestSourceSet: DefaultAndroidSourceSet? = null
if (variantType.hasTestComponents) {
androidTestSourceSet = sourceSetManager.setUpTestSourceSet(
computeSourceSetName(
productFlavor.name, VariantTypeImpl.ANDROID_TEST
)
) as DefaultAndroidSourceSet
unitTestSourceSet = sourceSetManager.setUpTestSourceSet(
computeSourceSetName(
productFlavor.name, VariantTypeImpl.UNIT_TEST
)
) as DefaultAndroidSourceSet
}
val productFlavorData =
ProductFlavorData(
productFlavor, mainSourceSet, androidTestSourceSet, unitTestSourceSet
)
productFlavors[productFlavor.name] = productFlavorData
}
companion object {
private fun checkName(name: String, displayName: String) {
checkPrefix(
name,
displayName,
VariantType.ANDROID_TEST_PREFIX
)
checkPrefix(
name,
displayName,
VariantType.UNIT_TEST_PREFIX
)
if (BuilderConstants.LINT == name) {
throw RuntimeException(
String.format(
"%1\$s names cannot be %2\$s",
displayName,
BuilderConstants.LINT
)
)
}
}
private fun checkPrefix(
name: String,
displayName: String,
prefix: String
) {
if (name.startsWith(prefix)) {
throw RuntimeException(
String.format(
"%1\$s names cannot start with '%2\$s'",
displayName,
prefix
)
)
}
}
}
}