All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codingfeline.buildkonfig.gradle.BuildKonfigSpec.kt Maven / Gradle / Ivy

The newest version!
package com.codingfeline.buildkonfig.gradle

import com.codingfeline.buildkonfig.compiler.FieldSpec
import com.codingfeline.buildkonfig.compiler.TargetConfig
import com.codingfeline.buildkonfig.compiler.TargetConfigFile
import com.codingfeline.buildkonfig.compiler.TargetName
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import java.io.File

data class TargetConfigSource(
    val name: String,
    val configFile: TargetConfigFileImpl,
    val sourceSet: KotlinSourceSet,
)

data class TargetConfigFileImpl(
    @Input override val targetName: TargetName,
    @Internal override val outputDirectory: File,
    @Input override val config: TargetConfig?
) : TargetConfigFile

fun BuildKonfigExtension.mergeConfigs(
    logger: (String) -> Unit,
    flavor: Flavor = DEFAULT_FLAVOR
): Map {
    if (!defaultConfigs.containsKey(DEFAULT_FLAVOR)) {
        throw IllegalStateException("non-flavored defaultConfigs must be provided.")
    }

    val defaultConfig = mergeDefaultConfigs(logger, flavor, defaultConfigs)

    val targetConfigsByName = mergeTargetConfigs(logger, flavor, targetConfigs.mapValues { it.value.toList() })

    // result Map has both common & target configs
    return targetConfigsByName
        .mapValues { (_, config) ->
            mergeConfigs(
                defaultConfig,
                checkTargetSpecificFields(defaultConfig, config)
            )
        } + (COMMON_SOURCESET_NAME to defaultConfig)
}

fun checkTargetSpecificFields(defaultConfig: TargetConfig, targetConfig: TargetConfig): TargetConfig {
    val result = TargetConfig(targetConfig.name)

    val checked = targetConfig.fieldSpecs.mapValues { (name, spec) ->
        spec.copy(isTargetSpecific = !defaultConfig.fieldSpecs.containsKey(name))
    }

    result.fieldSpecs.putAll(checked)

    return result
}

fun mergeConfigs(
    base: TargetConfig,
    new: TargetConfig,
    onReplaced: (old: FieldSpec, new: FieldSpec) -> Unit = { _, _ -> /* no-op */ }
): TargetConfig {
    val result = TargetConfig(base.name)

    val fieldSpecs = listOf(base.fieldSpecs, new.fieldSpecs)
        .fold(mutableMapOf()) { acc, specs ->
            specs.forEach { (name, value) ->
                val alreadyPresent = acc[name]
                val newValue = value.copy()
                acc[name] = newValue
                if (alreadyPresent != null) {
                    onReplaced(alreadyPresent, newValue)
                }
            }
            acc
        }

    result.fieldSpecs.putAll(fieldSpecs)

    return result
}

fun mergeDefaultConfigs(
    logger: (String) -> Unit,
    flavor: Flavor,
    defaultConfigs: Map
): TargetConfig {
    val default = defaultConfigs.getValue(DEFAULT_FLAVOR)
    val flavored = defaultConfigs[flavor]

    if (flavor == DEFAULT_FLAVOR || flavored == null) {
        return default.copy()
    }

    return mergeConfigs(default, flavored) { old, new ->
        logger("BuildKonfig(Default): field '${old.name}' is being replaced with flavored($flavor): ${old.value} -> ${new.value}")
    }
}

fun mergeTargetConfigs(
    logger: (String) -> Unit,
    flavor: Flavor, /* = kotlin.String */
    targetConfigs: Map>
): Map {
    // default for targetConfigs
    val defaultTargetConfigs = targetConfigs
        .getOrDefault(DEFAULT_FLAVOR, emptyList())
        // convert to Map
        .associateBy { "${it.name}Main" }

    val flavoredConfigs = if (flavor != DEFAULT_FLAVOR) {
        targetConfigs.getOrDefault(flavor, emptyList())
            // convert to Map
            .associateBy { "${it.name}Main" }
    } else {
        // we don't want to merge the same configs
        emptyMap()
    }

    return listOf(defaultTargetConfigs, flavoredConfigs)
        .fold(mutableMapOf()) { acc, configs ->
            configs.forEach { (name, config) ->
                val alreadyPresent = acc[name]
                acc[name] = if (alreadyPresent != null) {
                    mergeConfigs(alreadyPresent, config) { old, new ->
                        logger("BuildKonfig($name): field is being replaced with flavored($flavor): ${old.value} -> ${new.value}")
                    }
                } else {
                    config.copy()
                }
            }
            acc
        }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy