MPP: Support MPP-dependent Java modules in Android projects

#KT-27265 Fixed
This commit is contained in:
Alexey Sedunov
2018-10-04 20:53:15 +03:00
parent dcdd42ba00
commit fea397a2ad
4 changed files with 220 additions and 64 deletions
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.project.sync.idea.data.service.AndroidProjectKeys
import com.android.tools.idea.gradle.util.ContentEntries.findParentContentEntry
import com.android.tools.idea.io.FilePaths
import com.intellij.openapi.diagnostic.Logger
@@ -20,6 +20,7 @@ import com.intellij.openapi.externalSystem.service.project.manage.ContentRootDat
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.util.SmartList
@@ -78,7 +79,9 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
}
val androidModel = module.getAndroidModel(modelsProvider) ?: continue
addExtraDependeeModules(nodeToImport, projectNode, modelsProvider, rootModel, false)
addExtraDependeeModules(nodeToImport, projectNode, modelsProvider, rootModel, true)
val androidModel = getAndroidModuleModel(nodeToImport) ?: continue
val variantName = androidModel.selectedVariant.name
val activeSourceSetInfos = nodeToImport.kotlinAndroidSourceSets?.filter { it.kotlinModule.name.startsWith(variantName) } ?: emptyList()
for (activeSourceSetInfo in activeSourceSetInfos) {
@@ -94,8 +97,6 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
}
addExtraDependeeModules(androidModel, projectNode, modelsProvider, rootModel, false)
addExtraDependeeModules(androidModel, projectNode, modelsProvider, rootModel, true)
val mainSourceSetInfo = activeSourceSetInfos.firstOrNull { it.kotlinModule.name == variantName }
if (mainSourceSetInfo != null) {
@@ -109,32 +110,64 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
private fun getDependeeModuleNodes(
moduleNode: DataNode<ModuleData>,
projectNode: DataNode<ProjectData>,
modelsProvider: IdeModifiableModelsProvider,
testScope: Boolean
): List<DataNode<out ModuleData>> {
val androidModel = getAndroidModuleModel(moduleNode)
if (androidModel != null) {
val dependencies = if (testScope) {
androidModel.selectedAndroidTestCompileDependencies
} else {
androidModel.selectedMainCompileLevel2Dependencies
} ?: return emptyList()
return dependencies
.moduleDependencies
.mapNotNull { projectNode.findChildModuleById(it.projectPath) }
}
val javaModel = getJavaModuleModel(moduleNode)
if (javaModel != null) {
val scope = if (testScope) DependencyScope.TEST.name else DependencyScope.COMPILE.name
val moduleNames = javaModel
.javaModuleDependencies
.filter { scope == it.scope ?: DependencyScope.COMPILE.name }
.mapTo(HashSet()) { it.moduleName }
return ExternalSystemApiUtil
.getChildren(projectNode, ProjectKeys.MODULE)
.filter { modelsProvider.findIdeModule(it.data)?.name in moduleNames }
}
return emptyList()
}
private fun List<DataNode<GradleSourceSetData>>.firstByPlatformOrNull(platform: KotlinPlatform) = firstOrNull {
it.kotlinSourceSet?.platform == platform
}
private fun addExtraDependeeModules(
androidModel: AndroidModuleModel,
moduleNode: DataNode<ModuleData>,
projectNode: DataNode<ProjectData>,
modelsProvider: IdeModifiableModelsProvider,
rootModel: ModifiableRootModel,
testScope: Boolean
) {
val dependencies = if (testScope) {
androidModel.selectedAndroidTestCompileDependencies
} else {
androidModel.selectedMainCompileLevel2Dependencies
} ?: return
val commonSourceSetName = KotlinSourceSet.commonName(testScope)
val relevantNodes = dependencies
.moduleDependencies
.mapNotNull { projectNode.findChildModuleById(it.projectPath) }
val dependeeModuleNodes = getDependeeModuleNodes(moduleNode, projectNode, modelsProvider, testScope)
val relevantNodes = dependeeModuleNodes
.flatMap { ExternalSystemApiUtil.getChildren(it, GradleSourceSetData.KEY) }
.filter {
val ktModule = it.kotlinSourceSet?.kotlinModule
ktModule != null && ktModule.isTestModule == testScope
}
val commonSourceSetName = KotlinSourceSet.commonName(testScope)
val isAndroidModule = getAndroidModuleModel(moduleNode) != null
SmartList<DataNode<GradleSourceSetData>>()
.apply {
addIfNotNull(
relevantNodes.firstOrNull { it.kotlinSourceSet?.platform == KotlinPlatform.ANDROID }
?: relevantNodes.firstOrNull { it.kotlinSourceSet?.platform == KotlinPlatform.JVM }
(if (isAndroidModule) relevantNodes.firstByPlatformOrNull(KotlinPlatform.ANDROID) else null)
?: relevantNodes.firstByPlatformOrNull(KotlinPlatform.JVM)
)
addIfNotNull(
relevantNodes.firstOrNull {
@@ -152,6 +185,12 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
private fun getAndroidModuleModel(moduleNode: DataNode<ModuleData>) =
ExternalSystemApiUtil.getChildren(moduleNode, AndroidProjectKeys.ANDROID_MODEL).firstOrNull()?.data
private fun getJavaModuleModel(moduleNode: DataNode<ModuleData>) =
ExternalSystemApiUtil.getChildren(moduleNode, AndroidProjectKeys.JAVA_MODULE_MODEL).firstOrNull()?.data
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.project.sync.idea.data.service.AndroidProjectKeys
import com.android.tools.idea.gradle.util.ContentEntries.findParentContentEntry
import com.android.tools.idea.gradle.util.FilePaths
import com.intellij.openapi.diagnostic.Logger
@@ -20,6 +20,7 @@ import com.intellij.openapi.externalSystem.service.project.manage.ContentRootDat
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.util.SmartList
@@ -78,7 +79,9 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
}
val androidModel = module.getAndroidModel(modelsProvider) ?: continue
addExtraDependeeModules(nodeToImport, projectNode, modelsProvider, rootModel, false)
addExtraDependeeModules(nodeToImport, projectNode, modelsProvider, rootModel, true)
val androidModel = getAndroidModuleModel(nodeToImport) ?: continue
val variantName = androidModel.selectedVariant.name
val activeSourceSetInfos = nodeToImport.kotlinAndroidSourceSets?.filter { it.kotlinModule.name.startsWith(variantName) } ?: emptyList()
for (activeSourceSetInfo in activeSourceSetInfos) {
@@ -94,8 +97,6 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
}
addExtraDependeeModules(androidModel, projectNode, modelsProvider, rootModel, false)
addExtraDependeeModules(androidModel, projectNode, modelsProvider, rootModel, true)
val mainSourceSetInfo = activeSourceSetInfos.firstOrNull { it.kotlinModule.name == variantName }
if (mainSourceSetInfo != null) {
@@ -109,32 +110,64 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
private fun getDependeeModuleNodes(
moduleNode: DataNode<ModuleData>,
projectNode: DataNode<ProjectData>,
modelsProvider: IdeModifiableModelsProvider,
testScope: Boolean
): List<DataNode<out ModuleData>> {
val androidModel = getAndroidModuleModel(moduleNode)
if (androidModel != null) {
val dependencies = if (testScope) {
androidModel.selectedAndroidTestCompileDependencies
} else {
androidModel.selectedMainCompileLevel2Dependencies
} ?: return emptyList()
return dependencies
.moduleDependencies
.mapNotNull { projectNode.findChildModuleById(it.projectPath) }
}
val javaModel = getJavaModuleModel(moduleNode)
if (javaModel != null) {
val scope = if (testScope) DependencyScope.TEST.name else DependencyScope.COMPILE.name
val moduleNames = javaModel
.javaModuleDependencies
.filter { scope == it.scope ?: DependencyScope.COMPILE.name }
.mapTo(HashSet()) { it.moduleName }
return ExternalSystemApiUtil
.getChildren(projectNode, ProjectKeys.MODULE)
.filter { modelsProvider.findIdeModule(it.data)?.name in moduleNames }
}
return emptyList()
}
private fun List<DataNode<GradleSourceSetData>>.firstByPlatformOrNull(platform: KotlinPlatform) = firstOrNull {
it.kotlinSourceSet?.platform == platform
}
private fun addExtraDependeeModules(
androidModel: AndroidModuleModel,
moduleNode: DataNode<ModuleData>,
projectNode: DataNode<ProjectData>,
modelsProvider: IdeModifiableModelsProvider,
rootModel: ModifiableRootModel,
testScope: Boolean
) {
val dependencies = if (testScope) {
androidModel.selectedAndroidTestCompileDependencies
} else {
androidModel.selectedMainCompileLevel2Dependencies
} ?: return
val commonSourceSetName = KotlinSourceSet.commonName(testScope)
val relevantNodes = dependencies
.moduleDependencies
.mapNotNull { projectNode.findChildModuleById(it.projectPath) }
val dependeeModuleNodes = getDependeeModuleNodes(moduleNode, projectNode, modelsProvider, testScope)
val relevantNodes = dependeeModuleNodes
.flatMap { ExternalSystemApiUtil.getChildren(it, GradleSourceSetData.KEY) }
.filter {
val ktModule = it.kotlinSourceSet?.kotlinModule
ktModule != null && ktModule.isTestModule == testScope
}
val commonSourceSetName = KotlinSourceSet.commonName(testScope)
val isAndroidModule = getAndroidModuleModel(moduleNode) != null
SmartList<DataNode<GradleSourceSetData>>()
.apply {
addIfNotNull(
relevantNodes.firstOrNull { it.kotlinSourceSet?.platform == KotlinPlatform.ANDROID }
?: relevantNodes.firstOrNull { it.kotlinSourceSet?.platform == KotlinPlatform.JVM }
(if (isAndroidModule) relevantNodes.firstByPlatformOrNull(KotlinPlatform.ANDROID) else null)
?: relevantNodes.firstByPlatformOrNull(KotlinPlatform.JVM)
)
addIfNotNull(
relevantNodes.firstOrNull {
@@ -152,6 +185,12 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
private fun getAndroidModuleModel(moduleNode: DataNode<ModuleData>) =
ExternalSystemApiUtil.getChildren(moduleNode, AndroidProjectKeys.ANDROID_MODEL).firstOrNull()?.data
private fun getJavaModuleModel(moduleNode: DataNode<ModuleData>) =
ExternalSystemApiUtil.getChildren(moduleNode, AndroidProjectKeys.JAVA_MODULE_MODEL).firstOrNull()?.data
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.project.sync.idea.data.service.AndroidProjectKeys
import com.android.tools.idea.gradle.util.ContentEntries.findParentContentEntry
import com.android.tools.idea.io.FilePaths
import com.intellij.openapi.diagnostic.Logger
@@ -22,6 +22,7 @@ import com.intellij.openapi.externalSystem.service.project.manage.ContentRootDat
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.util.SmartList
@@ -89,7 +90,9 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
}
val androidModel = module.getAndroidModel(modelsProvider) ?: continue
addExtraDependeeModules(nodeToImport, projectNode, modelsProvider, rootModel, false)
addExtraDependeeModules(nodeToImport, projectNode, modelsProvider, rootModel, true)
val androidModel = getAndroidModuleModel(nodeToImport) ?: continue
val variantName = androidModel.selectedVariant.name
val activeSourceSetInfos = nodeToImport.kotlinAndroidSourceSets?.filter { it.kotlinModule.name.startsWith(variantName) } ?: emptyList()
for (activeSourceSetInfo in activeSourceSetInfos) {
@@ -105,8 +108,6 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
}
addExtraDependeeModules(androidModel, projectNode, modelsProvider, rootModel, false)
addExtraDependeeModules(androidModel, projectNode, modelsProvider, rootModel, true)
val mainSourceSetInfo = activeSourceSetInfos.firstOrNull { it.kotlinModule.name == variantName }
if (mainSourceSetInfo != null) {
@@ -120,32 +121,64 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
private fun getDependeeModuleNodes(
moduleNode: DataNode<ModuleData>,
projectNode: DataNode<ProjectData>,
modelsProvider: IdeModifiableModelsProvider,
testScope: Boolean
): List<DataNode<out ModuleData>> {
val androidModel = getAndroidModuleModel(moduleNode)
if (androidModel != null) {
val dependencies = if (testScope) {
androidModel.selectedAndroidTestCompileDependencies
} else {
androidModel.selectedMainCompileLevel2Dependencies
} ?: return emptyList()
return dependencies
.moduleDependencies
.mapNotNull { projectNode.findChildModuleById(it.projectPath) }
}
val javaModel = getJavaModuleModel(moduleNode)
if (javaModel != null) {
val scope = if (testScope) DependencyScope.TEST.name else DependencyScope.COMPILE.name
val moduleNames = javaModel
.javaModuleDependencies
.filter { scope == it.scope ?: DependencyScope.COMPILE.name }
.mapTo(HashSet()) { it.moduleName }
return ExternalSystemApiUtil
.getChildren(projectNode, ProjectKeys.MODULE)
.filter { modelsProvider.findIdeModule(it.data)?.name in moduleNames }
}
return emptyList()
}
private fun List<DataNode<GradleSourceSetData>>.firstByPlatformOrNull(platform: KotlinPlatform) = firstOrNull {
it.kotlinSourceSet?.platform == platform
}
private fun addExtraDependeeModules(
androidModel: AndroidModuleModel,
moduleNode: DataNode<ModuleData>,
projectNode: DataNode<ProjectData>,
modelsProvider: IdeModifiableModelsProvider,
rootModel: ModifiableRootModel,
testScope: Boolean
) {
val dependencies = if (testScope) {
androidModel.selectedAndroidTestCompileDependencies
} else {
androidModel.selectedMainCompileLevel2Dependencies
} ?: return
val commonSourceSetName = KotlinSourceSet.commonName(testScope)
val relevantNodes = dependencies
.moduleDependencies
.mapNotNull { projectNode.findChildModuleById(it.projectPath) }
val dependeeModuleNodes = getDependeeModuleNodes(moduleNode, projectNode, modelsProvider, testScope)
val relevantNodes = dependeeModuleNodes
.flatMap { ExternalSystemApiUtil.getChildren(it, GradleSourceSetData.KEY) }
.filter {
val ktModule = it.kotlinSourceSet?.kotlinModule
ktModule != null && ktModule.isTestModule == testScope
}
val commonSourceSetName = KotlinSourceSet.commonName(testScope)
val isAndroidModule = getAndroidModuleModel(moduleNode) != null
SmartList<DataNode<GradleSourceSetData>>()
.apply {
addIfNotNull(
relevantNodes.firstOrNull { it.kotlinSourceSet?.platform == KotlinPlatform.ANDROID }
?: relevantNodes.firstOrNull { it.kotlinSourceSet?.platform == KotlinPlatform.JVM }
(if (isAndroidModule) relevantNodes.firstByPlatformOrNull(KotlinPlatform.ANDROID) else null)
?: relevantNodes.firstByPlatformOrNull(KotlinPlatform.JVM)
)
addIfNotNull(
relevantNodes.firstOrNull {
@@ -163,6 +196,12 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
private fun getAndroidModuleModel(moduleNode: DataNode<ModuleData>) =
ExternalSystemApiUtil.getChildren(moduleNode, AndroidProjectKeys.ANDROID_MODEL).firstOrNull()?.data
private fun getJavaModuleModel(moduleNode: DataNode<ModuleData>) =
ExternalSystemApiUtil.getChildren(moduleNode, AndroidProjectKeys.JAVA_MODULE_MODEL).firstOrNull()?.data
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.project.sync.idea.data.service.AndroidProjectKeys
import com.android.tools.idea.gradle.util.ContentEntries.findParentContentEntry
import com.android.tools.idea.io.FilePaths
import com.intellij.openapi.diagnostic.Logger
@@ -20,6 +20,7 @@ import com.intellij.openapi.externalSystem.service.project.manage.ContentRootDat
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.util.SmartList
@@ -78,7 +79,9 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
}
val androidModel = module.getAndroidModel(modelsProvider) ?: continue
addExtraDependeeModules(nodeToImport, projectNode, modelsProvider, rootModel, false)
addExtraDependeeModules(nodeToImport, projectNode, modelsProvider, rootModel, true)
val androidModel = getAndroidModuleModel(nodeToImport) ?: continue
val variantName = androidModel.selectedVariant.name
val activeSourceSetInfos = nodeToImport.kotlinAndroidSourceSets?.filter { it.kotlinModule.name.startsWith(variantName) } ?: emptyList()
for (activeSourceSetInfo in activeSourceSetInfos) {
@@ -94,8 +97,6 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
}
addExtraDependeeModules(androidModel, projectNode, modelsProvider, rootModel, false)
addExtraDependeeModules(androidModel, projectNode, modelsProvider, rootModel, true)
val mainSourceSetInfo = activeSourceSetInfos.firstOrNull { it.kotlinModule.name == variantName }
if (mainSourceSetInfo != null) {
@@ -109,32 +110,64 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
private fun getDependeeModuleNodes(
moduleNode: DataNode<ModuleData>,
projectNode: DataNode<ProjectData>,
modelsProvider: IdeModifiableModelsProvider,
testScope: Boolean
): List<DataNode<out ModuleData>> {
val androidModel = getAndroidModuleModel(moduleNode)
if (androidModel != null) {
val dependencies = if (testScope) {
androidModel.selectedAndroidTestCompileDependencies
} else {
androidModel.selectedMainCompileLevel2Dependencies
} ?: return emptyList()
return dependencies
.moduleDependencies
.mapNotNull { projectNode.findChildModuleById(it.projectPath) }
}
val javaModel = getJavaModuleModel(moduleNode)
if (javaModel != null) {
val scope = if (testScope) DependencyScope.TEST.name else DependencyScope.COMPILE.name
val moduleNames = javaModel
.javaModuleDependencies
.filter { scope == it.scope ?: DependencyScope.COMPILE.name }
.mapTo(HashSet()) { it.moduleName }
return ExternalSystemApiUtil
.getChildren(projectNode, ProjectKeys.MODULE)
.filter { modelsProvider.findIdeModule(it.data)?.name in moduleNames }
}
return emptyList()
}
private fun List<DataNode<GradleSourceSetData>>.firstByPlatformOrNull(platform: KotlinPlatform) = firstOrNull {
it.kotlinSourceSet?.platform == platform
}
private fun addExtraDependeeModules(
androidModel: AndroidModuleModel,
moduleNode: DataNode<ModuleData>,
projectNode: DataNode<ProjectData>,
modelsProvider: IdeModifiableModelsProvider,
rootModel: ModifiableRootModel,
testScope: Boolean
) {
val dependencies = if (testScope) {
androidModel.selectedAndroidTestCompileDependencies
} else {
androidModel.selectedMainCompileLevel2Dependencies
} ?: return
val commonSourceSetName = KotlinSourceSet.commonName(testScope)
val relevantNodes = dependencies
.moduleDependencies
.mapNotNull { projectNode.findChildModuleById(it.projectPath) }
val dependeeModuleNodes = getDependeeModuleNodes(moduleNode, projectNode, modelsProvider, testScope)
val relevantNodes = dependeeModuleNodes
.flatMap { ExternalSystemApiUtil.getChildren(it, GradleSourceSetData.KEY) }
.filter {
val ktModule = it.kotlinSourceSet?.kotlinModule
ktModule != null && ktModule.isTestModule == testScope
}
val commonSourceSetName = KotlinSourceSet.commonName(testScope)
val isAndroidModule = getAndroidModuleModel(moduleNode) != null
SmartList<DataNode<GradleSourceSetData>>()
.apply {
addIfNotNull(
relevantNodes.firstOrNull { it.kotlinSourceSet?.platform == KotlinPlatform.ANDROID }
?: relevantNodes.firstOrNull { it.kotlinSourceSet?.platform == KotlinPlatform.JVM }
(if (isAndroidModule) relevantNodes.firstByPlatformOrNull(KotlinPlatform.ANDROID) else null)
?: relevantNodes.firstByPlatformOrNull(KotlinPlatform.JVM)
)
addIfNotNull(
relevantNodes.firstOrNull {
@@ -152,6 +185,12 @@ class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<Modul
}
}
private fun getAndroidModuleModel(moduleNode: DataNode<ModuleData>) =
ExternalSystemApiUtil.getChildren(moduleNode, AndroidProjectKeys.ANDROID_MODEL).firstOrNull()?.data
private fun getJavaModuleModel(moduleNode: DataNode<ModuleData>) =
ExternalSystemApiUtil.getChildren(moduleNode, AndroidProjectKeys.JAVA_MODULE_MODEL).firstOrNull()?.data
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,