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.provider.Provider
|
||||||
import org.gradle.api.tasks.Exec
|
import org.gradle.api.tasks.Exec
|
||||||
import org.gradle.api.tasks.TaskProvider
|
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.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_MAIN_SOURCE_SET_NAME
|
||||||
import org.jetbrains.kotlin.gradle.KotlinSourceSet.Companion.COMMON_TEST_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
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
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 {
|
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
|
||||||
return ErrorMessageBuilder
|
return ErrorMessageBuilder
|
||||||
.create(project, e, "Gradle import errors")
|
.create(project, e, "Gradle import errors")
|
||||||
@@ -57,53 +54,50 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
SourceSetCachedFinder(project)
|
SourceSetCachedFinder(project)
|
||||||
)
|
)
|
||||||
val dependencyMapper = KotlinDependencyMapper()
|
val dependencyMapper = KotlinDependencyMapper()
|
||||||
val sourceSetMap = buildSourceSets(dependencyResolver, project, dependencyMapper) ?: return null
|
val importingContext = MultiplatformModelImportingContextImpl(project)
|
||||||
val targets = buildTargets(projectTargets, sourceSetMap, dependencyResolver, project, dependencyMapper)
|
|
||||||
computeSourceSetsDeferredInfo(sourceSetMap, targets, isHMPPEnabled(project), shouldCoerceRootSourceSetToCommon(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 coroutinesState = getCoroutinesState(project)
|
||||||
val kotlinNativeHome = KotlinNativeHomeEvaluator.getKotlinNativeHome(project) ?: NO_KOTLIN_NATIVE_HOME
|
val kotlinNativeHome = KotlinNativeHomeEvaluator.getKotlinNativeHome(project) ?: NO_KOTLIN_NATIVE_HOME
|
||||||
return KotlinMPPGradleModelImpl(
|
return KotlinMPPGradleModelImpl(
|
||||||
filterOrphanSourceSets(sourceSetMap, targets, project),
|
filterOrphanSourceSets(importingContext),
|
||||||
targets,
|
importingContext.targets,
|
||||||
ExtraFeaturesImpl(coroutinesState, isHMPPEnabled(project), isNativeDependencyPropagationEnabled(project)),
|
ExtraFeaturesImpl(
|
||||||
|
coroutinesState,
|
||||||
|
importingContext.getProperty(IS_HMPP_ENABLED),
|
||||||
|
importingContext.getProperty(ENABLE_NATIVE_DEPENDENCY_PROPAGATION)
|
||||||
|
),
|
||||||
kotlinNativeHome,
|
kotlinNativeHome,
|
||||||
dependencyMapper.toDependencyMap()
|
dependencyMapper.toDependencyMap()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterOrphanSourceSets(
|
private fun filterOrphanSourceSets(
|
||||||
sourceSets: Map<String, KotlinSourceSetImpl>,
|
importingContext: MultiplatformModelImportingContext
|
||||||
targets: Collection<KotlinTarget>,
|
|
||||||
project: Project
|
|
||||||
): Map<String, KotlinSourceSetImpl> {
|
): Map<String, KotlinSourceSetImpl> {
|
||||||
if (try {
|
if (importingContext.getProperty(IMPORT_ORPHAN_SOURCE_SETS)) return importingContext.sourceSetsByNames
|
||||||
project.properties["import_orphan_source_sets"]
|
|
||||||
} catch (e: Exception) {
|
// TODO: similar to importingContext.sourceSetsByCompilations.keys, will be deduplicated in further commits
|
||||||
null
|
val compiledSourceSets: Collection<String> =
|
||||||
}?.toString()?.toBoolean() ?: DEFAULT_IMPORT_ORPHAN_SOURCE_SETS
|
importingContext.targets
|
||||||
) return sourceSets
|
.flatMap { it.compilations }
|
||||||
val compiledSourceSets: Collection<String> = targets
|
.flatMap { it.sourceSets }
|
||||||
.flatMap { it.compilations }
|
.flatMap { it.dependsOnSourceSets.union(listOf(it.name)) }
|
||||||
.flatMap { it.sourceSets }
|
.distinct()
|
||||||
.flatMap { it.dependsOnSourceSets.union(listOf(it.name)) }
|
|
||||||
.distinct()
|
val (orphanSourceSets, nonOrphanSourceSets) = importingContext.sourceSets.partition { !compiledSourceSets.contains(it.name) }
|
||||||
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.")
|
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) }
|
return nonOrphanSourceSets.associateBy { it.name }
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCoroutinesState(project: Project): String? {
|
private fun getCoroutinesState(project: Project): String? {
|
||||||
@@ -134,32 +128,33 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildSourceSets(
|
private fun buildSourceSets(
|
||||||
|
importingContext: MultiplatformModelImportingContext,
|
||||||
dependencyResolver: DependencyResolver,
|
dependencyResolver: DependencyResolver,
|
||||||
project: Project,
|
|
||||||
dependencyMapper: KotlinDependencyMapper
|
dependencyMapper: KotlinDependencyMapper
|
||||||
): Map<String, KotlinSourceSetImpl>? {
|
): 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
|
val getSourceSets = kotlinExt.javaClass.getMethodOrNull("getSourceSets") ?: return null
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val sourceSets =
|
val sourceSets =
|
||||||
(getSourceSets(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
|
(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
|
// Some performance optimisation: do not build metadata dependencies if source set is not common
|
||||||
val doBuildMetadataDependencies = try {
|
val allSourceSets = if (importingContext.getProperty(BUILD_METADATA_DEPENDENCIES)) {
|
||||||
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) {
|
|
||||||
allSourceSetsProtos.map { proto -> proto.buildKotlinSourceSetImpl(true) }
|
allSourceSetsProtos.map { proto -> proto.buildKotlinSourceSetImpl(true) }
|
||||||
} else {
|
} else {
|
||||||
val unactualizedSourceSets = allSourceSetsProtos.flatMap { it.dependsOnSourceSets }.distinct()
|
val unactualizedSourceSets = allSourceSetsProtos.flatMap { it.dependsOnSourceSets }.distinct()
|
||||||
allSourceSetsProtos.map { proto -> proto.buildKotlinSourceSetImpl(unactualizedSourceSets.contains(proto.name)) }
|
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 map = allSourceSets.map { it.name to it }.toMap()
|
||||||
val dependsOnCache = HashMap<String, Set<String>>()
|
val dependsOnCache = HashMap<String, Set<String>>()
|
||||||
return allSourceSets.map { sourceSet ->
|
return allSourceSets.map { sourceSet ->
|
||||||
@@ -176,19 +171,14 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
}.toMap()
|
}.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildAndroidDeps(classLoader: ClassLoader, project: Project): Map<String, List<Any>>? {
|
private fun buildAndroidDeps(importingContext: MultiplatformModelImportingContext, classLoader: ClassLoader): Map<String, List<Any>>? {
|
||||||
val includeAndroidDeps = try {
|
if (importingContext.getProperty(INCLUDE_ANDROID_DEPENDENCIES)) {
|
||||||
project.properties["kotlin.include.android.dependencies"]?.toString()?.toBoolean() == true
|
|
||||||
} catch (_: Exception) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
if (includeAndroidDeps) {
|
|
||||||
try {
|
try {
|
||||||
val resolverClass = classLoader.loadClass("org.jetbrains.kotlin.gradle.targets.android.internal.AndroidDependencyResolver")
|
val resolverClass = classLoader.loadClass("org.jetbrains.kotlin.gradle.targets.android.internal.AndroidDependencyResolver")
|
||||||
val getAndroidSourceSetDependencies = resolverClass.getMethodOrNull("getAndroidSourceSetDependencies", Project::class.java)
|
val getAndroidSourceSetDependencies = resolverClass.getMethodOrNull("getAndroidSourceSetDependencies", Project::class.java)
|
||||||
val resolver = resolverClass.getField("INSTANCE").get(null)
|
val resolver = resolverClass.getField("INSTANCE").get(null)
|
||||||
@Suppress("UNCHECKED_CAST")
|
@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) {
|
} catch (e: Exception) {
|
||||||
logger.info("Unexpected exception", e)
|
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 dependsOnSourceSets = (getDependsOn(gradleSourceSet) as? Set<Named>)?.mapTo(LinkedHashSet()) { it.name } ?: emptySet<String>()
|
||||||
|
|
||||||
val sourceSetDependenciesBuilder: () -> Array<KotlinDependencyId> = {
|
val sourceSetDependenciesBuilder: () -> Array<KotlinDependencyId> = {
|
||||||
buildSourceSetDependencies(gradleSourceSet, dependencyResolver, project, androidDeps).map { dependencyMapper.getId(it) }
|
buildSourceSetDependencies(gradleSourceSet, dependencyResolver, project, androidDeps)
|
||||||
|
.map { dependencyMapper.getId(it) }
|
||||||
.distinct()
|
.distinct()
|
||||||
.toTypedArray()
|
.toTypedArray()
|
||||||
}
|
}
|
||||||
@@ -295,14 +286,12 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildTargets(
|
private fun buildTargets(
|
||||||
|
importingContext: MultiplatformModelImportingContext,
|
||||||
projectTargets: Collection<Named>,
|
projectTargets: Collection<Named>,
|
||||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
|
||||||
dependencyResolver: DependencyResolver,
|
dependencyResolver: DependencyResolver,
|
||||||
project: Project,
|
|
||||||
dependencyMapper: KotlinDependencyMapper
|
dependencyMapper: KotlinDependencyMapper
|
||||||
): Collection<KotlinTarget> {
|
): Collection<KotlinTarget> {
|
||||||
val isHMPPEnabled = isHMPPEnabled(project)
|
return projectTargets.mapNotNull { buildTarget(importingContext, it, dependencyResolver, dependencyMapper) }
|
||||||
return projectTargets.mapNotNull { buildTarget(it, sourceSetMap, dependencyResolver, project, dependencyMapper, isHMPPEnabled) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private operator fun Any?.get(methodName: String, vararg params: Any): Any? {
|
private operator fun Any?.get(methodName: String, vararg params: Any): Any? {
|
||||||
@@ -357,12 +346,10 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildTarget(
|
private fun buildTarget(
|
||||||
|
importingContext: MultiplatformModelImportingContext,
|
||||||
gradleTarget: Named,
|
gradleTarget: Named,
|
||||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
|
||||||
dependencyResolver: DependencyResolver,
|
dependencyResolver: DependencyResolver,
|
||||||
project: Project,
|
dependencyMapper: KotlinDependencyMapper
|
||||||
dependencyMapper: KotlinDependencyMapper,
|
|
||||||
isHMPPEnabled: Boolean
|
|
||||||
): KotlinTarget? {
|
): KotlinTarget? {
|
||||||
val targetClass = gradleTarget.javaClass
|
val targetClass = gradleTarget.javaClass
|
||||||
val getPlatformType = targetClass.getMethodOrNull("getPlatformType") ?: return null
|
val getPlatformType = targetClass.getMethodOrNull("getPlatformType") ?: return null
|
||||||
@@ -387,15 +374,15 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
|
|
||||||
val gradleCompilations = getCompilations(gradleTarget) ?: return null
|
val gradleCompilations = getCompilations(gradleTarget) ?: return null
|
||||||
val compilations = gradleCompilations.mapNotNull {
|
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) {
|
if (compilation == null || platform != KotlinPlatform.ANDROID) {
|
||||||
compilation
|
compilation
|
||||||
} else {
|
} else {
|
||||||
compilation.addDependsOnSourceSetsToCompilation(sourceSetMap, isHMPPEnabled)
|
compilation.addDependsOnSourceSetsToCompilation(importingContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jar = buildTargetJar(gradleTarget, project)
|
val jar = buildTargetJar(gradleTarget, importingContext.project)
|
||||||
val testRunTasks = buildTestRunTasks(project, gradleTarget)
|
val testRunTasks = buildTestRunTasks(importingContext.project, gradleTarget)
|
||||||
val nativeMainRunTasks =
|
val nativeMainRunTasks =
|
||||||
if (platform == KotlinPlatform.NATIVE) buildNativeMainRunTasks(gradleTarget)
|
if (platform == KotlinPlatform.NATIVE) buildNativeMainRunTasks(gradleTarget)
|
||||||
else emptyList()
|
else emptyList()
|
||||||
@@ -419,12 +406,11 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinCompilationImpl.addDependsOnSourceSetsToCompilation(
|
private fun KotlinCompilationImpl.addDependsOnSourceSetsToCompilation(
|
||||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
importingContext: MultiplatformModelImportingContext
|
||||||
isHMPPEnabled: Boolean
|
|
||||||
): KotlinCompilationImpl {
|
): 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
|
// intermediate source sets should be common if HMPP is disabled
|
||||||
dependsOnSourceSets.subtract(this.sourceSets).forEach {
|
dependsOnSourceSets.subtract(this.sourceSets).forEach {
|
||||||
it.actualPlatforms.addSimplePlatforms(listOf(KotlinPlatform.COMMON))
|
it.actualPlatforms.addSimplePlatforms(listOf(KotlinPlatform.COMMON))
|
||||||
@@ -550,26 +536,24 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildCompilation(
|
private fun buildCompilation(
|
||||||
|
importingContext: MultiplatformModelImportingContext,
|
||||||
gradleCompilation: Named,
|
gradleCompilation: Named,
|
||||||
classifier: String?,
|
classifier: String?,
|
||||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
|
||||||
dependencyResolver: DependencyResolver,
|
dependencyResolver: DependencyResolver,
|
||||||
project: Project,
|
|
||||||
dependencyMapper: KotlinDependencyMapper
|
dependencyMapper: KotlinDependencyMapper
|
||||||
|
|
||||||
): KotlinCompilationImpl? {
|
): KotlinCompilationImpl? {
|
||||||
val compilationClass = gradleCompilation.javaClass
|
val compilationClass = gradleCompilation.javaClass
|
||||||
val getKotlinSourceSets = compilationClass.getMethodOrNull("getKotlinSourceSets") ?: return null
|
val getKotlinSourceSets = compilationClass.getMethodOrNull("getKotlinSourceSets") ?: return null
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val kotlinGradleSourceSets = (getKotlinSourceSets(gradleCompilation) as? Collection<Named>) ?: return null
|
val kotlinGradleSourceSets = (getKotlinSourceSets(gradleCompilation) as? Collection<Named>) ?: return null
|
||||||
val kotlinSourceSets = kotlinGradleSourceSets.mapNotNull { sourceSetMap[it.name] }
|
val kotlinSourceSets = kotlinGradleSourceSets.mapNotNull { importingContext.sourceSetByName(it.name) }
|
||||||
val compileKotlinTask = getCompileKotlinTaskName(project, gradleCompilation) ?: return null
|
val compileKotlinTask = getCompileKotlinTaskName(importingContext.project, gradleCompilation) ?: return null
|
||||||
val output = buildCompilationOutput(gradleCompilation, compileKotlinTask) ?: return null
|
val output = buildCompilationOutput(gradleCompilation, compileKotlinTask) ?: return null
|
||||||
val arguments = buildCompilationArguments(compileKotlinTask)
|
val arguments = buildCompilationArguments(compileKotlinTask)
|
||||||
val dependencyClasspath = buildDependencyClasspath(compileKotlinTask)
|
val dependencyClasspath = buildDependencyClasspath(compileKotlinTask)
|
||||||
val dependencies =
|
val dependencies =
|
||||||
buildCompilationDependencies(gradleCompilation, classifier, sourceSetMap, dependencyResolver, project, dependencyMapper)
|
buildCompilationDependencies(importingContext, gradleCompilation, classifier, dependencyResolver, dependencyMapper)
|
||||||
val kotlinTaskProperties = getKotlinTaskProperties(compileKotlinTask, classifier)
|
val kotlinTaskProperties = getKotlinTaskProperties(compileKotlinTask, classifier)
|
||||||
|
|
||||||
// Get konanTarget (for native compilations only).
|
// Get konanTarget (for native compilations only).
|
||||||
@@ -609,26 +593,33 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildCompilationDependencies(
|
private fun buildCompilationDependencies(
|
||||||
|
importingContext: MultiplatformModelImportingContext,
|
||||||
gradleCompilation: Named,
|
gradleCompilation: Named,
|
||||||
classifier: String?,
|
classifier: String?,
|
||||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
|
||||||
dependencyResolver: DependencyResolver,
|
dependencyResolver: DependencyResolver,
|
||||||
project: Project,
|
|
||||||
dependencyMapper: KotlinDependencyMapper
|
dependencyMapper: KotlinDependencyMapper
|
||||||
): Set<KotlinDependency> {
|
): Set<KotlinDependency> {
|
||||||
return LinkedHashSet<KotlinDependency>().apply {
|
return LinkedHashSet<KotlinDependency>().apply {
|
||||||
val transformationBuilder = MetadataDependencyTransformationBuilder(gradleCompilation)
|
val transformationBuilder = MetadataDependencyTransformationBuilder(gradleCompilation)
|
||||||
this += buildDependencies(
|
this += buildDependencies(
|
||||||
gradleCompilation, dependencyResolver, "getCompileDependencyConfigurationName", "COMPILE", project, transformationBuilder
|
gradleCompilation,
|
||||||
|
dependencyResolver,
|
||||||
|
"getCompileDependencyConfigurationName",
|
||||||
|
"COMPILE",
|
||||||
|
importingContext.project,
|
||||||
|
transformationBuilder
|
||||||
)
|
)
|
||||||
this += buildDependencies(
|
this += buildDependencies(
|
||||||
gradleCompilation, dependencyResolver, "getRuntimeDependencyConfigurationName", "RUNTIME", project, transformationBuilder
|
gradleCompilation,
|
||||||
|
dependencyResolver,
|
||||||
|
"getRuntimeDependencyConfigurationName",
|
||||||
|
"RUNTIME",
|
||||||
|
importingContext.project,
|
||||||
|
transformationBuilder
|
||||||
).onlyNewDependencies(this)
|
).onlyNewDependencies(this)
|
||||||
|
|
||||||
this += sourceSetMap[compilationFullName(
|
val sourceSet = importingContext.sourceSetByName(compilationFullName(gradleCompilation.name, classifier))
|
||||||
gradleCompilation.name,
|
this += sourceSet?.dependencies?.mapNotNull { dependencyMapper.getDependency(it) } ?: emptySet()
|
||||||
classifier
|
|
||||||
)]?.dependencies?.map { dependencyMapper.getDependency(it) }?.filterNotNull() ?: emptySet()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,30 +771,9 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
return KotlinCompilationOutputImpl(classesDirs.files, destinationDir, resourcesDir)
|
return KotlinCompilationOutputImpl(classesDirs.files, destinationDir, resourcesDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeSourceSetsDeferredInfo(
|
private fun computeSourceSetsDeferredInfo(importingContext: MultiplatformModelImportingContext) {
|
||||||
sourceSets: Map<String, KotlinSourceSetImpl>,
|
for (sourceSet in importingContext.sourceSets) {
|
||||||
targets: Collection<KotlinTarget>,
|
if (!importingContext.getProperty(IS_HMPP_ENABLED)) {
|
||||||
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) {
|
|
||||||
val name = sourceSet.name
|
val name = sourceSet.name
|
||||||
if (name == COMMON_MAIN_SOURCE_SET_NAME) {
|
if (name == COMMON_MAIN_SOURCE_SET_NAME) {
|
||||||
sourceSet.isTestModule = false
|
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
|
sourceSet.isTestModule = isTest
|
||||||
}
|
}
|
||||||
|
|
||||||
(allSourceSetToCompilations[sourceSet])?.let { compilations ->
|
importingContext.compilationsBySourceSet(sourceSet)?.let { compilations ->
|
||||||
val platforms = compilations.map { it.platform }
|
val platforms = compilations.map { it.platform }
|
||||||
sourceSet.actualPlatforms.addSimplePlatforms(platforms)
|
sourceSet.actualPlatforms.addSimplePlatforms(platforms)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceSet.shouldCoerceToCommon(isHMPPEnabled, coerceRootSourceSetsToCommon)) {
|
if (sourceSet.shouldCoerceToCommon(importingContext)) {
|
||||||
sourceSet.actualPlatforms.addSimplePlatforms(listOf(KotlinPlatform.COMMON))
|
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
|
val isRoot = name == COMMON_MAIN_SOURCE_SET_NAME || name == COMMON_TEST_SOURCE_SET_NAME
|
||||||
|
|
||||||
// never makes sense to coerce single-targeted source-sets
|
// 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