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>) {
|
||||
if (resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) == null) {
|
||||
// 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) {
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java)
|
||||
if (mppModel == null) {
|
||||
resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java)?.sourceSets?.values?.forEach { sourceSet ->
|
||||
sourceSet.dependencies.modifyDependenciesOnMppModules(ideProject, resolverCtx)
|
||||
}
|
||||
super.populateModuleDependencies(gradleModule, ideModule, ideProject)//TODO add dependencies on mpp module
|
||||
} else {
|
||||
mppModel.dependencyMap.values.modifyDependenciesOnMppModules(ideProject, resolverCtx)
|
||||
}
|
||||
populateModuleDependencies(gradleModule, ideProject, ideModule, resolverCtx)
|
||||
}
|
||||
@@ -236,6 +192,72 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
||||
private var nativeDebugAdvertised = 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(
|
||||
gradleModule: IdeaModule,
|
||||
mainModuleNode: DataNode<ModuleData>,
|
||||
@@ -358,6 +380,10 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
||||
targetData.moduleIds = compilationIds
|
||||
}
|
||||
|
||||
sourceSetMap.values.forEach {
|
||||
it.getSecond().dependencies?.modifyDependenciesOnMppModules(projectDataNode, resolverCtx)
|
||||
}
|
||||
|
||||
val ignoreCommonSourceSets by lazy { externalProject.notImportedCommonSourceSets() }
|
||||
for (sourceSet in mppModel.sourceSets.values) {
|
||||
if (delegateToAndroidPlugin(sourceSet)) continue
|
||||
@@ -532,7 +558,8 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
||||
val processedModuleIds = HashSet<String>()
|
||||
processCompilations(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, compilation ->
|
||||
if (processedModuleIds.add(getKotlinModuleId(gradleModule, compilation, resolverCtx))) {
|
||||
val substitutedDependencies = substitutor.substituteDependencies(compilation)
|
||||
val substitutedDependencies =
|
||||
substitutor.substituteDependencies(compilation.dependencies.mapNotNull { mppModel.dependencyMap[it] })
|
||||
buildDependencies(
|
||||
resolverCtx,
|
||||
sourceSetMap,
|
||||
@@ -722,8 +749,17 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
||||
}
|
||||
|
||||
private fun addDependency(fromModule: DataNode<*>, toModule: DataNode<*>, dependOnTestModule: Boolean) {
|
||||
if (fromModule.data == toModule.data) return
|
||||
val fromData = fromModule.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 {
|
||||
it.scope = DependencyScope.COMPILE
|
||||
it.isExported = false
|
||||
|
||||
@@ -201,7 +201,15 @@ class ModuleInfo(
|
||||
}
|
||||
|
||||
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) {
|
||||
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")
|
||||
|
||||
@@ -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(
|
||||
gradleCompilation: Named,
|
||||
classifier: String?,
|
||||
@@ -580,11 +594,14 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
)
|
||||
this += buildDependencies(
|
||||
gradleCompilation, dependencyResolver, "getRuntimeDependencyConfigurationName", "RUNTIME", project, transformationBuilder
|
||||
)
|
||||
).onlyNewDependencies(this)
|
||||
|
||||
this += sourceSetMap[compilationFullName(
|
||||
gradleCompilation.name,
|
||||
classifier
|
||||
)]?.dependencies?.map { dependencyMapper.getDependency(it) }?.filterNotNull() ?: emptySet()
|
||||
|
||||
makeConfigurationNamesDefault(dependencyMapper)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,7 +675,8 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
)
|
||||
this += buildDependencies(
|
||||
gradleSourceSet, dependencyResolver, "getRuntimeOnlyMetadataConfigurationName", "RUNTIME", project, transformationBuilder
|
||||
)
|
||||
).onlyNewDependencies(this)
|
||||
|
||||
this += buildAndroidSourceSetDependencies(androidDeps, gradleSourceSet)
|
||||
}
|
||||
}
|
||||
@@ -793,7 +811,6 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
|
||||
private val projectDependencyTransformation =
|
||||
transformations.filter { it.projectPath != null }.associateBy { it.projectPath }
|
||||
//TODO
|
||||
|
||||
val dependenciesByProjectPath by lazy {
|
||||
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