
modulecheck.parsing.gradle.model.Config.kt Maven / Gradle / Ivy
/*
* Copyright (C) 2021-2022 Rick Busarow
* 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 modulecheck.parsing.gradle.model
import modulecheck.utils.capitalize
import modulecheck.utils.decapitalize
class Configurations(
delegate: Map
) : Map by delegate {
override fun toString(): String {
return toList().joinToString("\n")
}
}
@JvmInline
value class ConfigurationName(val value: String) : Comparable {
fun toSourceSetName(): SourceSetName = when (this.value) {
// "main" source set configurations omit the "main" from their name,
// creating "implementation" instead of "mainImplementation"
in mainConfigurations -> SourceSetName.MAIN
// all other configurations (like "test", "debug", or "androidTest")
// are just "$sourceSetName${baseConfigurationName.capitalize()}"
else -> this.value.extractSourceSetName()
}
/**
* Returns the base name of the Configuration without any source set prefix.
*
* For "main" source sets, this function just returns the same string,
* e.g.: ConfigurationName("api").nameWithoutSourceSet() == "api"
* ConfigurationName("implementation").nameWithoutSourceSet() == "implementation"
*
* For other source sets, it returns the base configuration names:
* ConfigurationName("debugApi").nameWithoutSourceSet() == "Api"
* ConfigurationName("testImplementation").nameWithoutSourceSet() == "Implementation"
*/
fun nameWithoutSourceSet(): String {
return when {
isKapt() -> ConfigurationName.kapt.value
else -> value.removePrefix(toSourceSetName().value)
}
}
/**
* Returns the base name of the Configuration without any source set prefix.
*
* For "main" source sets, this function just returns the same string,
* e.g.: ConfigurationName("api").nameWithoutSourceSet() == "api"
* ConfigurationName("implementation").nameWithoutSourceSet() == "implementation"
*
* For other source sets, it returns the base configuration names:
* ConfigurationName("debugApi").nameWithoutSourceSet() == "Api"
* ConfigurationName("testImplementation").nameWithoutSourceSet() == "Implementation"
*/
fun switchSourceSet(newSourceSetName: SourceSetName): ConfigurationName {
return when {
isKapt() -> "${nameWithoutSourceSet()}${newSourceSetName.value.capitalize()}".asConfigurationName()
else -> "${newSourceSetName.value}${nameWithoutSourceSet().capitalize()}".asConfigurationName()
}
}
/**
* find the "base" configuration name and remove it
*
* For instance, `debugCompileOnly` would find the "CompileOnly" and remove it, returning "debug"
* as the sourceSet name
*/
private fun String.extractSourceSetName(): SourceSetName {
// All kapt configurations start with `kapt`
//
// Config SourceSet
// | kaptAndroidTest | androidTest
// | kaptTest | test
// | kapt | main
// etc.
if (this.startsWith(kapt.value)) {
return removePrefix(kapt.value)
.decapitalize()
.asSourceSetName()
}
// All the base JVM configurations omit "main" from their configuration name
//
// Config SourceSet
// | api | main
// | compileOnlyApi | main
// | implementation | main
// etc.
val configType = mainConfigurationsCapitalized
.find { this.endsWith(it) }
?: return asSourceSetName()
// For any other configuration, the formula is $sourceSetName${baseConfigurationName.capitalize()}
//
// Config SourceSet
// | debugApi | debug
// | releaseCompileOnly | release
// | testImplementation | test
// etc.
return removeSuffix(configType)
.decapitalize()
.asSourceSetName()
}
/**
* Returns the '-api' version of the current configuration.
*
* In Returns | api | api | implementation | api | compileOnly | api | testImplementation |
* testApi | debug | debugApi | androidTestImplementation | androidTestApi
*
* @return for any main/common configuration, just returns `api`. For any other configuration, it
* returns the [SourceSetName] appended with `Api`.
*/
fun apiVariant() = toSourceSetName().apiConfig()
/**
* Returns the '-implementation' version of the current configuration.
*
* In Returns | implementation | implementation | implementation | implementation | compileOnly
* | implementation | testImplementation | testImplementation | debug | debugImplementation |
* androidTestImplementation | androidTestImplementation
*
* @return for any main/common configuration, just returns `implementation`. For any other
* configuration, it returns the [SourceSetName] appended with `Implementation`.
*/
fun implementationVariant() = toSourceSetName().implementationConfig()
/**
* Returns the 'kapt-' version of the current configuration.
*
* @return for any main/common configuration, just returns `kapt`. For any other configuration, it
* returns `kapt` appended with the [SourceSetName].
*/
fun kaptVariant() = toSourceSetName().kaptVariant()
/** @return true if the configuration is an `api` variant */
fun isApi(): Boolean = this == apiVariant()
/** @return true if the configuration is an `implementation` variant */
fun isImplementation(): Boolean = this == implementationVariant()
/** @return true if the configuration is a `kapt` variant */
fun isKapt(): Boolean = this == kaptVariant()
override fun compareTo(other: ConfigurationName): Int {
return value.compareTo(other.value)
}
override fun toString(): String = "(ConfigurationName) `$value`"
companion object {
val androidTestImplementation = ConfigurationName("androidTestImplementation")
val annotationProcessor = ConfigurationName("annotationProcessor")
val anvil = ConfigurationName("anvil")
val api = ConfigurationName("api")
val compile = ConfigurationName("compile")
val compileOnly = ConfigurationName("compileOnly")
val compileOnlyApi = ConfigurationName("compileOnlyApi")
val implementation = ConfigurationName("implementation")
val kapt = ConfigurationName("kapt")
val kotlinCompileClasspath = ConfigurationName("kotlinCompilerPluginClasspathMain")
val ksp = ConfigurationName("ksp")
val runtime = ConfigurationName("runtime")
val runtimeOnly = ConfigurationName("runtimeOnly")
val testApi = ConfigurationName("testApi")
val testImplementation = ConfigurationName("testImplementation")
internal val mainConfigurations = listOf(
api.value,
compile.value,
compileOnly.value,
compileOnlyApi.value,
implementation.value,
kapt.value,
// kotlinCompilerPluginClasspath is a special case,
// since the main config is suffixed with "Main"
kotlinCompileClasspath.value,
runtime.value,
runtimeOnly.value
)
/**
* The order of this list matters. CompileOnlyApi must be before `api` or
* `extractSourceSetName` below will match the wrong suffix.
*/
.sortedByDescending { it.length }
internal val mainCommonConfigurations = listOf(
api.value,
implementation.value
)
private val mainConfigurationsCapitalized = mainConfigurations
.map { it.capitalize() }
.toSet()
fun main() = listOf(
compileOnlyApi,
api,
implementation,
compileOnly,
compile,
kapt,
runtimeOnly,
runtime
)
fun private() = listOf(
implementation,
compileOnly,
compile,
runtimeOnly,
runtime
)
fun public() = listOf(
compileOnlyApi,
api
)
}
}
fun String.asConfigurationName(): ConfigurationName = ConfigurationName(this)
data class Config(
val name: ConfigurationName,
private val upstreamSequence: Sequence,
private val downstreamSequence: Sequence
) {
val upstream: List by lazy { upstreamSequence.toList() }
val downstream: List by lazy { downstreamSequence.toList() }
fun withUpstream(): List = listOf(this) + upstream
fun withDownstream(): List = listOf(this) + downstream
override fun toString(): String {
return """Config -- name=${name.value}
| upstream=${upstream.map { it.name.value }}
| downstream=${downstream.map { it.name.value }}
|)
""".trimMargin()
}
}
fun Map>.main(): List {
return listOfNotNull(
get(ConfigurationName.api),
get(ConfigurationName.compileOnly),
get(ConfigurationName.implementation),
get(ConfigurationName.runtimeOnly)
).flatten()
}
fun Map>.all(): List {
return values.flatten()
}
fun Iterable.names(): List = map { it.name }
fun Sequence.names(): Sequence = map { it.name }
fun Iterable.distinctSourceSetNames(): List =
map { it.toSourceSetName() }
.distinct()
fun Sequence.distinctSourceSetNames(): Sequence =
map { it.toSourceSetName() }
.distinct()
© 2015 - 2025 Weber Informatics LLC | Privacy Policy