Introduce MultiplatformModelImportingContext
Essentially it is responsible for returning various information about the model being imported, such as: - flags and properties, which configure the process of import - "bulk" requests which might be needed multiple times during import, but which are more convenient to be computed once, like various indices (source sets by name, compilations by source-sets, etc.) ^KT-37127
This commit is contained in:
@@ -19,6 +19,7 @@ import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Exec
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.GradleImportProperties.*
|
||||
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel.Companion.NO_KOTLIN_NATIVE_HOME
|
||||
import org.jetbrains.kotlin.gradle.KotlinSourceSet.Companion.COMMON_MAIN_SOURCE_SET_NAME
|
||||
import org.jetbrains.kotlin.gradle.KotlinSourceSet.Companion.COMMON_TEST_SOURCE_SET_NAME
|
||||
@@ -33,10 +34,6 @@ import java.io.File
|
||||
import java.lang.reflect.Method
|
||||
|
||||
class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
// This flag enables import of source sets which do not belong to any compilation
|
||||
private val DEFAULT_IMPORT_ORPHAN_SOURCE_SETS = true
|
||||
private val DEFAULT_BUILD_METADATA_DEPENDENCIES_FOR_ACTUALISED_SOURCE_SETS = true
|
||||
|
||||
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
|
||||
return ErrorMessageBuilder
|
||||
.create(project, e, "Gradle import errors")
|
||||
@@ -57,53 +54,50 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
SourceSetCachedFinder(project)
|
||||
)
|
||||
val dependencyMapper = KotlinDependencyMapper()
|
||||
val sourceSetMap = buildSourceSets(dependencyResolver, project, dependencyMapper) ?: return null
|
||||
val targets = buildTargets(projectTargets, sourceSetMap, dependencyResolver, project, dependencyMapper)
|
||||
computeSourceSetsDeferredInfo(sourceSetMap, targets, isHMPPEnabled(project), shouldCoerceRootSourceSetToCommon(project))
|
||||
val importingContext = MultiplatformModelImportingContextImpl(project)
|
||||
|
||||
importingContext.initializeSourceSets(buildSourceSets(importingContext, dependencyResolver, dependencyMapper) ?: return null)
|
||||
|
||||
val targets = buildTargets(importingContext, projectTargets, dependencyResolver, dependencyMapper)
|
||||
importingContext.initializeTargets(targets)
|
||||
importingContext.initializeCompilations(targets.flatMap { it.compilations })
|
||||
|
||||
computeSourceSetsDeferredInfo(importingContext)
|
||||
|
||||
val coroutinesState = getCoroutinesState(project)
|
||||
val kotlinNativeHome = KotlinNativeHomeEvaluator.getKotlinNativeHome(project) ?: NO_KOTLIN_NATIVE_HOME
|
||||
return KotlinMPPGradleModelImpl(
|
||||
filterOrphanSourceSets(sourceSetMap, targets, project),
|
||||
targets,
|
||||
ExtraFeaturesImpl(coroutinesState, isHMPPEnabled(project), isNativeDependencyPropagationEnabled(project)),
|
||||
filterOrphanSourceSets(importingContext),
|
||||
importingContext.targets,
|
||||
ExtraFeaturesImpl(
|
||||
coroutinesState,
|
||||
importingContext.getProperty(IS_HMPP_ENABLED),
|
||||
importingContext.getProperty(ENABLE_NATIVE_DEPENDENCY_PROPAGATION)
|
||||
),
|
||||
kotlinNativeHome,
|
||||
dependencyMapper.toDependencyMap()
|
||||
)
|
||||
}
|
||||
|
||||
private fun filterOrphanSourceSets(
|
||||
sourceSets: Map<String, KotlinSourceSetImpl>,
|
||||
targets: Collection<KotlinTarget>,
|
||||
project: Project
|
||||
importingContext: MultiplatformModelImportingContext
|
||||
): Map<String, KotlinSourceSetImpl> {
|
||||
if (try {
|
||||
project.properties["import_orphan_source_sets"]
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}?.toString()?.toBoolean() ?: DEFAULT_IMPORT_ORPHAN_SOURCE_SETS
|
||||
) return sourceSets
|
||||
val compiledSourceSets: Collection<String> = targets
|
||||
.flatMap { it.compilations }
|
||||
.flatMap { it.sourceSets }
|
||||
.flatMap { it.dependsOnSourceSets.union(listOf(it.name)) }
|
||||
.distinct()
|
||||
sourceSets.filter { !compiledSourceSets.contains(it.key) }.forEach {
|
||||
logger.warn("[sync warning] Source set \"${it.key}\" is not compiled with any compilation. This source set is not imported in the IDE.")
|
||||
if (importingContext.getProperty(IMPORT_ORPHAN_SOURCE_SETS)) return importingContext.sourceSetsByNames
|
||||
|
||||
// TODO: similar to importingContext.sourceSetsByCompilations.keys, will be deduplicated in further commits
|
||||
val compiledSourceSets: Collection<String> =
|
||||
importingContext.targets
|
||||
.flatMap { it.compilations }
|
||||
.flatMap { it.sourceSets }
|
||||
.flatMap { it.dependsOnSourceSets.union(listOf(it.name)) }
|
||||
.distinct()
|
||||
|
||||
val (orphanSourceSets, nonOrphanSourceSets) = importingContext.sourceSets.partition { !compiledSourceSets.contains(it.name) }
|
||||
|
||||
orphanSourceSets.forEach {
|
||||
logger.warn("[sync warning] Source set \"${it.name}\" is not compiled with any compilation. This source set is not imported in the IDE.")
|
||||
}
|
||||
return sourceSets.filter { compiledSourceSets.contains(it.key) }
|
||||
}
|
||||
|
||||
private fun isHMPPEnabled(project: Project): Boolean {
|
||||
//TODO(auskov): replace with Project.isKotlinGranularMetadataEnabled after merging with gradle branch
|
||||
return (project.findProperty("kotlin.mpp.enableGranularSourceSetsMetadata") as? String)?.toBoolean() ?: false
|
||||
}
|
||||
|
||||
private fun shouldCoerceRootSourceSetToCommon(project: Project): Boolean {
|
||||
return (project.findProperty("kotlin.mpp.coerceRootSourceSetsToCommon") as? String)?.toBoolean() ?: true
|
||||
}
|
||||
|
||||
private fun isNativeDependencyPropagationEnabled(project: Project): Boolean {
|
||||
return (project.findProperty("kotlin.native.enableDependencyPropagation") as? String)?.toBoolean() ?: true
|
||||
return nonOrphanSourceSets.associateBy { it.name }
|
||||
}
|
||||
|
||||
private fun getCoroutinesState(project: Project): String? {
|
||||
@@ -134,32 +128,33 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
}
|
||||
|
||||
private fun buildSourceSets(
|
||||
importingContext: MultiplatformModelImportingContext,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project,
|
||||
dependencyMapper: KotlinDependencyMapper
|
||||
): Map<String, KotlinSourceSetImpl>? {
|
||||
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
|
||||
val kotlinExt = importingContext.project.extensions.findByName("kotlin") ?: return null
|
||||
val getSourceSets = kotlinExt.javaClass.getMethodOrNull("getSourceSets") ?: return null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val sourceSets =
|
||||
(getSourceSets(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
|
||||
val androidDeps = buildAndroidDeps(kotlinExt.javaClass.classLoader, project)
|
||||
val androidDeps = buildAndroidDeps(importingContext, kotlinExt.javaClass.classLoader)
|
||||
|
||||
val allSourceSetsProtos = sourceSets.mapNotNull {
|
||||
buildSourceSet(it, dependencyResolver, importingContext.project, dependencyMapper, androidDeps)
|
||||
}
|
||||
|
||||
// Some performance optimisation: do not build metadata dependencies if source set is not common
|
||||
val doBuildMetadataDependencies = try {
|
||||
project.properties["build_metadata_dependencies_for_actualised_source_sets"]?.toString()?.toBoolean()
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
} ?: DEFAULT_BUILD_METADATA_DEPENDENCIES_FOR_ACTUALISED_SOURCE_SETS
|
||||
val allSourceSetsProtos = sourceSets.mapNotNull { buildSourceSet(it, dependencyResolver, project, dependencyMapper, androidDeps) }
|
||||
val allSourceSets = if (doBuildMetadataDependencies) {
|
||||
val allSourceSets = if (importingContext.getProperty(BUILD_METADATA_DEPENDENCIES)) {
|
||||
allSourceSetsProtos.map { proto -> proto.buildKotlinSourceSetImpl(true) }
|
||||
} else {
|
||||
val unactualizedSourceSets = allSourceSetsProtos.flatMap { it.dependsOnSourceSets }.distinct()
|
||||
allSourceSetsProtos.map { proto -> proto.buildKotlinSourceSetImpl(unactualizedSourceSets.contains(proto.name)) }
|
||||
}
|
||||
|
||||
// TODO: Weird quirk, we actually *recreate* all source-sets, because those contain
|
||||
// wrong (non-closured) dependsOnNames, so we can not save this map in the importingContext straight away
|
||||
// This will be fixed in later commit
|
||||
val map = allSourceSets.map { it.name to it }.toMap()
|
||||
val dependsOnCache = HashMap<String, Set<String>>()
|
||||
return allSourceSets.map { sourceSet ->
|
||||
@@ -176,19 +171,14 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
private fun buildAndroidDeps(classLoader: ClassLoader, project: Project): Map<String, List<Any>>? {
|
||||
val includeAndroidDeps = try {
|
||||
project.properties["kotlin.include.android.dependencies"]?.toString()?.toBoolean() == true
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
}
|
||||
if (includeAndroidDeps) {
|
||||
private fun buildAndroidDeps(importingContext: MultiplatformModelImportingContext, classLoader: ClassLoader): Map<String, List<Any>>? {
|
||||
if (importingContext.getProperty(INCLUDE_ANDROID_DEPENDENCIES)) {
|
||||
try {
|
||||
val resolverClass = classLoader.loadClass("org.jetbrains.kotlin.gradle.targets.android.internal.AndroidDependencyResolver")
|
||||
val getAndroidSourceSetDependencies = resolverClass.getMethodOrNull("getAndroidSourceSetDependencies", Project::class.java)
|
||||
val resolver = resolverClass.getField("INSTANCE").get(null)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return getAndroidSourceSetDependencies?.let { it(resolver, project) } as Map<String, List<Any>>?
|
||||
return getAndroidSourceSetDependencies?.let { it(resolver, importingContext.project) } as Map<String, List<Any>>?
|
||||
} catch (e: Exception) {
|
||||
logger.info("Unexpected exception", e)
|
||||
}
|
||||
@@ -216,7 +206,8 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
val dependsOnSourceSets = (getDependsOn(gradleSourceSet) as? Set<Named>)?.mapTo(LinkedHashSet()) { it.name } ?: emptySet<String>()
|
||||
|
||||
val sourceSetDependenciesBuilder: () -> Array<KotlinDependencyId> = {
|
||||
buildSourceSetDependencies(gradleSourceSet, dependencyResolver, project, androidDeps).map { dependencyMapper.getId(it) }
|
||||
buildSourceSetDependencies(gradleSourceSet, dependencyResolver, project, androidDeps)
|
||||
.map { dependencyMapper.getId(it) }
|
||||
.distinct()
|
||||
.toTypedArray()
|
||||
}
|
||||
@@ -295,14 +286,12 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
}
|
||||
|
||||
private fun buildTargets(
|
||||
importingContext: MultiplatformModelImportingContext,
|
||||
projectTargets: Collection<Named>,
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project,
|
||||
dependencyMapper: KotlinDependencyMapper
|
||||
): Collection<KotlinTarget> {
|
||||
val isHMPPEnabled = isHMPPEnabled(project)
|
||||
return projectTargets.mapNotNull { buildTarget(it, sourceSetMap, dependencyResolver, project, dependencyMapper, isHMPPEnabled) }
|
||||
return projectTargets.mapNotNull { buildTarget(importingContext, it, dependencyResolver, dependencyMapper) }
|
||||
}
|
||||
|
||||
private operator fun Any?.get(methodName: String, vararg params: Any): Any? {
|
||||
@@ -357,12 +346,10 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
}
|
||||
|
||||
private fun buildTarget(
|
||||
importingContext: MultiplatformModelImportingContext,
|
||||
gradleTarget: Named,
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project,
|
||||
dependencyMapper: KotlinDependencyMapper,
|
||||
isHMPPEnabled: Boolean
|
||||
dependencyMapper: KotlinDependencyMapper
|
||||
): KotlinTarget? {
|
||||
val targetClass = gradleTarget.javaClass
|
||||
val getPlatformType = targetClass.getMethodOrNull("getPlatformType") ?: return null
|
||||
@@ -387,15 +374,15 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
|
||||
val gradleCompilations = getCompilations(gradleTarget) ?: return null
|
||||
val compilations = gradleCompilations.mapNotNull {
|
||||
val compilation = buildCompilation(it, disambiguationClassifier, sourceSetMap, dependencyResolver, project, dependencyMapper)
|
||||
val compilation = buildCompilation(importingContext, it, disambiguationClassifier, dependencyResolver, dependencyMapper)
|
||||
if (compilation == null || platform != KotlinPlatform.ANDROID) {
|
||||
compilation
|
||||
} else {
|
||||
compilation.addDependsOnSourceSetsToCompilation(sourceSetMap, isHMPPEnabled)
|
||||
compilation.addDependsOnSourceSetsToCompilation(importingContext)
|
||||
}
|
||||
}
|
||||
val jar = buildTargetJar(gradleTarget, project)
|
||||
val testRunTasks = buildTestRunTasks(project, gradleTarget)
|
||||
val jar = buildTargetJar(gradleTarget, importingContext.project)
|
||||
val testRunTasks = buildTestRunTasks(importingContext.project, gradleTarget)
|
||||
val nativeMainRunTasks =
|
||||
if (platform == KotlinPlatform.NATIVE) buildNativeMainRunTasks(gradleTarget)
|
||||
else emptyList()
|
||||
@@ -419,12 +406,11 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
}
|
||||
|
||||
private fun KotlinCompilationImpl.addDependsOnSourceSetsToCompilation(
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
isHMPPEnabled: Boolean
|
||||
importingContext: MultiplatformModelImportingContext
|
||||
): KotlinCompilationImpl {
|
||||
val dependsOnSourceSets = this.sourceSets.flatMap { it.dependsOnSourceSets }.mapNotNull { sourceSetMap[it] }
|
||||
val dependsOnSourceSets = this.sourceSets.flatMap { it.dependsOnSourceSets }.mapNotNull { importingContext.sourceSetByName(it) }
|
||||
|
||||
if (!isHMPPEnabled) {
|
||||
if (!importingContext.getProperty(IS_HMPP_ENABLED)) {
|
||||
// intermediate source sets should be common if HMPP is disabled
|
||||
dependsOnSourceSets.subtract(this.sourceSets).forEach {
|
||||
it.actualPlatforms.addSimplePlatforms(listOf(KotlinPlatform.COMMON))
|
||||
@@ -550,26 +536,24 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
}
|
||||
|
||||
private fun buildCompilation(
|
||||
importingContext: MultiplatformModelImportingContext,
|
||||
gradleCompilation: Named,
|
||||
classifier: String?,
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project,
|
||||
dependencyMapper: KotlinDependencyMapper
|
||||
|
||||
): KotlinCompilationImpl? {
|
||||
val compilationClass = gradleCompilation.javaClass
|
||||
val getKotlinSourceSets = compilationClass.getMethodOrNull("getKotlinSourceSets") ?: return null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val kotlinGradleSourceSets = (getKotlinSourceSets(gradleCompilation) as? Collection<Named>) ?: return null
|
||||
val kotlinSourceSets = kotlinGradleSourceSets.mapNotNull { sourceSetMap[it.name] }
|
||||
val compileKotlinTask = getCompileKotlinTaskName(project, gradleCompilation) ?: return null
|
||||
val kotlinSourceSets = kotlinGradleSourceSets.mapNotNull { importingContext.sourceSetByName(it.name) }
|
||||
val compileKotlinTask = getCompileKotlinTaskName(importingContext.project, gradleCompilation) ?: return null
|
||||
val output = buildCompilationOutput(gradleCompilation, compileKotlinTask) ?: return null
|
||||
val arguments = buildCompilationArguments(compileKotlinTask)
|
||||
val dependencyClasspath = buildDependencyClasspath(compileKotlinTask)
|
||||
val dependencies =
|
||||
buildCompilationDependencies(gradleCompilation, classifier, sourceSetMap, dependencyResolver, project, dependencyMapper)
|
||||
buildCompilationDependencies(importingContext, gradleCompilation, classifier, dependencyResolver, dependencyMapper)
|
||||
val kotlinTaskProperties = getKotlinTaskProperties(compileKotlinTask, classifier)
|
||||
|
||||
// Get konanTarget (for native compilations only).
|
||||
@@ -609,26 +593,33 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
}
|
||||
|
||||
private fun buildCompilationDependencies(
|
||||
importingContext: MultiplatformModelImportingContext,
|
||||
gradleCompilation: Named,
|
||||
classifier: String?,
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project,
|
||||
dependencyMapper: KotlinDependencyMapper
|
||||
): Set<KotlinDependency> {
|
||||
return LinkedHashSet<KotlinDependency>().apply {
|
||||
val transformationBuilder = MetadataDependencyTransformationBuilder(gradleCompilation)
|
||||
this += buildDependencies(
|
||||
gradleCompilation, dependencyResolver, "getCompileDependencyConfigurationName", "COMPILE", project, transformationBuilder
|
||||
gradleCompilation,
|
||||
dependencyResolver,
|
||||
"getCompileDependencyConfigurationName",
|
||||
"COMPILE",
|
||||
importingContext.project,
|
||||
transformationBuilder
|
||||
)
|
||||
this += buildDependencies(
|
||||
gradleCompilation, dependencyResolver, "getRuntimeDependencyConfigurationName", "RUNTIME", project, transformationBuilder
|
||||
gradleCompilation,
|
||||
dependencyResolver,
|
||||
"getRuntimeDependencyConfigurationName",
|
||||
"RUNTIME",
|
||||
importingContext.project,
|
||||
transformationBuilder
|
||||
).onlyNewDependencies(this)
|
||||
|
||||
this += sourceSetMap[compilationFullName(
|
||||
gradleCompilation.name,
|
||||
classifier
|
||||
)]?.dependencies?.map { dependencyMapper.getDependency(it) }?.filterNotNull() ?: emptySet()
|
||||
val sourceSet = importingContext.sourceSetByName(compilationFullName(gradleCompilation.name, classifier))
|
||||
this += sourceSet?.dependencies?.mapNotNull { dependencyMapper.getDependency(it) } ?: emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -780,30 +771,9 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
return KotlinCompilationOutputImpl(classesDirs.files, destinationDir, resourcesDir)
|
||||
}
|
||||
|
||||
private fun computeSourceSetsDeferredInfo(
|
||||
sourceSets: Map<String, KotlinSourceSetImpl>,
|
||||
targets: Collection<KotlinTarget>,
|
||||
isHMPPEnabled: Boolean,
|
||||
coerceRootSourceSetsToCommon: Boolean
|
||||
) {
|
||||
// includes only compilations where source set is listed
|
||||
val compiledSourceSetToCompilations = LinkedHashMap<KotlinSourceSet, MutableSet<KotlinCompilation>>()
|
||||
// includes compilations where source set is included via dependsOn
|
||||
val allSourceSetToCompilations = LinkedHashMap<KotlinSourceSet, MutableSet<KotlinCompilation>>()
|
||||
for (target in targets) {
|
||||
for (compilation in target.compilations) {
|
||||
for (sourceSet in compilation.sourceSets) {
|
||||
compiledSourceSetToCompilations.getOrPut(sourceSet) { LinkedHashSet() } += compilation
|
||||
allSourceSetToCompilations.getOrPut(sourceSet) { LinkedHashSet() } += compilation
|
||||
sourceSet.dependsOnSourceSets.mapNotNull { sourceSets[it] }.forEach {
|
||||
allSourceSetToCompilations.getOrPut(it) { LinkedHashSet() } += compilation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (sourceSet in sourceSets.values) {
|
||||
if (!isHMPPEnabled) {
|
||||
private fun computeSourceSetsDeferredInfo(importingContext: MultiplatformModelImportingContext) {
|
||||
for (sourceSet in importingContext.sourceSets) {
|
||||
if (!importingContext.getProperty(IS_HMPP_ENABLED)) {
|
||||
val name = sourceSet.name
|
||||
if (name == COMMON_MAIN_SOURCE_SET_NAME) {
|
||||
sourceSet.isTestModule = false
|
||||
@@ -815,22 +785,31 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
}
|
||||
}
|
||||
|
||||
allSourceSetToCompilations[sourceSet]?.all { it.isTestModule }?.let { isTest ->
|
||||
// TODO DISCUSS AT REVIEW: can we simplify it to:
|
||||
// sourceSet.isTestModule = importingContext.compilationsBySourceSet(sourceSet)?.all { it.isTestModule} ?: false
|
||||
// ^
|
||||
// |
|
||||
// sic!
|
||||
// The difference from the current behaviour would be in case if source set is not included into any compilation AND
|
||||
// KotlinSourceSetImpl.defaultIsTestModule is set to 'true'. Though I don't know who and why would do that.
|
||||
importingContext.compilationsBySourceSet(sourceSet)?.all { it.isTestModule }?.let { isTest ->
|
||||
sourceSet.isTestModule = isTest
|
||||
}
|
||||
|
||||
(allSourceSetToCompilations[sourceSet])?.let { compilations ->
|
||||
importingContext.compilationsBySourceSet(sourceSet)?.let { compilations ->
|
||||
val platforms = compilations.map { it.platform }
|
||||
sourceSet.actualPlatforms.addSimplePlatforms(platforms)
|
||||
}
|
||||
|
||||
if (sourceSet.shouldCoerceToCommon(isHMPPEnabled, coerceRootSourceSetsToCommon)) {
|
||||
if (sourceSet.shouldCoerceToCommon(importingContext)) {
|
||||
sourceSet.actualPlatforms.addSimplePlatforms(listOf(KotlinPlatform.COMMON))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinSourceSetImpl.shouldCoerceToCommon(isHMPPEnabled: Boolean, coerceRootSourceSetsToCommon: Boolean): Boolean {
|
||||
private fun KotlinSourceSetImpl.shouldCoerceToCommon(importingContext: MultiplatformModelImportingContext): Boolean {
|
||||
val isHMPPEnabled = importingContext.getProperty(IS_HMPP_ENABLED)
|
||||
val coerceRootSourceSetsToCommon = importingContext.getProperty(COERCE_ROOT_SOURCE_SETS_TO_COMMON)
|
||||
val isRoot = name == COMMON_MAIN_SOURCE_SET_NAME || name == COMMON_TEST_SOURCE_SET_NAME
|
||||
|
||||
// never makes sense to coerce single-targeted source-sets
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.jetbrains.kotlin.gradle.GradleImportProperties.*
|
||||
import java.lang.Exception
|
||||
|
||||
private val logger = Logging.getLogger(KotlinMPPGradleModelBuilder::class.java)
|
||||
|
||||
internal interface MultiplatformModelImportingContext {
|
||||
val project: Project
|
||||
|
||||
val targets: Collection<KotlinTarget>
|
||||
val compilations: Collection<KotlinCompilation>
|
||||
|
||||
val sourceSets: Collection<KotlinSourceSetImpl>
|
||||
val sourceSetsByNames: Map<String, KotlinSourceSetImpl>
|
||||
|
||||
fun sourceSetByName(name: String): KotlinSourceSet?
|
||||
fun compilationsBySourceSet(sourceSet: KotlinSourceSet): Collection<KotlinCompilation>?
|
||||
}
|
||||
|
||||
internal fun MultiplatformModelImportingContext.getProperty(property: GradleImportProperties): Boolean = project.getProperty(property)
|
||||
|
||||
internal fun Project.getProperty(property: GradleImportProperties): Boolean {
|
||||
val explicitValueIfAny = try {
|
||||
(findProperty(property.id) as? String)?.toBoolean()
|
||||
} catch (e: Exception) {
|
||||
logger.error("Error while trying to read property $property from project $project", e)
|
||||
null
|
||||
}
|
||||
|
||||
return explicitValueIfAny ?: property.defaultValue
|
||||
}
|
||||
|
||||
internal enum class GradleImportProperties(val id: String, val defaultValue: Boolean) {
|
||||
IS_HMPP_ENABLED("kotlin.mpp.enableGranularSourceSetsMetadata", false),
|
||||
COERCE_ROOT_SOURCE_SETS_TO_COMMON("kotlin.mpp.coerceRootSourceSetsToCommon", true),
|
||||
ENABLE_NATIVE_DEPENDENCY_PROPAGATION("kotlin.native.enableDependencyPropagation", true),
|
||||
BUILD_METADATA_DEPENDENCIES("build_metadata_dependencies_for_actualised_source_sets", true),
|
||||
IMPORT_ORPHAN_SOURCE_SETS("import_orphan_source_sets", true),
|
||||
INCLUDE_ANDROID_DEPENDENCIES("kotlin.include.android.dependencies", false)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
internal class MultiplatformModelImportingContextImpl(override val project: Project) : MultiplatformModelImportingContext {
|
||||
/** see [initializeSourceSets] */
|
||||
override lateinit var sourceSetsByNames: Map<String, KotlinSourceSetImpl>
|
||||
private set
|
||||
override val sourceSets: Collection<KotlinSourceSetImpl>
|
||||
get() = sourceSetsByNames.values
|
||||
|
||||
|
||||
/** see [initializeCompilations] */
|
||||
override lateinit var compilations: Collection<KotlinCompilation>
|
||||
private set
|
||||
private lateinit var sourceSetToParticipatedCompilations: Map<KotlinSourceSet, Set<KotlinCompilation>>
|
||||
|
||||
|
||||
/** see [initializeTargets] */
|
||||
override lateinit var targets: Collection<KotlinTarget>
|
||||
private set
|
||||
|
||||
internal fun initializeSourceSets(sourceSetsByNames: Map<String, KotlinSourceSetImpl>) {
|
||||
require(!this::sourceSetsByNames.isInitialized) {
|
||||
"Attempt to re-initialize source sets for $this. Previous value: ${this.sourceSetsByNames}"
|
||||
}
|
||||
this.sourceSetsByNames = sourceSetsByNames
|
||||
}
|
||||
|
||||
internal fun initializeCompilations(compilations: Collection<KotlinCompilation>) {
|
||||
require(!this::compilations.isInitialized) { "Attempt to re-initialize compilations for $this. Previous value: ${this.compilations}" }
|
||||
this.compilations = compilations
|
||||
|
||||
val sourceSetToCompilations = LinkedHashMap<KotlinSourceSet, MutableSet<KotlinCompilation>>()
|
||||
|
||||
for (target in targets) {
|
||||
for (compilation in target.compilations) {
|
||||
for (sourceSet in compilation.sourceSets) {
|
||||
sourceSetToCompilations.getOrPut(sourceSet) { LinkedHashSet() } += compilation
|
||||
sourceSet.dependsOnSourceSets.mapNotNull { sourceSetByName(it) }.forEach {
|
||||
sourceSetToCompilations.getOrPut(it) { LinkedHashSet() } += compilation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.sourceSetToParticipatedCompilations = sourceSetToCompilations
|
||||
}
|
||||
|
||||
internal fun initializeTargets(targets: Collection<KotlinTarget>) {
|
||||
require(!this::targets.isInitialized) { "Attempt to re-initialize targets for $this. Previous value: ${this.targets}" }
|
||||
this.targets = targets
|
||||
}
|
||||
|
||||
override fun compilationsBySourceSet(sourceSet: KotlinSourceSet): Collection<KotlinCompilation>? =
|
||||
sourceSetToParticipatedCompilations[sourceSet]
|
||||
|
||||
override fun sourceSetByName(name: String): KotlinSourceSet? = sourceSetsByNames[name]
|
||||
}
|
||||
Reference in New Issue
Block a user