Gradle: Implement new MPP model import

This commit is contained in:
Alexey Sedunov
2018-08-03 18:54:40 +03:00
committed by Sergey Igushkin
parent caec846330
commit ecf607d4fa
32 changed files with 2128 additions and 10 deletions
@@ -0,0 +1,72 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.util.ContentEntries.findParentContentEntry
import com.android.tools.idea.io.FilePaths
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.util.containers.stream
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.gradle.KotlinCompilation
import java.io.File
class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<ModuleData, Void>() {
override fun getTargetDataKey() = ProjectKeys.MODULE
override fun postProcess(
toImport: MutableCollection<DataNode<ModuleData>>,
projectData: ProjectData?,
project: Project,
modelsProvider: IdeModifiableModelsProvider
) {
for (nodeToImport in toImport) {
val projectNode = ExternalSystemApiUtil.findParent(nodeToImport, ProjectKeys.PROJECT) ?: continue
val moduleData = nodeToImport.data
val module = modelsProvider.findIdeModule(moduleData) ?: continue
val androidModel = AndroidModuleModel.get(module) ?: continue
val variantName = androidModel.selectedVariant.name
val sourceSetInfo = nodeToImport.kotlinAndroidSourceSets?.firstOrNull { it.kotlinModule.name == variantName } ?: continue
val compilation = sourceSetInfo.kotlinModule as? KotlinCompilation ?: continue
val rootModel = modelsProvider.getModifiableRootModel(module)
for (sourceSet in compilation.sourceSets) {
if (sourceSet.isAndroid) {
val sourceType = if (sourceSet.isTestModule) JavaSourceRootType.TEST_SOURCE else JavaSourceRootType.SOURCE
val resourceType = if (sourceSet.isTestModule) JavaResourceRootType.TEST_RESOURCE else JavaResourceRootType.RESOURCE
sourceSet.sourceDirs.forEach { addSourceRoot(it, sourceType, rootModel) }
sourceSet.resourceDirs.forEach { addSourceRoot(it, resourceType, rootModel) }
} else {
val sourceSetId = sourceSetInfo.sourceSetIdsByName[sourceSet.name] ?: continue
val sourceSetData = ExternalSystemApiUtil.findFirstRecursively(projectNode) {
(it.data as? ModuleData)?.id == sourceSetId
}?.data as? ModuleData ?: continue
val sourceSetModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
rootModel.addModuleOrderEntry(sourceSetModule)
}
}
}
}
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,
rootModel: ModifiableRootModel
) {
val parent = findParentContentEntry(sourceRoot, rootModel.contentEntries.stream()) ?: return
val url = FilePaths.pathToIdeaUrl(sourceRoot)
parent.addSourceFolder(url, type)
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.util.FilePaths
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ModifiableRootModel
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.gradle.KotlinCompilation
import java.io.File
class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<ModuleData, Void>() {
override fun getTargetDataKey() = ProjectKeys.MODULE
override fun postProcess(
toImport: MutableCollection<DataNode<ModuleData>>,
projectData: ProjectData?,
project: Project,
modelsProvider: IdeModifiableModelsProvider
) {
for (nodeToImport in toImport) {
val projectNode = ExternalSystemApiUtil.findParent(nodeToImport, ProjectKeys.PROJECT) ?: continue
val moduleData = nodeToImport.data
val module = modelsProvider.findIdeModule(moduleData) ?: continue
val androidModel = AndroidModuleModel.get(module) ?: continue
val variantName = androidModel.selectedVariant.name
val sourceSetInfo = nodeToImport.kotlinAndroidSourceSets?.firstOrNull { it.kotlinModule.name == variantName } ?: continue
val compilation = sourceSetInfo.kotlinModule as? KotlinCompilation ?: continue
val rootModel = modelsProvider.getModifiableRootModel(module)
for (sourceSet in compilation.sourceSets) {
if (sourceSet.isAndroid) {
val sourceType = if (sourceSet.isTestModule) JavaSourceRootType.TEST_SOURCE else JavaSourceRootType.SOURCE
val resourceType = if (sourceSet.isTestModule) JavaResourceRootType.TEST_RESOURCE else JavaResourceRootType.RESOURCE
sourceSet.sourceDirs.forEach { addSourceRoot(it, sourceType, rootModel) }
sourceSet.resourceDirs.forEach { addSourceRoot(it, resourceType, rootModel) }
} else {
val sourceSetId = sourceSetInfo.sourceSetIdsByName[sourceSet.name] ?: continue
val sourceSetData = ExternalSystemApiUtil.findFirstRecursively(projectNode) {
(it.data as? ModuleData)?.id == sourceSetId
}?.data as? ModuleData ?: continue
val sourceSetModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
rootModel.addModuleOrderEntry(sourceSetModule)
}
}
}
}
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,
rootModel: ModifiableRootModel
) {
val parent = FilePaths.findParentContentEntry(sourceRoot, rootModel.contentEntries) ?: return
val url = FilePaths.pathToIdeaUrl(sourceRoot)
parent.addSourceFolder(url, type)
}
}
@@ -0,0 +1,72 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.util.ContentEntries.findParentContentEntry
import com.android.tools.idea.gradle.util.FilePaths
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.util.containers.stream
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.gradle.KotlinCompilation
import java.io.File
class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<ModuleData, Void>() {
override fun getTargetDataKey() = ProjectKeys.MODULE
override fun postProcess(
toImport: MutableCollection<DataNode<ModuleData>>,
projectData: ProjectData?,
project: Project,
modelsProvider: IdeModifiableModelsProvider
) {
for (nodeToImport in toImport) {
val projectNode = ExternalSystemApiUtil.findParent(nodeToImport, ProjectKeys.PROJECT) ?: continue
val moduleData = nodeToImport.data
val module = modelsProvider.findIdeModule(moduleData) ?: continue
val androidModel = AndroidModuleModel.get(module) ?: continue
val variantName = androidModel.selectedVariant.name
val sourceSetInfo = nodeToImport.kotlinAndroidSourceSets?.firstOrNull { it.kotlinModule.name == variantName } ?: continue
val compilation = sourceSetInfo.kotlinModule as? KotlinCompilation ?: continue
val rootModel = modelsProvider.getModifiableRootModel(module)
for (sourceSet in compilation.sourceSets) {
if (sourceSet.isAndroid) {
val sourceType = if (sourceSet.isTestModule) JavaSourceRootType.TEST_SOURCE else JavaSourceRootType.SOURCE
val resourceType = if (sourceSet.isTestModule) JavaResourceRootType.TEST_RESOURCE else JavaResourceRootType.RESOURCE
sourceSet.sourceDirs.forEach { addSourceRoot(it, sourceType, rootModel) }
sourceSet.resourceDirs.forEach { addSourceRoot(it, resourceType, rootModel) }
} else {
val sourceSetId = sourceSetInfo.sourceSetIdsByName[sourceSet.name] ?: continue
val sourceSetData = ExternalSystemApiUtil.findFirstRecursively(projectNode) {
(it.data as? ModuleData)?.id == sourceSetId
}?.data as? ModuleData ?: continue
val sourceSetModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
rootModel.addModuleOrderEntry(sourceSetModule)
}
}
}
}
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,
rootModel: ModifiableRootModel
) {
val parent = findParentContentEntry(sourceRoot, rootModel.contentEntries.stream()) ?: return
val url = FilePaths.pathToIdeaUrl(sourceRoot)
parent.addSourceFolder(url, type)
}
}
@@ -0,0 +1,72 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.util.ContentEntries.findParentContentEntry
import com.android.tools.idea.io.FilePaths
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.util.containers.stream
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.gradle.KotlinCompilation
import java.io.File
class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<ModuleData, Void>() {
override fun getTargetDataKey() = ProjectKeys.MODULE
override fun postProcess(
toImport: MutableCollection<DataNode<ModuleData>>,
projectData: ProjectData?,
project: Project,
modelsProvider: IdeModifiableModelsProvider
) {
for (nodeToImport in toImport) {
val projectNode = ExternalSystemApiUtil.findParent(nodeToImport, ProjectKeys.PROJECT) ?: continue
val moduleData = nodeToImport.data
val module = modelsProvider.findIdeModule(moduleData) ?: continue
val androidModel = AndroidModuleModel.get(module) ?: continue
val variantName = androidModel.selectedVariant.name
val sourceSetInfo = nodeToImport.kotlinAndroidSourceSets?.firstOrNull { it.kotlinModule.name == variantName } ?: continue
val compilation = sourceSetInfo.kotlinModule as? KotlinCompilation ?: continue
val rootModel = modelsProvider.getModifiableRootModel(module)
for (sourceSet in compilation.sourceSets) {
if (sourceSet.isAndroid) {
val sourceType = if (sourceSet.isTestModule) JavaSourceRootType.TEST_SOURCE else JavaSourceRootType.SOURCE
val resourceType = if (sourceSet.isTestModule) JavaResourceRootType.TEST_RESOURCE else JavaResourceRootType.RESOURCE
sourceSet.sourceDirs.forEach { addSourceRoot(it, sourceType, rootModel) }
sourceSet.resourceDirs.forEach { addSourceRoot(it, resourceType, rootModel) }
} else {
val sourceSetId = sourceSetInfo.sourceSetIdsByName[sourceSet.name] ?: continue
val sourceSetData = ExternalSystemApiUtil.findFirstRecursively(projectNode) {
(it.data as? ModuleData)?.id == sourceSetId
}?.data as? ModuleData ?: continue
val sourceSetModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
rootModel.addModuleOrderEntry(sourceSetModule)
}
}
}
}
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,
rootModel: ModifiableRootModel
) {
val parent = findParentContentEntry(sourceRoot, rootModel.contentEntries.stream()) ?: return
val url = FilePaths.pathToIdeaUrl(sourceRoot)
parent.addSourceFolder(url, type)
}
}
@@ -0,0 +1,72 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.util.ContentEntries.findParentContentEntry
import com.android.tools.idea.io.FilePaths
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.util.containers.stream
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.gradle.KotlinCompilation
import java.io.File
class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<ModuleData, Void>() {
override fun getTargetDataKey() = ProjectKeys.MODULE
override fun postProcess(
toImport: MutableCollection<DataNode<ModuleData>>,
projectData: ProjectData?,
project: Project,
modelsProvider: IdeModifiableModelsProvider
) {
for (nodeToImport in toImport) {
val projectNode = ExternalSystemApiUtil.findParent(nodeToImport, ProjectKeys.PROJECT) ?: continue
val moduleData = nodeToImport.data
val module = modelsProvider.findIdeModule(moduleData) ?: continue
val androidModel = AndroidModuleModel.get(module) ?: continue
val variantName = androidModel.selectedVariant.name
val sourceSetInfo = nodeToImport.kotlinAndroidSourceSets?.firstOrNull { it.kotlinModule.name == variantName } ?: continue
val compilation = sourceSetInfo.kotlinModule as? KotlinCompilation ?: continue
val rootModel = modelsProvider.getModifiableRootModel(module)
for (sourceSet in compilation.sourceSets) {
if (sourceSet.isAndroid) {
val sourceType = if (sourceSet.isTestModule) JavaSourceRootType.TEST_SOURCE else JavaSourceRootType.SOURCE
val resourceType = if (sourceSet.isTestModule) JavaResourceRootType.TEST_RESOURCE else JavaResourceRootType.RESOURCE
sourceSet.sourceDirs.forEach { addSourceRoot(it, sourceType, rootModel) }
sourceSet.resourceDirs.forEach { addSourceRoot(it, resourceType, rootModel) }
} else {
val sourceSetId = sourceSetInfo.sourceSetIdsByName[sourceSet.name] ?: continue
val sourceSetData = ExternalSystemApiUtil.findFirstRecursively(projectNode) {
(it.data as? ModuleData)?.id == sourceSetId
}?.data as? ModuleData ?: continue
val sourceSetModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
rootModel.addModuleOrderEntry(sourceSetModule)
}
}
}
}
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,
rootModel: ModifiableRootModel
) {
val parent = findParentContentEntry(sourceRoot, rootModel.contentEntries.stream()) ?: return
val url = FilePaths.pathToIdeaUrl(sourceRoot)
parent.addSourceFolder(url, type)
}
}
@@ -0,0 +1,81 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.android.configure
import com.android.builder.model.AndroidProject
import com.android.builder.model.NativeAndroidProject
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants
import com.intellij.openapi.externalSystem.util.Order
import com.intellij.openapi.util.Key
import org.gradle.tooling.model.idea.IdeaModule
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModelBuilder
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver
import org.jetbrains.kotlin.idea.configuration.KotlinSourceSetInfo
import org.jetbrains.kotlin.idea.util.CopyableDataNodeUserDataProperty
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
var DataNode<ModuleData>.kotlinAndroidSourceSets: List<KotlinSourceSetInfo>?
by CopyableDataNodeUserDataProperty(Key.create("ANDROID_COMPILATIONS"))
@Order(ExternalSystemConstants.UNORDERED - 1)
class KotlinAndroidMPPGradleProjectResolver : AbstractProjectResolverExtension() {
private val isAndroidProject by lazy {
resolverCtx.hasModulesWithModel(AndroidProject::class.java)
|| resolverCtx.hasModulesWithModel(NativeAndroidProject::class.java)
}
override fun getToolingExtensionsClasses(): Set<Class<out Any>> {
return setOf(KotlinMPPGradleModelBuilder::class.java, Unit::class.java)
}
override fun getExtraProjectModelClasses(): Set<Class<out Any>> {
return setOf(KotlinMPPGradleModel::class.java)
}
override fun createModule(gradleModule: IdeaModule, projectDataNode: DataNode<ProjectData>): DataNode<ModuleData> {
return super.createModule(gradleModule, projectDataNode).also {
initializeModuleData(gradleModule, it, projectDataNode)
}
}
override fun populateModuleContentRoots(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
super.populateModuleContentRoots(gradleModule, ideModule)
if (isAndroidProject) {
KotlinMPPGradleProjectResolver.populateContentRoots(gradleModule, ideModule, resolverCtx)
}
}
override fun populateModuleDependencies(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>, ideProject: DataNode<ProjectData>) {
super.populateModuleDependencies(gradleModule, ideModule, ideProject)
if (isAndroidProject) {
KotlinMPPGradleProjectResolver.populateModuleDependencies(gradleModule, ideProject, ideModule, resolverCtx)
}
}
private fun initializeModuleData(
gradleModule: IdeaModule,
mainModuleData: DataNode<ModuleData>,
projectDataNode: DataNode<ProjectData>
) {
if (!isAndroidProject) return
KotlinMPPGradleProjectResolver.initializeModuleData(gradleModule, mainModuleData, projectDataNode, resolverCtx)
val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) ?: return
mainModuleData.kotlinAndroidSourceSets = mppModel
.targets
.asSequence()
.flatMap { it.compilations.asSequence() }
.filter { it.isAndroid }
.map { KotlinMPPGradleProjectResolver.createSourceSetInfo(it, gradleModule, resolverCtx) }
.toList()
}
}