Fix import of MPP projects in IDEA 2020.1
This commit is contained in:
+87
-51
@@ -142,59 +142,15 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExternalDependency.getDependencyArtifacts(): Collection<File> =
|
|
||||||
when (this) {
|
|
||||||
is ExternalProjectDependency -> this.projectDependencyArtifacts
|
|
||||||
is FileCollectionDependency -> this.files
|
|
||||||
else -> emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ExternalDependency.addDependencyArtifactInternal(file: File) {
|
|
||||||
when (this) {
|
|
||||||
is ExternalProjectDependency -> this.projectDependencyArtifacts.add(file)
|
|
||||||
is FileCollectionDependency -> this.files.add(file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun populateModuleDependencies(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>, ideProject: DataNode<ProjectData>) {
|
override fun populateModuleDependencies(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>, ideProject: DataNode<ProjectData>) {
|
||||||
if (resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) == null) {
|
val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java)
|
||||||
// Add mpp-artifacts into map used for dependency substitution
|
if (mppModel == null) {
|
||||||
val mppArtifacts = ideProject.getUserData(MPP_CONFIGURATION_ARTIFACTS)
|
resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java)?.sourceSets?.values?.forEach { sourceSet ->
|
||||||
val configArtifacts = ideProject.getUserData(CONFIGURATION_ARTIFACTS)
|
sourceSet.dependencies.modifyDependenciesOnMppModules(ideProject, resolverCtx)
|
||||||
if (mppArtifacts != null && configArtifacts != null) {
|
|
||||||
// processing case when one artifact could be produced by several (actualized!)source sets
|
|
||||||
if (mppArtifacts.isNotEmpty() && resolverCtx.isResolveModulePerSourceSet) {
|
|
||||||
val externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java)
|
|
||||||
|
|
||||||
//Note! Should not use MultiValuesMap as it contains Set of values, but we need comparision === instead of ==
|
|
||||||
val artifactToDependency = HashMap<String, MutableCollection<ExternalDependency>>()
|
|
||||||
externalProject?.sourceSets?.values?.forEach { sourceSet ->
|
|
||||||
sourceSet.dependencies.forEach { dependency ->
|
|
||||||
dependency.getDependencyArtifacts().map { toCanonicalPath(it.absolutePath) }
|
|
||||||
.filter { mppArtifacts.keys.contains(it) }.forEach { filePath ->
|
|
||||||
(artifactToDependency[filePath] ?: ArrayList<ExternalDependency>().also { newCollection ->
|
|
||||||
artifactToDependency[filePath] = newCollection
|
|
||||||
}).add(dependency)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// create 'fake' dependency artifact files and put them into dependency substitution map
|
|
||||||
mppArtifacts.forEach { (filePath, moduleIds) ->
|
|
||||||
moduleIds.firstOrNull()?.also { configArtifacts[filePath] = it }
|
|
||||||
artifactToDependency[filePath]?.forEach { externalDependency ->
|
|
||||||
for ((index, module) in moduleIds.withIndex()) {
|
|
||||||
if (index != 0) {
|
|
||||||
val fakeArtifact = "$filePath-MPP-$index"
|
|
||||||
configArtifacts[fakeArtifact] = module
|
|
||||||
externalDependency.addDependencyArtifactInternal(File(fakeArtifact))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
super.populateModuleDependencies(gradleModule, ideModule, ideProject)//TODO add dependencies on mpp module
|
super.populateModuleDependencies(gradleModule, ideModule, ideProject)//TODO add dependencies on mpp module
|
||||||
|
} else {
|
||||||
|
mppModel.dependencyMap.values.modifyDependenciesOnMppModules(ideProject, resolverCtx)
|
||||||
}
|
}
|
||||||
populateModuleDependencies(gradleModule, ideProject, ideModule, resolverCtx)
|
populateModuleDependencies(gradleModule, ideProject, ideModule, resolverCtx)
|
||||||
}
|
}
|
||||||
@@ -236,6 +192,72 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
private var nativeDebugAdvertised = false
|
private var nativeDebugAdvertised = false
|
||||||
private val androidPluginPresent = PluginManager.getPlugin(PluginId.findId("org.jetbrains.android"))?.isEnabled ?: false
|
private val androidPluginPresent = PluginManager.getPlugin(PluginId.findId("org.jetbrains.android"))?.isEnabled ?: false
|
||||||
|
|
||||||
|
private fun ExternalDependency.getDependencyArtifacts(): Collection<File> =
|
||||||
|
when (this) {
|
||||||
|
is ExternalProjectDependency -> this.projectDependencyArtifacts
|
||||||
|
is FileCollectionDependency -> this.files
|
||||||
|
else -> emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Collection<ExternalDependency>.modifyDependenciesOnMppModules(
|
||||||
|
ideProject: DataNode<ProjectData>,
|
||||||
|
resolverCtx: ProjectResolverContext
|
||||||
|
) {
|
||||||
|
// Add mpp-artifacts into map used for dependency substitution
|
||||||
|
val mppArtifacts = ideProject.getUserData(MPP_CONFIGURATION_ARTIFACTS)
|
||||||
|
val configArtifacts = ideProject.getUserData(CONFIGURATION_ARTIFACTS)
|
||||||
|
if (mppArtifacts != null && configArtifacts != null) {
|
||||||
|
val reverseConfigArtifacts = HashMap(configArtifacts.map { it.value to it.key }.toMap())
|
||||||
|
// processing case when one artifact could be produced by several (actualized!)source sets
|
||||||
|
if (mppArtifacts.isNotEmpty() && resolverCtx.isResolveModulePerSourceSet) {
|
||||||
|
//Note! Should not use MultiValuesMap as it contains Set of values, but we need comparision === instead of ==
|
||||||
|
val artifactToDependency = HashMap<String, MutableCollection<ExternalDependency>>()
|
||||||
|
this.forEach { dependency ->
|
||||||
|
dependency.getDependencyArtifacts().map { toCanonicalPath(it.absolutePath) }
|
||||||
|
.filter { mppArtifacts.keys.contains(it) }.forEach { filePath ->
|
||||||
|
(artifactToDependency[filePath] ?: ArrayList<ExternalDependency>().also { newCollection ->
|
||||||
|
artifactToDependency[filePath] = newCollection
|
||||||
|
}).add(dependency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// create 'fake' dependency artifact files and put them into dependency substitution map
|
||||||
|
mppArtifacts.forEach { (filePath, moduleIds) ->
|
||||||
|
moduleIds.firstOrNull()?.also { configArtifacts[filePath] = it }
|
||||||
|
artifactToDependency[filePath]?.forEach { externalDependency ->
|
||||||
|
for ((index, module) in moduleIds.withIndex()) {
|
||||||
|
if (index != 0) {
|
||||||
|
val fakeArtifact = if (reverseConfigArtifacts.containsKey(module)) {
|
||||||
|
reverseConfigArtifacts[module]
|
||||||
|
} else {
|
||||||
|
val result = "$filePath-MPP-$index"
|
||||||
|
configArtifacts[result] = module
|
||||||
|
reverseConfigArtifacts[module] = result
|
||||||
|
result
|
||||||
|
}
|
||||||
|
externalDependency.addDependencyArtifactInternal(File(fakeArtifact))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ExternalDependency.addDependencyArtifactInternal(file: File) {
|
||||||
|
when (this) {
|
||||||
|
is DefaultExternalProjectDependency -> this.projectDependencyArtifacts =
|
||||||
|
ArrayList<File>(this.projectDependencyArtifacts).also {
|
||||||
|
it.add(file)
|
||||||
|
}
|
||||||
|
is ExternalProjectDependency -> try {
|
||||||
|
this.projectDependencyArtifacts.add(file)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
is FileCollectionDependency -> this.files.add(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun initializeModuleData(
|
fun initializeModuleData(
|
||||||
gradleModule: IdeaModule,
|
gradleModule: IdeaModule,
|
||||||
mainModuleNode: DataNode<ModuleData>,
|
mainModuleNode: DataNode<ModuleData>,
|
||||||
@@ -358,6 +380,10 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
targetData.moduleIds = compilationIds
|
targetData.moduleIds = compilationIds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceSetMap.values.forEach {
|
||||||
|
it.getSecond().dependencies?.modifyDependenciesOnMppModules(projectDataNode, resolverCtx)
|
||||||
|
}
|
||||||
|
|
||||||
val ignoreCommonSourceSets by lazy { externalProject.notImportedCommonSourceSets() }
|
val ignoreCommonSourceSets by lazy { externalProject.notImportedCommonSourceSets() }
|
||||||
for (sourceSet in mppModel.sourceSets.values) {
|
for (sourceSet in mppModel.sourceSets.values) {
|
||||||
if (delegateToAndroidPlugin(sourceSet)) continue
|
if (delegateToAndroidPlugin(sourceSet)) continue
|
||||||
@@ -532,7 +558,8 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
val processedModuleIds = HashSet<String>()
|
val processedModuleIds = HashSet<String>()
|
||||||
processCompilations(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, compilation ->
|
processCompilations(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, compilation ->
|
||||||
if (processedModuleIds.add(getKotlinModuleId(gradleModule, compilation, resolverCtx))) {
|
if (processedModuleIds.add(getKotlinModuleId(gradleModule, compilation, resolverCtx))) {
|
||||||
val substitutedDependencies = substitutor.substituteDependencies(compilation)
|
val substitutedDependencies =
|
||||||
|
substitutor.substituteDependencies(compilation.dependencies.mapNotNull { mppModel.dependencyMap[it] })
|
||||||
buildDependencies(
|
buildDependencies(
|
||||||
resolverCtx,
|
resolverCtx,
|
||||||
sourceSetMap,
|
sourceSetMap,
|
||||||
@@ -722,8 +749,17 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addDependency(fromModule: DataNode<*>, toModule: DataNode<*>, dependOnTestModule: Boolean) {
|
private fun addDependency(fromModule: DataNode<*>, toModule: DataNode<*>, dependOnTestModule: Boolean) {
|
||||||
|
if (fromModule.data == toModule.data) return
|
||||||
val fromData = fromModule.data as? ModuleData ?: return
|
val fromData = fromModule.data as? ModuleData ?: return
|
||||||
val toData = toModule.data as? ModuleData ?: return
|
val toData = toModule.data as? ModuleData ?: return
|
||||||
|
val existing = fromModule.children.mapNotNull { it.data as? ModuleDependencyData }.filter { it.target.id == (toModule.data as? ModuleData)?.id }
|
||||||
|
val nodeToModify =
|
||||||
|
existing.singleOrNull() ?: existing.firstOrNull { it.scope == DependencyScope.COMPILE } ?: existing.firstOrNull()
|
||||||
|
if (nodeToModify != null) {
|
||||||
|
nodeToModify.scope = DependencyScope.COMPILE
|
||||||
|
nodeToModify.isProductionOnTestDependency = nodeToModify.isProductionOnTestDependency || dependOnTestModule
|
||||||
|
return
|
||||||
|
}
|
||||||
val moduleDependencyData = ModuleDependencyData(fromData, toData).also {
|
val moduleDependencyData = ModuleDependencyData(fromData, toData).also {
|
||||||
it.scope = DependencyScope.COMPILE
|
it.scope = DependencyScope.COMPILE
|
||||||
it.isExported = false
|
it.isExported = false
|
||||||
|
|||||||
@@ -201,7 +201,15 @@ class ModuleInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun moduleDependency(moduleName: String, scope: DependencyScope, productionOnTest: Boolean? = null) {
|
fun moduleDependency(moduleName: String, scope: DependencyScope, productionOnTest: Boolean? = null) {
|
||||||
val moduleEntry = rootModel.orderEntries.filterIsInstance<ModuleOrderEntry>().singleOrNull { it.moduleName == moduleName }
|
val moduleEntries = rootModel.orderEntries.filterIsInstance<ModuleOrderEntry>().filter { it.moduleName == moduleName }
|
||||||
|
if (moduleEntries.size > 1) {
|
||||||
|
projectInfo.messageCollector.report(
|
||||||
|
"Found multiple order entries for module $moduleName: ${rootModel.orderEntries.filterIsInstance<ModuleOrderEntry>()}"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val moduleEntry = moduleEntries.singleOrNull()
|
||||||
|
|
||||||
if (moduleEntry == null) {
|
if (moduleEntry == null) {
|
||||||
val allModules = rootModel.orderEntries.filterIsInstance<ModuleOrderEntry>().map { it.moduleName }.joinToString(", ")
|
val allModules = rootModel.orderEntries.filterIsInstance<ModuleOrderEntry>().map { it.moduleName }.joinToString(", ")
|
||||||
projectInfo.messageCollector.report("Module '${module.name}': No module dependency found: '$moduleName'. All module names: $allModules")
|
projectInfo.messageCollector.report("Module '${module.name}': No module dependency found: '$moduleName'. All module names: $allModules")
|
||||||
|
|||||||
@@ -565,6 +565,20 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns only those dependencies with RUNTIME scope which are not present with compile scope
|
||||||
|
*/
|
||||||
|
private fun Collection<KotlinDependency>.onlyNewDependencies(compileDependencies: Collection<KotlinDependency>): List<KotlinDependency> {
|
||||||
|
val compileDependencyArtefacts = compileDependencies.flatMap { (it as? ExternalProjectDependency)?.projectDependencyArtifacts ?: emptyList() }
|
||||||
|
return this.filter {
|
||||||
|
if (it is ExternalProjectDependency)
|
||||||
|
!(compileDependencyArtefacts.containsAll(it.projectDependencyArtifacts))
|
||||||
|
else
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun buildCompilationDependencies(
|
private fun buildCompilationDependencies(
|
||||||
gradleCompilation: Named,
|
gradleCompilation: Named,
|
||||||
classifier: String?,
|
classifier: String?,
|
||||||
@@ -580,11 +594,14 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
)
|
)
|
||||||
this += buildDependencies(
|
this += buildDependencies(
|
||||||
gradleCompilation, dependencyResolver, "getRuntimeDependencyConfigurationName", "RUNTIME", project, transformationBuilder
|
gradleCompilation, dependencyResolver, "getRuntimeDependencyConfigurationName", "RUNTIME", project, transformationBuilder
|
||||||
)
|
).onlyNewDependencies(this)
|
||||||
|
|
||||||
this += sourceSetMap[compilationFullName(
|
this += sourceSetMap[compilationFullName(
|
||||||
gradleCompilation.name,
|
gradleCompilation.name,
|
||||||
classifier
|
classifier
|
||||||
)]?.dependencies?.map { dependencyMapper.getDependency(it) }?.filterNotNull() ?: emptySet()
|
)]?.dependencies?.map { dependencyMapper.getDependency(it) }?.filterNotNull() ?: emptySet()
|
||||||
|
|
||||||
|
makeConfigurationNamesDefault(dependencyMapper)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +675,8 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
)
|
)
|
||||||
this += buildDependencies(
|
this += buildDependencies(
|
||||||
gradleSourceSet, dependencyResolver, "getRuntimeOnlyMetadataConfigurationName", "RUNTIME", project, transformationBuilder
|
gradleSourceSet, dependencyResolver, "getRuntimeOnlyMetadataConfigurationName", "RUNTIME", project, transformationBuilder
|
||||||
)
|
).onlyNewDependencies(this)
|
||||||
|
|
||||||
this += buildAndroidSourceSetDependencies(androidDeps, gradleSourceSet)
|
this += buildAndroidSourceSetDependencies(androidDeps, gradleSourceSet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -793,7 +811,6 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
|||||||
|
|
||||||
private val projectDependencyTransformation =
|
private val projectDependencyTransformation =
|
||||||
transformations.filter { it.projectPath != null }.associateBy { it.projectPath }
|
transformations.filter { it.projectPath != null }.associateBy { it.projectPath }
|
||||||
//TODO
|
|
||||||
|
|
||||||
val dependenciesByProjectPath by lazy {
|
val dependenciesByProjectPath by lazy {
|
||||||
configuration
|
configuration
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
//BUNCH: 193
|
||||||
|
fun makeConfigurationNamesDefault(dependencyMapper: KotlinDependencyMapper) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* 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.jetbrains.plugins.gradle.model.DefaultExternalProjectDependency
|
||||||
|
|
||||||
|
//BUNCH: 193
|
||||||
|
fun makeConfigurationNamesDefault(dependencyMapper: KotlinDependencyMapper) {
|
||||||
|
dependencyMapper.toDependencyMap().values.forEach {
|
||||||
|
(it as? DefaultExternalProjectDependency)?.configurationName = "default"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user