Gradle: Implement new MPP model import
This commit is contained in:
committed by
Sergey Igushkin
parent
caec846330
commit
ecf607d4fa
+8
-4
@@ -23,12 +23,14 @@ import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.KVisibility
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Any> copyBean(bean: T) =
|
||||
copyProperties(bean, bean::class.java.newInstance()!!, true, collectProperties(bean::class as KClass<T>, false))
|
||||
fun <T : Any> copyBean(bean: T) = copyBeanTo(bean, bean::class.java.newInstance()!!)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Any> copyBeanTo(from: T, to: T, filter: ((KProperty1<T, Any?>, Any?) -> Boolean)? = null) =
|
||||
copyProperties(from, to, true, collectProperties(from::class as KClass<T>, false), filter)
|
||||
|
||||
fun <From : Any, To : From> mergeBeans(from: From, to: To): To {
|
||||
// TODO: rewrite when updated version of com.intellij.util.xmlb is available on TeamCity
|
||||
@@ -48,7 +50,8 @@ private fun <From : Any, To : Any> copyProperties(
|
||||
from: From,
|
||||
to: To,
|
||||
deepCopyWhenNeeded: Boolean,
|
||||
propertiesToCopy: List<KProperty1<From, Any?>>
|
||||
propertiesToCopy: List<KProperty1<From, Any?>>,
|
||||
filter: ((KProperty1<From, Any?>, Any?) -> Boolean)? = null
|
||||
): To {
|
||||
if (from == to) return to
|
||||
|
||||
@@ -57,6 +60,7 @@ private fun <From : Any, To : Any> copyProperties(
|
||||
val toProperty = to::class.memberProperties.firstOrNull { it.name == fromProperty.name } as? KMutableProperty1<To, Any?>
|
||||
?: continue
|
||||
val fromValue = fromProperty.get(from)
|
||||
if (filter != null && !filter(fromProperty, fromValue)) continue
|
||||
toProperty.set(to, if (deepCopyWhenNeeded) fromValue?.copyValueIfNeeded() else fromValue)
|
||||
}
|
||||
return to
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.fileTypes.FileType
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModulePointerManager
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.FileIndex
|
||||
@@ -145,3 +146,6 @@ val PsiElement.module: Module?
|
||||
get() = ModuleUtilCore.findModuleForPsiElement(this)
|
||||
|
||||
fun VirtualFile.findModule(project: Project) = ModuleUtilCore.findModuleForFile(this, project)
|
||||
|
||||
fun Module.createPointer() =
|
||||
ModulePointerManager.getInstance(project).create(this)
|
||||
+72
@@ -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)
|
||||
}
|
||||
}
|
||||
+70
@@ -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)
|
||||
}
|
||||
}
|
||||
+72
@@ -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)
|
||||
}
|
||||
}
|
||||
+72
@@ -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)
|
||||
}
|
||||
}
|
||||
+72
@@ -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)
|
||||
}
|
||||
}
|
||||
+81
@@ -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()
|
||||
}
|
||||
}
|
||||
+5
@@ -30,6 +30,7 @@ import org.gradle.tooling.model.idea.IdeaModule
|
||||
import org.jetbrains.kotlin.gradle.CompilerArgumentsBySourceSet
|
||||
import org.jetbrains.kotlin.gradle.KotlinGradleModel
|
||||
import org.jetbrains.kotlin.gradle.KotlinGradleModelBuilder
|
||||
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
|
||||
import org.jetbrains.kotlin.idea.inspections.gradle.getDependencyModules
|
||||
import org.jetbrains.kotlin.idea.util.CopyableDataNodeUserDataProperty
|
||||
import org.jetbrains.kotlin.idea.util.NotNullableCopyableDataNodeUserDataProperty
|
||||
@@ -78,6 +79,10 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension()
|
||||
ideModule: DataNode<ModuleData>,
|
||||
ideProject: DataNode<ProjectData>
|
||||
) {
|
||||
if (resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) != null) {
|
||||
return super.populateModuleDependencies(gradleModule, ideModule, ideProject)
|
||||
}
|
||||
|
||||
val outputToSourceSet = ideProject.getUserData(GradleProjectResolver.MODULES_OUTPUTS)
|
||||
val sourceSetByName = ideProject.getUserData(GradleProjectResolver.RESOLVED_SOURCE_SETS)
|
||||
|
||||
|
||||
+3
-2
@@ -200,6 +200,7 @@ fun configureFacetByGradleModule(
|
||||
sourceSetNode: DataNode<GradleSourceSetData>?,
|
||||
sourceSetName: String? = sourceSetNode?.data?.id?.let { it.substring(it.lastIndexOf(':') + 1) }
|
||||
): KotlinFacet? {
|
||||
if (moduleNode.kotlinSourceSet != null) return null // Suppress in the presence of new MPP model
|
||||
if (!moduleNode.isResolved) return null
|
||||
|
||||
if (!moduleNode.hasKotlinPlugin) {
|
||||
@@ -263,7 +264,7 @@ private fun getExplicitOutputPath(moduleNode: DataNode<ModuleData>, platformKind
|
||||
return K2JSCompilerArguments().apply { parseCommandLineArguments(k2jsArgumentList, this) }.outputFile
|
||||
}
|
||||
|
||||
private fun adjustClasspath(kotlinFacet: KotlinFacet, dependencyClasspath: List<String>) {
|
||||
internal fun adjustClasspath(kotlinFacet: KotlinFacet, dependencyClasspath: List<String>) {
|
||||
if (dependencyClasspath.isEmpty()) return
|
||||
val arguments = kotlinFacet.configuration.settings.compilerArguments as? K2JVMCompilerArguments ?: return
|
||||
val fullClasspath = arguments.classpath?.split(File.pathSeparator) ?: emptyList()
|
||||
@@ -274,7 +275,7 @@ private fun adjustClasspath(kotlinFacet: KotlinFacet, dependencyClasspath: List<
|
||||
|
||||
private val gradlePropertyFiles = listOf("local.properties", "gradle.properties")
|
||||
|
||||
private fun findKotlinCoroutinesProperty(project: Project): String {
|
||||
internal fun findKotlinCoroutinesProperty(project: Project): String {
|
||||
for (propertyFileName in gradlePropertyFiles) {
|
||||
val propertyFile = project.baseDir.findChild(propertyFileName) ?: continue
|
||||
val properties = Properties()
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.idea.configuration
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||
import com.intellij.openapi.externalSystem.model.project.AbstractNamedData
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||
import com.intellij.openapi.util.Key
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.gradle.KotlinModule
|
||||
import org.jetbrains.kotlin.gradle.KotlinPlatform
|
||||
import org.jetbrains.kotlin.gradle.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.idea.util.CopyableDataNodeUserDataProperty
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
import java.io.File
|
||||
import com.intellij.openapi.externalSystem.model.Key as ExternalKey
|
||||
|
||||
var DataNode<out ModuleData>.kotlinSourceSet: KotlinSourceSetInfo?
|
||||
by CopyableDataNodeUserDataProperty(Key.create("KOTLIN_SOURCE_SET"))
|
||||
|
||||
var DataNode<out ModuleData>.kotlinTargetDataNode: DataNode<KotlinTargetData>?
|
||||
by CopyableDataNodeUserDataProperty(Key.create("KOTLIN_TARGET_DATA_NODE"))
|
||||
|
||||
class KotlinSourceSetInfo(val kotlinModule: KotlinModule) {
|
||||
var moduleId: String? = null
|
||||
var platform: KotlinPlatform = KotlinPlatform.COMMON
|
||||
var defaultCompilerArguments: CommonCompilerArguments? = null
|
||||
var compilerArguments: CommonCompilerArguments? = null
|
||||
var dependencyClasspath: List<String> = emptyList()
|
||||
var isTestModule: Boolean = false
|
||||
var sourceSetIdsByName: Map<String, String> = emptyMap()
|
||||
}
|
||||
|
||||
class KotlinTargetData(name: String) : AbstractNamedData(GradleConstants.SYSTEM_ID, name) {
|
||||
var moduleIds: Set<String> = emptySet()
|
||||
var archiveFile: File? = null
|
||||
|
||||
companion object {
|
||||
val KEY = ExternalKey.create(KotlinTargetData::class.java, ProjectKeys.MODULE.processingWeight + 1)
|
||||
}
|
||||
}
|
||||
+610
@@ -0,0 +1,610 @@
|
||||
/*
|
||||
* 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.idea.configuration
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||
import com.intellij.openapi.externalSystem.model.project.*
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants
|
||||
import com.intellij.openapi.externalSystem.util.Order
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.util.Pair
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.util.PathUtilRt
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import com.intellij.util.text.VersionComparatorUtil
|
||||
import org.gradle.tooling.model.UnsupportedMethodException
|
||||
import org.gradle.tooling.model.idea.IdeaContentRoot
|
||||
import org.gradle.tooling.model.idea.IdeaModule
|
||||
import org.jetbrains.kotlin.cli.common.arguments.*
|
||||
import org.jetbrains.kotlin.gradle.*
|
||||
import org.jetbrains.plugins.gradle.model.*
|
||||
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
|
||||
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolver
|
||||
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolver.CONFIGURATION_ARTIFACTS
|
||||
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolver.MODULES_OUTPUTS
|
||||
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil.buildDependencies
|
||||
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil.getModuleId
|
||||
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
import java.io.File
|
||||
|
||||
@Order(ExternalSystemConstants.UNORDERED + 1)
|
||||
open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
|
||||
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, resolverCtx)
|
||||
}
|
||||
}
|
||||
|
||||
override fun populateModuleContentRoots(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
|
||||
if (resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) == null) {
|
||||
return super.populateModuleContentRoots(gradleModule, ideModule)
|
||||
}
|
||||
populateContentRoots(gradleModule, ideModule, resolverCtx)
|
||||
}
|
||||
|
||||
override fun populateModuleCompileOutputSettings(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
|
||||
if (resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) == null) {
|
||||
super.populateModuleCompileOutputSettings(gradleModule, ideModule)
|
||||
}
|
||||
|
||||
val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) ?: return
|
||||
val ideaOutDir = File(ideModule.data.linkedExternalProjectPath, "out")
|
||||
val projectDataNode = ideModule.getDataNode(ProjectKeys.PROJECT)!!
|
||||
val moduleOutputsMap = projectDataNode.getUserData(MODULES_OUTPUTS)!!
|
||||
val outputDirs = HashSet<String>()
|
||||
processCompilations(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, compilation ->
|
||||
var gradleOutputMap = dataNode.getUserData(GradleProjectResolver.GRADLE_OUTPUTS)
|
||||
if (gradleOutputMap == null) {
|
||||
gradleOutputMap = MultiMap.create()
|
||||
dataNode.putUserData(GradleProjectResolver.GRADLE_OUTPUTS, gradleOutputMap)
|
||||
}
|
||||
|
||||
val moduleData = dataNode.data
|
||||
|
||||
with(compilation.output) {
|
||||
effectiveClassesDir?.let {
|
||||
moduleData.isInheritProjectCompileOutputPath = false
|
||||
moduleData.setCompileOutputPath(compilation.sourceType, it.absolutePath)
|
||||
for (gradleOutputDir in classesDirs) {
|
||||
recordOutputDir(gradleOutputDir, it, compilation.sourceType, moduleData, moduleOutputsMap, gradleOutputMap)
|
||||
}
|
||||
}
|
||||
resourcesDir?.let {
|
||||
moduleData.setCompileOutputPath(compilation.resourceType, it.absolutePath)
|
||||
recordOutputDir(it, it, compilation.resourceType, moduleData, moduleOutputsMap, gradleOutputMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outputDirs.any { FileUtil.isAncestor(ideaOutDir, File(it), false) }) {
|
||||
excludeOutDir(ideModule, ideaOutDir)
|
||||
}
|
||||
}
|
||||
|
||||
override fun populateModuleDependencies(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>, ideProject: DataNode<ProjectData>) {
|
||||
if (resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) == null) {
|
||||
super.populateModuleDependencies(gradleModule, ideModule, ideProject)
|
||||
}
|
||||
populateModuleDependencies(gradleModule, ideProject, ideModule, resolverCtx)
|
||||
}
|
||||
|
||||
private fun recordOutputDir(
|
||||
gradleOutputDir: File,
|
||||
effectiveOutputDir: File,
|
||||
sourceType: ExternalSystemSourceType,
|
||||
moduleData: GradleSourceSetData,
|
||||
moduleOutputsMap: MutableMap<String, Pair<String, ExternalSystemSourceType>>,
|
||||
gradleOutputMap: MultiMap<ExternalSystemSourceType, String>
|
||||
) {
|
||||
val gradleOutputPath = ExternalSystemApiUtil.toCanonicalPath(gradleOutputDir.absolutePath)
|
||||
gradleOutputMap.putValue(sourceType, gradleOutputPath)
|
||||
if (gradleOutputDir.path != effectiveOutputDir.path) {
|
||||
moduleOutputsMap[gradleOutputPath] = Pair(moduleData.id, sourceType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun excludeOutDir(ideModule: DataNode<ModuleData>, ideaOutDir: File) {
|
||||
val contentRootDataDataNode = ExternalSystemApiUtil.find(ideModule, ProjectKeys.CONTENT_ROOT)
|
||||
|
||||
val excludedContentRootData: ContentRootData
|
||||
if (contentRootDataDataNode == null || !FileUtil.isAncestor(File(contentRootDataDataNode.data.rootPath), ideaOutDir, false)) {
|
||||
excludedContentRootData = ContentRootData(GradleConstants.SYSTEM_ID, ideaOutDir.absolutePath)
|
||||
ideModule.createChild(ProjectKeys.CONTENT_ROOT, excludedContentRootData)
|
||||
} else {
|
||||
excludedContentRootData = contentRootDataDataNode.data
|
||||
}
|
||||
|
||||
excludedContentRootData.storePath(ExternalSystemSourceType.EXCLUDED, ideaOutDir.absolutePath)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun initializeModuleData(
|
||||
gradleModule: IdeaModule,
|
||||
mainModuleNode: DataNode<ModuleData>,
|
||||
projectDataNode: DataNode<ProjectData>,
|
||||
resolverCtx: ProjectResolverContext
|
||||
) {
|
||||
val mainModuleData = mainModuleNode.data
|
||||
val mainModuleConfigPath = mainModuleData.linkedExternalProjectPath
|
||||
val mainModuleFileDirectoryPath = mainModuleData.moduleFileDirectoryPath
|
||||
|
||||
val externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java)
|
||||
val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java)
|
||||
if (mppModel == null || externalProject == null) return
|
||||
|
||||
val jdkName = gradleModule.jdkNameIfAny
|
||||
|
||||
val moduleGroup: Array<String>? = if (!resolverCtx.isUseQualifiedModuleNames) {
|
||||
val gradlePath = gradleModule.gradleProject.path
|
||||
val isRootModule = gradlePath.isEmpty() || gradlePath == ":"
|
||||
if (isRootModule) {
|
||||
arrayOf(mainModuleData.internalName)
|
||||
} else {
|
||||
gradlePath.split(":").drop(1).toTypedArray()
|
||||
}
|
||||
} else null
|
||||
|
||||
val sourceSetMap = projectDataNode.getUserData(GradleProjectResolver.RESOLVED_SOURCE_SETS)!!
|
||||
|
||||
val sourceSetToCompilationData = LinkedHashMap<KotlinSourceSet, MutableSet<GradleSourceSetData>>()
|
||||
for (target in mppModel.targets) {
|
||||
if (target.isAndroid) continue
|
||||
val targetData = KotlinTargetData(target.name).also {
|
||||
it.archiveFile = target.jar?.archiveFile
|
||||
}
|
||||
val targetDataNode = mainModuleNode.createChild<KotlinTargetData>(KotlinTargetData.KEY, targetData)
|
||||
|
||||
val compilationIds = LinkedHashSet<String>()
|
||||
for (compilation in target.compilations) {
|
||||
val moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx)
|
||||
val existingSourceSetDataNode = sourceSetMap[moduleId]?.first
|
||||
if (existingSourceSetDataNode?.kotlinSourceSet != null) continue
|
||||
|
||||
compilationIds += moduleId
|
||||
|
||||
val moduleExternalName = getExternalModuleName(gradleModule, compilation)
|
||||
val moduleInternalName = getInternalModuleName(gradleModule, externalProject, compilation, resolverCtx)
|
||||
|
||||
val compilationData = existingSourceSetDataNode?.data ?: GradleSourceSetData(
|
||||
moduleId, moduleExternalName, moduleInternalName, mainModuleFileDirectoryPath, mainModuleConfigPath
|
||||
).also {
|
||||
it.group = externalProject.group
|
||||
it.version = externalProject.version
|
||||
|
||||
when (compilation.name) {
|
||||
KotlinCompilation.MAIN_COMPILATION_NAME -> {
|
||||
it.publication = ProjectId(externalProject.group, externalProject.name, externalProject.version)
|
||||
}
|
||||
KotlinCompilation.TEST_COMPILATION_NAME -> {
|
||||
it.productionModuleId = getInternalModuleName(
|
||||
gradleModule,
|
||||
externalProject,
|
||||
compilation,
|
||||
resolverCtx,
|
||||
KotlinCompilation.MAIN_COMPILATION_NAME
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
it.ideModuleGroup = moduleGroup
|
||||
it.sdkName = jdkName
|
||||
}
|
||||
|
||||
val kotlinSourceSet = createSourceSetInfo(compilation, gradleModule, resolverCtx)
|
||||
|
||||
if (compilation.platform == KotlinPlatform.JVM) {
|
||||
compilationData.targetCompatibility = (kotlinSourceSet.compilerArguments as? K2JVMCompilerArguments)?.jvmTarget
|
||||
}
|
||||
|
||||
for (sourceSet in compilation.sourceSets) {
|
||||
sourceSetToCompilationData.getOrPut(sourceSet) { LinkedHashSet() } += compilationData
|
||||
}
|
||||
|
||||
val compilationDataNode =
|
||||
(existingSourceSetDataNode ?: mainModuleNode.createChild(GradleSourceSetData.KEY, compilationData)).also {
|
||||
it.kotlinSourceSet = kotlinSourceSet
|
||||
it.kotlinTargetDataNode = targetDataNode
|
||||
}
|
||||
if (existingSourceSetDataNode == null) {
|
||||
sourceSetMap[moduleId] = Pair(compilationDataNode, createExternalSourceSet(compilation, compilationData))
|
||||
}
|
||||
}
|
||||
|
||||
targetData.moduleIds = compilationIds
|
||||
}
|
||||
|
||||
for (sourceSet in mppModel.sourceSets.values) {
|
||||
if (sourceSet.isAndroid) continue
|
||||
val moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
|
||||
val existingSourceSetDataNode = sourceSetMap[moduleId]?.first
|
||||
if (existingSourceSetDataNode?.kotlinSourceSet != null) continue
|
||||
|
||||
val moduleExternalName = getExternalModuleName(gradleModule, sourceSet)
|
||||
val moduleInternalName = getInternalModuleName(gradleModule, externalProject, sourceSet, resolverCtx)
|
||||
|
||||
val sourceSetData = existingSourceSetDataNode?.data ?: GradleSourceSetData(
|
||||
moduleId, moduleExternalName, moduleInternalName, mainModuleFileDirectoryPath, mainModuleConfigPath
|
||||
).also {
|
||||
it.group = externalProject.group
|
||||
it.version = externalProject.version
|
||||
|
||||
val name = sourceSet.name
|
||||
val baseName = name.removeSuffix("Test")
|
||||
if (baseName != name) {
|
||||
it.productionModuleId = getInternalModuleName(
|
||||
gradleModule,
|
||||
externalProject,
|
||||
sourceSet,
|
||||
resolverCtx,
|
||||
baseName + "Main"
|
||||
)
|
||||
}
|
||||
|
||||
it.ideModuleGroup = moduleGroup
|
||||
it.sdkName = jdkName
|
||||
it.targetCompatibility = sourceSetToCompilationData[sourceSet]
|
||||
?.mapNotNull { it.targetCompatibility }
|
||||
?.minWith(VersionComparatorUtil.COMPARATOR)
|
||||
}
|
||||
|
||||
val kotlinSourceSet = createSourceSetInfo(sourceSet, gradleModule, resolverCtx)
|
||||
|
||||
val sourceSetDataNode =
|
||||
(existingSourceSetDataNode ?: mainModuleNode.createChild(GradleSourceSetData.KEY, sourceSetData)).also {
|
||||
it.kotlinSourceSet = kotlinSourceSet
|
||||
}
|
||||
if (existingSourceSetDataNode == null) {
|
||||
sourceSetMap[moduleId] = Pair(sourceSetDataNode, createExternalSourceSet(sourceSet, sourceSetData))
|
||||
}
|
||||
}
|
||||
|
||||
with(projectDataNode.data) {
|
||||
if (mainModuleData.linkedExternalProjectPath == linkedExternalProjectPath) {
|
||||
group = mainModuleData.group
|
||||
version = mainModuleData.version
|
||||
}
|
||||
}
|
||||
|
||||
mainModuleNode.coroutines = mppModel.extraFeatures.coroutinesState
|
||||
}
|
||||
|
||||
fun populateContentRoots(
|
||||
gradleModule: IdeaModule,
|
||||
ideModule: DataNode<ModuleData>,
|
||||
resolverCtx: ProjectResolverContext
|
||||
) {
|
||||
val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) ?: return
|
||||
processSourceSets(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, sourceSet ->
|
||||
createContentRootData(sourceSet.sourceDirs, sourceSet.sourceType, dataNode)
|
||||
createContentRootData(sourceSet.resourceDirs, sourceSet.resourceType, dataNode)
|
||||
}
|
||||
|
||||
for (gradleContentRoot in gradleModule.contentRoots ?: emptySet<IdeaContentRoot?>()) {
|
||||
if (gradleContentRoot == null) continue
|
||||
|
||||
val rootDirectory = gradleContentRoot.rootDirectory ?: continue
|
||||
val ideContentRoot = ContentRootData(GradleConstants.SYSTEM_ID, rootDirectory.absolutePath).also { ideContentRoot ->
|
||||
(gradleContentRoot.excludeDirectories ?: emptySet()).forEach { file ->
|
||||
ideContentRoot.storePath(ExternalSystemSourceType.EXCLUDED, file.absolutePath)
|
||||
}
|
||||
}
|
||||
ideModule.createChild(ProjectKeys.CONTENT_ROOT, ideContentRoot)
|
||||
}
|
||||
}
|
||||
|
||||
fun populateModuleDependencies(
|
||||
gradleModule: IdeaModule,
|
||||
ideProject: DataNode<ProjectData>,
|
||||
ideModule: DataNode<ModuleData>,
|
||||
resolverCtx: ProjectResolverContext
|
||||
) {
|
||||
val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) ?: return
|
||||
val sourceSetMap = ideProject.getUserData(GradleProjectResolver.RESOLVED_SOURCE_SETS) ?: return
|
||||
val artifactsMap = ideProject.getUserData(CONFIGURATION_ARTIFACTS) ?: return
|
||||
val processedModuleIds = HashSet<String>()
|
||||
processCompilations(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, compilation ->
|
||||
if (processedModuleIds.add(getKotlinModuleId(gradleModule, compilation, resolverCtx))) {
|
||||
buildDependencies(
|
||||
resolverCtx,
|
||||
sourceSetMap,
|
||||
artifactsMap,
|
||||
dataNode,
|
||||
preprocessDependencies(compilation, ideProject),
|
||||
ideProject
|
||||
)
|
||||
for (sourceSet in compilation.sourceSets) {
|
||||
if (sourceSet.fullName() == compilation.fullName()) continue
|
||||
addDependency(dataNode, sourceSet, gradleModule, ideModule, resolverCtx)
|
||||
}
|
||||
}
|
||||
}
|
||||
processSourceSets(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, sourceSet ->
|
||||
dataNode.data.productionModuleId?.let {
|
||||
val productionModuleDataNode = ideModule.findChildModuleByInternalName(it)
|
||||
if (productionModuleDataNode != null) {
|
||||
addDependency(dataNode, productionModuleDataNode)
|
||||
}
|
||||
}
|
||||
if (processedModuleIds.add(getKotlinModuleId(gradleModule, sourceSet, resolverCtx))) {
|
||||
buildDependencies(
|
||||
resolverCtx,
|
||||
sourceSetMap,
|
||||
artifactsMap,
|
||||
dataNode,
|
||||
preprocessDependencies(sourceSet, ideProject),
|
||||
ideProject
|
||||
)
|
||||
}
|
||||
for (targetSourceSetName in sourceSet.dependsOnSourceSets) {
|
||||
val targetSourceSet = mppModel.sourceSets[targetSourceSetName] ?: continue
|
||||
addDependency(dataNode, targetSourceSet, gradleModule, ideModule, resolverCtx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun preprocessDependencies(
|
||||
kotlinModule: KotlinModule,
|
||||
ideProject: DataNode<ProjectData>
|
||||
): List<ExternalDependency> {
|
||||
return kotlinModule.dependencies
|
||||
.groupBy { it.id }
|
||||
.mapValues { it.value.firstOrNull { it.scope == "COMPILE" } ?: it.value.lastOrNull() }
|
||||
.values
|
||||
.filterNotNull()
|
||||
.map { adjustDependency(it, ideProject) }
|
||||
}
|
||||
|
||||
private fun adjustDependency(
|
||||
dependency: ExternalDependency,
|
||||
ideProject: DataNode<ProjectData>
|
||||
): ExternalDependency {
|
||||
if (dependency !is ExternalProjectDependency) return dependency
|
||||
val projectPath = dependency.projectPath
|
||||
val classifier = dependency.classifier ?: return dependency
|
||||
val targetModuleNode = ExternalSystemApiUtil.findFirstRecursively(ideProject) {
|
||||
(it.data as? ModuleData)?.id == projectPath
|
||||
} ?: return dependency
|
||||
val targetCompilation = ExternalSystemApiUtil
|
||||
.getChildren(targetModuleNode, GradleSourceSetData.KEY)
|
||||
.mapNotNull { sourceSetNode ->
|
||||
sourceSetNode.kotlinSourceSet?.kotlinModule as? KotlinCompilation
|
||||
}
|
||||
.firstOrNull {
|
||||
it.name == KotlinCompilation.MAIN_COMPILATION_NAME && it.target.disambiguationClassifier == classifier
|
||||
} ?: return dependency
|
||||
return DefaultExternalProjectDependency(dependency).also {
|
||||
it.configurationName = targetCompilation.fullName()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addDependency(fromModule: DataNode<*>, toModule: DataNode<*>) {
|
||||
val fromData = fromModule.data as? ModuleData ?: return
|
||||
val toData = toModule.data as? ModuleData ?: return
|
||||
val moduleDependencyData = ModuleDependencyData(fromData, toData).also {
|
||||
it.scope = DependencyScope.COMPILE
|
||||
it.isExported = false
|
||||
}
|
||||
fromModule.createChild(ProjectKeys.MODULE_DEPENDENCY, moduleDependencyData)
|
||||
}
|
||||
|
||||
private fun addDependency(
|
||||
fromModule: DataNode<*>,
|
||||
toModule: KotlinModule,
|
||||
gradleModule: IdeaModule,
|
||||
ideModule: DataNode<ModuleData>,
|
||||
resolverCtx: ProjectResolverContext
|
||||
) {
|
||||
val usedModuleId = getKotlinModuleId(gradleModule, toModule, resolverCtx)
|
||||
val usedModuleDataNode = ideModule.findChildModuleById(usedModuleId) ?: return
|
||||
addDependency(fromModule, usedModuleDataNode)
|
||||
}
|
||||
|
||||
private fun createContentRootData(sourceDirs: Set<File>, sourceType: ExternalSystemSourceType, parentNode: DataNode<*>) {
|
||||
for (sourceDir in sourceDirs) {
|
||||
val contentRootData = ContentRootData(GradleConstants.SYSTEM_ID, sourceDir.absolutePath)
|
||||
contentRootData.storePath(sourceType, sourceDir.absolutePath)
|
||||
parentNode.createChild(ProjectKeys.CONTENT_ROOT, contentRootData)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processSourceSets(
|
||||
gradleModule: IdeaModule,
|
||||
mppModel: KotlinMPPGradleModel,
|
||||
ideModule: DataNode<ModuleData>,
|
||||
resolverCtx: ProjectResolverContext,
|
||||
processor: (DataNode<GradleSourceSetData>, KotlinSourceSet) -> Unit
|
||||
) {
|
||||
val sourceSetsMap = HashMap<String, DataNode<GradleSourceSetData>>()
|
||||
for (dataNode in ExternalSystemApiUtil.findAll(ideModule, GradleSourceSetData.KEY)) {
|
||||
if (dataNode.kotlinSourceSet != null) {
|
||||
sourceSetsMap[dataNode.data.id] = dataNode
|
||||
}
|
||||
}
|
||||
for (sourceSet in mppModel.sourceSets.values) {
|
||||
if (sourceSet.isAndroid) continue
|
||||
val moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
|
||||
val moduleDataNode = sourceSetsMap[moduleId] ?: continue
|
||||
processor(moduleDataNode, sourceSet)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processCompilations(
|
||||
gradleModule: IdeaModule,
|
||||
mppModel: KotlinMPPGradleModel,
|
||||
ideModule: DataNode<ModuleData>,
|
||||
resolverCtx: ProjectResolverContext,
|
||||
processor: (DataNode<GradleSourceSetData>, KotlinCompilation) -> Unit
|
||||
) {
|
||||
val sourceSetsMap = HashMap<String, DataNode<GradleSourceSetData>>()
|
||||
for (dataNode in ExternalSystemApiUtil.findAll(ideModule, GradleSourceSetData.KEY)) {
|
||||
if (dataNode.kotlinSourceSet != null) {
|
||||
sourceSetsMap[dataNode.data.id] = dataNode
|
||||
}
|
||||
}
|
||||
for (target in mppModel.targets) {
|
||||
if (target.isAndroid) continue
|
||||
for (compilation in target.compilations) {
|
||||
val moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx)
|
||||
val moduleDataNode = sourceSetsMap[moduleId] ?: continue
|
||||
processor(moduleDataNode, compilation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val IdeaModule.jdkNameIfAny
|
||||
get() = try {
|
||||
jdkName
|
||||
} catch (e: UnsupportedMethodException) {
|
||||
null
|
||||
}
|
||||
|
||||
private fun getExternalModuleName(gradleModule: IdeaModule, kotlinModule: KotlinModule) =
|
||||
gradleModule.name + ":" + kotlinModule.fullName()
|
||||
|
||||
private fun getInternalModuleName(
|
||||
gradleModule: IdeaModule,
|
||||
externalProject: ExternalProject,
|
||||
kotlinModule: KotlinModule,
|
||||
resolverCtx: ProjectResolverContext,
|
||||
actualName: String = kotlinModule.name
|
||||
): String {
|
||||
val delimiter: String
|
||||
val moduleName = StringBuilder()
|
||||
if (resolverCtx.isUseQualifiedModuleNames) {
|
||||
delimiter = "."
|
||||
if (StringUtil.isNotEmpty(externalProject.group)) {
|
||||
moduleName.append(externalProject.group).append(delimiter)
|
||||
}
|
||||
moduleName.append(externalProject.name)
|
||||
} else {
|
||||
delimiter = "_"
|
||||
moduleName.append(gradleModule.name)
|
||||
}
|
||||
moduleName.append(delimiter)
|
||||
moduleName.append(kotlinModule.fullName(actualName))
|
||||
return PathUtilRt.suggestFileName(moduleName.toString(), true, false)
|
||||
}
|
||||
|
||||
private fun createExternalSourceSet(compilation: KotlinCompilation, compilationData: GradleSourceSetData): ExternalSourceSet {
|
||||
return DefaultExternalSourceSet().also { sourceSet ->
|
||||
val effectiveClassesDir = compilation.output.effectiveClassesDir
|
||||
val resourcesDir = compilation.output.resourcesDir
|
||||
|
||||
sourceSet.name = compilation.fullName()
|
||||
sourceSet.targetCompatibility = compilationData.targetCompatibility
|
||||
sourceSet.dependencies += compilation.dependencies
|
||||
val sourcesWithTypes = SmartList<kotlin.Pair<IExternalSystemSourceType, ExternalSourceDirectorySet>>()
|
||||
if (effectiveClassesDir != null) {
|
||||
sourcesWithTypes += compilation.sourceType to DefaultExternalSourceDirectorySet().also { dirSet ->
|
||||
dirSet.outputDir = effectiveClassesDir
|
||||
dirSet.srcDirs = compilation.sourceSets.flatMapTo(LinkedHashSet()) { it.sourceDirs }
|
||||
dirSet.gradleOutputDirs += compilation.output.classesDirs
|
||||
dirSet.setInheritedCompilerOutput(false)
|
||||
}
|
||||
}
|
||||
if (resourcesDir != null) {
|
||||
sourcesWithTypes += compilation.resourceType to DefaultExternalSourceDirectorySet().also { dirSet ->
|
||||
dirSet.outputDir = resourcesDir
|
||||
dirSet.srcDirs = compilation.sourceSets.flatMapTo(LinkedHashSet()) { it.resourceDirs }
|
||||
dirSet.gradleOutputDirs += resourcesDir
|
||||
dirSet.setInheritedCompilerOutput(false)
|
||||
}
|
||||
}
|
||||
sourceSet.sources = sourcesWithTypes.toMap()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createExternalSourceSet(ktSourceSet: KotlinSourceSet, ktSourceSetData: GradleSourceSetData): ExternalSourceSet {
|
||||
return DefaultExternalSourceSet().also { sourceSet ->
|
||||
sourceSet.name = ktSourceSet.name
|
||||
sourceSet.targetCompatibility = ktSourceSetData.targetCompatibility
|
||||
sourceSet.dependencies += ktSourceSet.dependencies
|
||||
sourceSet.sources = linkedMapOf<IExternalSystemSourceType, ExternalSourceDirectorySet>(
|
||||
ktSourceSet.sourceType to DefaultExternalSourceDirectorySet().also { dirSet ->
|
||||
dirSet.srcDirs = ktSourceSet.sourceDirs
|
||||
},
|
||||
ktSourceSet.resourceType to DefaultExternalSourceDirectorySet().also { dirSet ->
|
||||
dirSet.srcDirs = ktSourceSet.resourceDirs
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val KotlinModule.sourceType
|
||||
get() = if (isTestModule) ExternalSystemSourceType.TEST else ExternalSystemSourceType.SOURCE
|
||||
|
||||
private val KotlinModule.resourceType
|
||||
get() = if (isTestModule) ExternalSystemSourceType.TEST_RESOURCE else ExternalSystemSourceType.RESOURCE
|
||||
|
||||
private fun createSourceSetInfo(
|
||||
sourceSet: KotlinSourceSet,
|
||||
gradleModule: IdeaModule,
|
||||
resolverCtx: ProjectResolverContext
|
||||
): KotlinSourceSetInfo {
|
||||
return KotlinSourceSetInfo(sourceSet).also {
|
||||
it.moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
|
||||
it.platform = sourceSet.platform
|
||||
it.isTestModule = sourceSet.isTestModule
|
||||
it.compilerArguments = createCompilerArguments(emptyList(), sourceSet.platform).also {
|
||||
it.multiPlatform = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createSourceSetInfo(
|
||||
compilation: KotlinCompilation,
|
||||
gradleModule: IdeaModule,
|
||||
resolverCtx: ProjectResolverContext
|
||||
): KotlinSourceSetInfo {
|
||||
return KotlinSourceSetInfo(compilation).also {
|
||||
it.moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx)
|
||||
it.platform = compilation.platform
|
||||
it.isTestModule = compilation.isTestModule
|
||||
it.compilerArguments = createCompilerArguments(compilation.arguments.currentArguments, compilation.platform).also {
|
||||
it.multiPlatform = true
|
||||
}
|
||||
it.dependencyClasspath = compilation.dependencyClasspath
|
||||
it.defaultCompilerArguments = createCompilerArguments(compilation.arguments.defaultArguments, compilation.platform)
|
||||
it.sourceSetIdsByName = compilation.sourceSets
|
||||
.asSequence()
|
||||
.filter { it.fullName() != compilation.fullName() }
|
||||
.map { it.name to getKotlinModuleId(gradleModule, it, resolverCtx) }
|
||||
.toMap()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCompilerArguments(args: List<String>, platform: KotlinPlatform): CommonCompilerArguments {
|
||||
return when (platform) {
|
||||
KotlinPlatform.COMMON -> K2MetadataCompilerArguments()
|
||||
KotlinPlatform.JVM -> K2JVMCompilerArguments()
|
||||
KotlinPlatform.JS -> K2JSCompilerArguments()
|
||||
}.also {
|
||||
parseCommandLineArguments(args, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinModule.fullName(simpleName: String = name) = when (this) {
|
||||
is KotlinCompilation -> target.disambiguationClassifier?.let { it + simpleName.capitalize() } ?: simpleName
|
||||
else -> simpleName
|
||||
}
|
||||
|
||||
private fun getKotlinModuleId(gradleModule: IdeaModule, kotlinModule: KotlinModule, resolverCtx: ProjectResolverContext) =
|
||||
getModuleId(resolverCtx, gradleModule) + ":" + kotlinModule.fullName()
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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.idea.configuration
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||
import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType
|
||||
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.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.LibraryOrderEntry
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.openapi.roots.impl.libraries.LibraryEx
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||
import org.jetbrains.kotlin.config.CoroutineSupport
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.config.KotlinModuleKind
|
||||
import org.jetbrains.kotlin.config.TargetPlatformKind
|
||||
import org.jetbrains.kotlin.gradle.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.KotlinModule
|
||||
import org.jetbrains.kotlin.gradle.KotlinPlatform
|
||||
import org.jetbrains.kotlin.gradle.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.idea.facet.applyCompilerArgumentsToFacet
|
||||
import org.jetbrains.kotlin.idea.facet.configureFacet
|
||||
import org.jetbrains.kotlin.idea.facet.getOrCreateFacet
|
||||
import org.jetbrains.kotlin.idea.facet.noVersionAutoAdvance
|
||||
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
|
||||
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
|
||||
import org.jetbrains.kotlin.idea.framework.effectiveKind
|
||||
import org.jetbrains.kotlin.idea.inspections.gradle.findAll
|
||||
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
|
||||
import org.jetbrains.kotlin.idea.roots.migrateNonJvmSourceFolders
|
||||
import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData
|
||||
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||
|
||||
class KotlinSourceSetDataService : AbstractProjectDataService<GradleSourceSetData, Void>() {
|
||||
override fun getTargetDataKey() = GradleSourceSetData.KEY
|
||||
|
||||
override fun postProcess(
|
||||
toImport: MutableCollection<DataNode<GradleSourceSetData>>,
|
||||
projectData: ProjectData?,
|
||||
project: Project,
|
||||
modelsProvider: IdeModifiableModelsProvider
|
||||
) {
|
||||
for (nodeToImport in toImport) {
|
||||
val mainModuleData = ExternalSystemApiUtil.findParent(
|
||||
nodeToImport,
|
||||
ProjectKeys.MODULE
|
||||
) ?: continue
|
||||
val sourceSetData = nodeToImport.data
|
||||
val kotlinSourceSet = nodeToImport.kotlinSourceSet ?: continue
|
||||
val ideModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
|
||||
val platform = kotlinSourceSet.platform
|
||||
val rootModel = modelsProvider.getModifiableRootModel(ideModule)
|
||||
|
||||
dropWrongLibraries(rootModel, platform, project)
|
||||
|
||||
if (platform != KotlinPlatform.JVM) {
|
||||
migrateNonJvmSourceFolders(rootModel)
|
||||
}
|
||||
|
||||
configureFacet(sourceSetData, kotlinSourceSet, mainModuleData, ideModule, modelsProvider)
|
||||
}
|
||||
}
|
||||
|
||||
private val KotlinModule.kind
|
||||
get() = when (this) {
|
||||
is KotlinCompilation -> KotlinModuleKind.COMPILATION_AND_SOURCE_SET_HOLDER
|
||||
is KotlinSourceSet -> KotlinModuleKind.SOURCE_SET_HOLDER
|
||||
else -> KotlinModuleKind.DEFAULT
|
||||
}
|
||||
|
||||
private fun configureFacet(
|
||||
sourceSetData: GradleSourceSetData,
|
||||
kotlinSourceSet: KotlinSourceSetInfo,
|
||||
mainModuleNode: DataNode<ModuleData>,
|
||||
ideModule: Module,
|
||||
modelsProvider: IdeModifiableModelsProvider
|
||||
) {
|
||||
val compilerVersion = mainModuleNode
|
||||
.findAll(BuildScriptClasspathData.KEY)
|
||||
.firstOrNull()
|
||||
?.data
|
||||
?.let { findKotlinPluginVersion(it) } ?: return
|
||||
val platformKind = when (kotlinSourceSet.platform) {
|
||||
KotlinPlatform.JVM -> TargetPlatformKind.Jvm[JvmTarget.fromString(
|
||||
sourceSetData.targetCompatibility ?: ""
|
||||
) ?: JvmTarget.DEFAULT]
|
||||
KotlinPlatform.JS -> TargetPlatformKind.JavaScript
|
||||
KotlinPlatform.COMMON -> TargetPlatformKind.Common
|
||||
}
|
||||
val coroutinesProperty = CoroutineSupport.byCompilerArgument(
|
||||
mainModuleNode.coroutines ?: findKotlinCoroutinesProperty(ideModule.project)
|
||||
)
|
||||
|
||||
val kotlinFacet = ideModule.getOrCreateFacet(modelsProvider, false)
|
||||
kotlinFacet.configureFacet(compilerVersion, coroutinesProperty, platformKind, modelsProvider)
|
||||
|
||||
val compilerArguments = kotlinSourceSet.compilerArguments
|
||||
val defaultCompilerArguments = kotlinSourceSet.defaultCompilerArguments
|
||||
if (compilerArguments != null) {
|
||||
applyCompilerArgumentsToFacet(
|
||||
compilerArguments,
|
||||
defaultCompilerArguments,
|
||||
kotlinFacet,
|
||||
modelsProvider
|
||||
)
|
||||
}
|
||||
|
||||
adjustClasspath(kotlinFacet, kotlinSourceSet.dependencyClasspath)
|
||||
|
||||
kotlinFacet.noVersionAutoAdvance()
|
||||
|
||||
with(kotlinFacet.configuration.settings) {
|
||||
kind = kotlinSourceSet.kotlinModule.kind
|
||||
|
||||
sourceSetNames = kotlinSourceSet.sourceSetIdsByName.values.mapNotNull { sourceSetId ->
|
||||
val node = mainModuleNode.findChildModuleById(sourceSetId) ?: return@mapNotNull null
|
||||
val data = node.data as? ModuleData ?: return@mapNotNull null
|
||||
modelsProvider.findIdeModule(data)?.name
|
||||
}
|
||||
|
||||
if (kotlinSourceSet.isTestModule) {
|
||||
testOutputPath = (kotlinSourceSet.compilerArguments as? K2JSCompilerArguments)?.outputFile
|
||||
productionOutputPath = null
|
||||
} else {
|
||||
productionOutputPath = (kotlinSourceSet.compilerArguments as? K2JSCompilerArguments)?.outputFile
|
||||
testOutputPath = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun dropWrongLibraries(
|
||||
rootModel: ModifiableRootModel,
|
||||
platform: KotlinPlatform,
|
||||
project: Project
|
||||
) {
|
||||
rootModel.orderEntries().librariesOnly().forEach { orderEntry ->
|
||||
val library = (orderEntry as? LibraryOrderEntry)?.library
|
||||
if (library != null && !library.matchesPlatform(platform, project)) {
|
||||
rootModel.removeOrderEntry(orderEntry)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun Library.matchesPlatform(platform: KotlinPlatform, project: Project): Boolean {
|
||||
val kind = (this as? LibraryEx)?.effectiveKind(project)
|
||||
return when (kind) {
|
||||
CommonLibraryKind -> true
|
||||
JSLibraryKind -> platform == KotlinPlatform.JS
|
||||
else -> platform == KotlinPlatform.JVM
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.idea.configuration
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
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.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.packaging.impl.artifacts.JarArtifactType
|
||||
import com.intellij.packaging.impl.elements.ProductionModuleOutputPackagingElement
|
||||
import org.jetbrains.kotlin.idea.util.createPointer
|
||||
|
||||
class KotlinTargetDataService : AbstractProjectDataService<KotlinTargetData, Void>() {
|
||||
override fun getTargetDataKey() = KotlinTargetData.KEY
|
||||
|
||||
override fun importData(
|
||||
toImport: MutableCollection<DataNode<KotlinTargetData>>,
|
||||
projectData: ProjectData?,
|
||||
project: Project,
|
||||
modelsProvider: IdeModifiableModelsProvider
|
||||
) {
|
||||
for (nodeToImport in toImport) {
|
||||
val targetData = nodeToImport.data
|
||||
val archiveFile = targetData.archiveFile ?: continue
|
||||
val artifactModel = modelsProvider.modifiableArtifactModel
|
||||
val artifactName = FileUtil.getNameWithoutExtension(archiveFile)
|
||||
artifactModel.findArtifact(artifactName)?.let { artifactModel.removeArtifact(it) }
|
||||
artifactModel.addArtifact(artifactName, JarArtifactType.getInstance()).also {
|
||||
it.outputPath = archiveFile.parent
|
||||
for (moduleId in targetData.moduleIds) {
|
||||
val compilationModuleDataNode = nodeToImport.parent?.findChildModuleById(moduleId) ?: continue
|
||||
val compilationData = compilationModuleDataNode.data ?: continue
|
||||
val kotlinSourceSet = compilationModuleDataNode.kotlinSourceSet ?: continue
|
||||
if (kotlinSourceSet.isTestModule) continue
|
||||
val moduleToPackage = modelsProvider.findIdeModule(compilationData) ?: continue
|
||||
it.rootElement.addOrFindChild(ProductionModuleOutputPackagingElement(project, moduleToPackage.createPointer()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.idea.configuration
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun DataNode<*>.findChildModuleById(id: String) =
|
||||
children.firstOrNull { (it.data as? ModuleData)?.id == id } as? DataNode<out ModuleData>
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun DataNode<*>.findChildModuleByInternalName(name: String) =
|
||||
children.firstOrNull { (it.data as? ModuleData)?.internalName == name }
|
||||
@@ -112,6 +112,12 @@ var CommonCompilerArguments.apiVersionView: VersionView
|
||||
autoAdvanceApiVersion = value == VersionView.LatestStable
|
||||
}
|
||||
|
||||
enum class KotlinModuleKind {
|
||||
DEFAULT,
|
||||
SOURCE_SET_HOLDER,
|
||||
COMPILATION_AND_SOURCE_SET_HOLDER
|
||||
}
|
||||
|
||||
class KotlinFacetSettings {
|
||||
companion object {
|
||||
// Increment this when making serialization-incompatible changes to configuration data
|
||||
@@ -196,6 +202,9 @@ class KotlinFacetSettings {
|
||||
|
||||
var productionOutputPath: String? = null
|
||||
var testOutputPath: String? = null
|
||||
|
||||
var kind: KotlinModuleKind = KotlinModuleKind.DEFAULT
|
||||
var sourceSetNames: List<String> = emptyList()
|
||||
}
|
||||
|
||||
fun TargetPlatformKind<*>.createCompilerArguments(init: CommonCompilerArguments.() -> Unit = {}): CommonCompilerArguments {
|
||||
|
||||
@@ -111,6 +111,20 @@ private fun readV2AndLaterConfig(element: Element): KotlinFacetSettings {
|
||||
listOfNotNull((it.content.firstOrNull() as? Text)?.textTrim)
|
||||
}
|
||||
}
|
||||
element.getChild("sourceSets")?.let {
|
||||
val items = it.getChildren("sourceSet")
|
||||
sourceSetNames = items.mapNotNull { (it.content.firstOrNull() as? Text)?.textTrim }
|
||||
}
|
||||
kind = element.getChild("newMppModelJpsModuleKind")?.let {
|
||||
val kindName = (it.content.firstOrNull() as? Text)?.textTrim
|
||||
if (kindName != null) {
|
||||
try {
|
||||
KotlinModuleKind.valueOf(kindName)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
} else null
|
||||
} ?: KotlinModuleKind.DEFAULT
|
||||
element.getChild("compilerSettings")?.let {
|
||||
compilerSettings = CompilerSettings()
|
||||
XmlSerializer.deserializeInto(compilerSettings!!, it)
|
||||
@@ -259,6 +273,16 @@ private fun KotlinFacetSettings.writeLatestConfig(element: Element) {
|
||||
}
|
||||
)
|
||||
}
|
||||
if (sourceSetNames.isNotEmpty()) {
|
||||
element.addContent(
|
||||
Element("sourceSets").apply {
|
||||
sourceSetNames.map { addContent(Element("sourceSet").apply { addContent(it) }) }
|
||||
}
|
||||
)
|
||||
}
|
||||
if (kind != KotlinModuleKind.DEFAULT) {
|
||||
element.addContent(Element("newMppModelJpsModuleKind").apply { addContent(kind.name) })
|
||||
}
|
||||
productionOutputPath?.let {
|
||||
if (it != (compilerArguments as? K2JSCompilerArguments)?.outputFile) {
|
||||
element.addContent(Element("productionOutputPath").apply { addContent(PathUtil.toSystemIndependentName(it)) })
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.gradle
|
||||
|
||||
import org.jetbrains.plugins.gradle.model.ExternalDependency
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
|
||||
typealias KotlinDependency = ExternalDependency
|
||||
|
||||
interface KotlinModule : Serializable {
|
||||
val isAndroid: Boolean
|
||||
val name: String
|
||||
val platform: KotlinPlatform
|
||||
val dependencies: Set<KotlinDependency>
|
||||
val isTestModule: Boolean
|
||||
}
|
||||
|
||||
interface KotlinSourceSet : KotlinModule {
|
||||
val sourceDirs: Set<File>
|
||||
val resourceDirs: Set<File>
|
||||
val dependsOnSourceSets: Set<String>
|
||||
}
|
||||
|
||||
interface KotlinCompilationOutput : Serializable {
|
||||
val classesDirs: Set<File>
|
||||
val effectiveClassesDir: File?
|
||||
val resourcesDir: File?
|
||||
}
|
||||
|
||||
interface KotlinCompilationArguments : Serializable {
|
||||
val defaultArguments: List<String>
|
||||
val currentArguments: List<String>
|
||||
}
|
||||
|
||||
interface KotlinCompilation : KotlinModule {
|
||||
val sourceSets: Collection<KotlinSourceSet>
|
||||
val target: KotlinTarget
|
||||
val output: KotlinCompilationOutput
|
||||
val arguments: KotlinCompilationArguments
|
||||
val dependencyClasspath: List<String>
|
||||
|
||||
companion object {
|
||||
const val MAIN_COMPILATION_NAME = "main"
|
||||
const val TEST_COMPILATION_NAME = "test"
|
||||
}
|
||||
}
|
||||
|
||||
enum class KotlinPlatform(val id: String) {
|
||||
COMMON("common"),
|
||||
JVM("jvm"),
|
||||
JS("js");
|
||||
|
||||
companion object {
|
||||
fun byId(id: String) = values().firstOrNull { it.id == id }
|
||||
}
|
||||
}
|
||||
|
||||
interface KotlinTargetJar : Serializable {
|
||||
val archiveFile: File?
|
||||
}
|
||||
|
||||
interface KotlinTarget : Serializable {
|
||||
val isAndroid: Boolean
|
||||
val name: String
|
||||
val disambiguationClassifier: String?
|
||||
val platform: KotlinPlatform
|
||||
val compilations: Collection<KotlinCompilation>
|
||||
val jar: KotlinTargetJar?
|
||||
}
|
||||
|
||||
interface ExtraFeatures : Serializable {
|
||||
val coroutinesState: String?
|
||||
}
|
||||
|
||||
interface KotlinMPPGradleModel : Serializable {
|
||||
val sourceSets: Map<String, KotlinSourceSet>
|
||||
val targets: Collection<KotlinTarget>
|
||||
val extraFeatures: ExtraFeatures
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* 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.gradle
|
||||
|
||||
import org.gradle.api.Named
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.SourceDirectorySet
|
||||
import org.jetbrains.plugins.gradle.model.AbstractExternalDependency
|
||||
import org.jetbrains.plugins.gradle.model.DefaultExternalProjectDependency
|
||||
import org.jetbrains.plugins.gradle.model.ExternalDependency
|
||||
import org.jetbrains.plugins.gradle.model.ExternalProjectDependency
|
||||
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
|
||||
import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
|
||||
import org.jetbrains.plugins.gradle.tooling.util.DependencyResolver
|
||||
import org.jetbrains.plugins.gradle.tooling.util.resolve.DependencyResolverImpl
|
||||
import org.jetbrains.plugins.gradle.tooling.util.SourceSetCachedFinder
|
||||
import java.io.File
|
||||
import java.lang.Exception
|
||||
|
||||
class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
|
||||
return ErrorMessageBuilder
|
||||
.create(project, e, "Gradle import errors")
|
||||
.withDescription("Unable to build Kotlin project configuration")
|
||||
}
|
||||
|
||||
override fun canBuild(modelName: String?): Boolean {
|
||||
return modelName == KotlinMPPGradleModel::class.java.name
|
||||
}
|
||||
|
||||
override fun buildAll(modelName: String, project: Project): Any? {
|
||||
val dependencyResolver = DependencyResolverImpl(
|
||||
project,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
SourceSetCachedFinder(project)
|
||||
)
|
||||
val sourceSets = buildSourceSets(project) ?: return null
|
||||
val sourceSetMap = sourceSets.map { it.name to it }.toMap()
|
||||
val targets = buildTargets(sourceSetMap, dependencyResolver, project) ?: return null
|
||||
computeSourceSetsDeferredInfo(sourceSets, targets)
|
||||
val coroutinesState = getCoroutinesState(project)
|
||||
return KotlinMPPGradleModelImpl(sourceSetMap, targets, ExtraFeaturesImpl(coroutinesState))
|
||||
}
|
||||
|
||||
private fun getCoroutinesState(project: Project): String? {
|
||||
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
|
||||
val getExperimental = kotlinExt.javaClass.getMethodOrNull("getExperimental") ?: return null
|
||||
val experimentalExt = getExperimental(kotlinExt) ?: return null
|
||||
val getCoroutines = experimentalExt.javaClass.getMethodOrNull("getCoroutines") ?: return null
|
||||
return getCoroutines(experimentalExt) as? String
|
||||
}
|
||||
|
||||
private fun buildSourceSets(project: Project): Collection<KotlinSourceSetImpl>? {
|
||||
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
|
||||
val getSourceSets = kotlinExt.javaClass.getMethodOrNull("getSourceSets") ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val sourceSets =
|
||||
(getSourceSets(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
|
||||
return sourceSets.mapNotNull { buildSourceSet(it) }
|
||||
}
|
||||
|
||||
private fun buildSourceSet(gradleSourceSet: Named): KotlinSourceSetImpl? {
|
||||
val sourceSetClass = gradleSourceSet.javaClass
|
||||
val getSourceDirSet = sourceSetClass.getMethodOrNull("getKotlin") ?: return null
|
||||
val getResourceDirSet = sourceSetClass.getMethodOrNull("getResources") ?: return null
|
||||
val getDependsOn = sourceSetClass.getMethodOrNull("getDependsOn") ?: return null
|
||||
val sourceDirs = (getSourceDirSet(gradleSourceSet) as? SourceDirectorySet)?.srcDirs ?: emptySet()
|
||||
val resourceDirs = (getResourceDirSet(gradleSourceSet) as? SourceDirectorySet)?.srcDirs ?: emptySet()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val dependsOnSourceSets = (getDependsOn(gradleSourceSet) as? Set<Named>)?.mapTo(LinkedHashSet()) { it.name } ?: emptySet<String>()
|
||||
return KotlinSourceSetImpl(gradleSourceSet.name, sourceDirs, resourceDirs, dependsOnSourceSets)
|
||||
}
|
||||
|
||||
private fun buildDependencies(
|
||||
gradleCompilation: Any,
|
||||
dependencyResolver: DependencyResolver,
|
||||
configurationNameAccessor: String,
|
||||
scope: String,
|
||||
project: Project
|
||||
): Collection<KotlinDependency> {
|
||||
val gradleCompilationClass = gradleCompilation.javaClass
|
||||
val getConfigurationName = gradleCompilationClass.getMethodOrNull(configurationNameAccessor) ?: return emptyList()
|
||||
val configurationName = getConfigurationName(gradleCompilation) as? String ?: return emptyList()
|
||||
val configuration = project.configurations.findByName(configurationName) ?: return emptyList()
|
||||
if (!configuration.isCanBeResolved) return emptyList()
|
||||
val artifactsByProjectPath = configuration
|
||||
.resolvedConfiguration
|
||||
.lenientConfiguration
|
||||
.firstLevelModuleDependencies
|
||||
.flatMap { it.moduleArtifacts }
|
||||
.filter { it.id.componentIdentifier is ProjectComponentIdentifier }
|
||||
.groupBy { (it.id.componentIdentifier as ProjectComponentIdentifier).projectPath }
|
||||
return dependencyResolver.resolveDependencies(configuration)
|
||||
.apply {
|
||||
forEach<ExternalDependency?> { (it as? AbstractExternalDependency)?.scope = scope }
|
||||
}
|
||||
.map {
|
||||
if (it !is ExternalProjectDependency || it.configurationName != Dependency.DEFAULT_CONFIGURATION) return@map it
|
||||
val artifacts = artifactsByProjectPath[it.projectPath] ?: return@map it
|
||||
val classifier = artifacts.mapTo(LinkedHashSet()) { it.classifier }.singleOrNull() ?: return@map it
|
||||
DefaultExternalProjectDependency(it).apply {
|
||||
this.classifier = classifier
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildTargets(
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project
|
||||
): Collection<KotlinTarget>? {
|
||||
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
|
||||
val getTargets = kotlinExt.javaClass.getMethodOrNull("getTargets") ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val targets = (getTargets.invoke(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
|
||||
return targets.mapNotNull { buildTarget(it, sourceSetMap, dependencyResolver, project) }
|
||||
}
|
||||
|
||||
private fun buildTarget(
|
||||
gradleTarget: Named,
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project
|
||||
): KotlinTarget? {
|
||||
val targetClass = gradleTarget.javaClass
|
||||
val getPlatformType = targetClass.getMethodOrNull("getPlatformType") ?: return null
|
||||
val getCompilations = targetClass.getMethodOrNull("getCompilations") ?: return null
|
||||
val getDisambiguationClassifier = targetClass.getMethodOrNull("getDisambiguationClassifier") ?: return null
|
||||
val platformId = (getPlatformType.invoke(gradleTarget) as? Named)?.name ?: return null
|
||||
val platform = KotlinPlatform.byId(platformId) ?: return null
|
||||
val disambiguationClassifier = getDisambiguationClassifier(gradleTarget) as? String
|
||||
val isAndroid = targetClass.name == KOTLIN_ANDROID_TARGET_CLASS_NAME
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val gradleCompilations =
|
||||
(getCompilations.invoke(gradleTarget) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
|
||||
val compilations = gradleCompilations.mapNotNull { buildCompilation(it, sourceSetMap, dependencyResolver, isAndroid, project) }
|
||||
val jar = buildTargetJar(gradleTarget, project)
|
||||
val target = KotlinTargetImpl(isAndroid, gradleTarget.name, disambiguationClassifier, platform, compilations, jar)
|
||||
compilations.forEach { it.target = target }
|
||||
return target
|
||||
}
|
||||
|
||||
private fun buildTargetJar(gradleTarget: Named, project: Project): KotlinTargetJar? {
|
||||
val targetClass = gradleTarget.javaClass
|
||||
val getArtifactsTaskName = targetClass.getMethodOrNull("getArtifactsTaskName") ?: return null
|
||||
val artifactsTaskName = getArtifactsTaskName(gradleTarget) as? String ?: return null
|
||||
val jarTask = project.tasks.findByName(artifactsTaskName) ?: return null
|
||||
val jarTaskClass = jarTask.javaClass
|
||||
val getArchivePath = jarTaskClass.getMethodOrNull("getArchivePath")
|
||||
val archiveFile = getArchivePath?.invoke(jarTask) as? File?
|
||||
return KotlinTargetJarImpl(archiveFile)
|
||||
}
|
||||
|
||||
private fun buildCompilation(
|
||||
gradleCompilation: Named,
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
dependencyResolver: DependencyResolver,
|
||||
isAndroid: Boolean,
|
||||
project: Project
|
||||
): KotlinCompilationImpl? {
|
||||
val compilationClass = gradleCompilation.javaClass
|
||||
val getKotlinSourceSets = compilationClass.getMethodOrNull("getKotlinSourceSets") ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val kotlinGradleSourceSets = (getKotlinSourceSets(gradleCompilation) as? Collection<Named>) ?: return null
|
||||
val kotlinSourceSets = kotlinGradleSourceSets.mapNotNull { sourceSetMap[it.name] }
|
||||
val getCompileKotlinTaskName = compilationClass.getMethodOrNull("getCompileKotlinTaskName") ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val compileKotlinTaskName = (getCompileKotlinTaskName(gradleCompilation) as? String) ?: return null
|
||||
val compileKotlinTask = project.tasks.findByName(compileKotlinTaskName) ?: return null
|
||||
val output = buildCompilationOutput(gradleCompilation, compileKotlinTask) ?: return null
|
||||
val arguments = buildCompilationArguments(compileKotlinTask) ?: return null
|
||||
val dependencyClasspath = buildDependencyClasspath(compileKotlinTask)
|
||||
val dependencies = buildDependencies(gradleCompilation, dependencyResolver, project)
|
||||
return KotlinCompilationImpl(isAndroid, gradleCompilation.name, kotlinSourceSets, dependencies, output, arguments, dependencyClasspath)
|
||||
}
|
||||
|
||||
private fun buildDependencies(
|
||||
gradleCompilation: Named,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project
|
||||
): Set<KotlinDependency> {
|
||||
return LinkedHashSet<KotlinDependency>().apply {
|
||||
this += buildDependencies(
|
||||
gradleCompilation, dependencyResolver, "getCompileDependencyConfigurationName", "COMPILE", project
|
||||
)
|
||||
this += buildDependencies(
|
||||
gradleCompilation, dependencyResolver, "getRuntimeDependencyConfigurationName", "RUNTIME", project
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildCompilationArguments(compileKotlinTask: Task): KotlinCompilationArguments? {
|
||||
val compileTaskClass = compileKotlinTask.javaClass
|
||||
val getCurrentArguments = compileTaskClass.getMethodOrNull("getSerializedCompilerArguments") ?: return null
|
||||
val getDefaultArguments = compileTaskClass.getMethodOrNull("getDefaultSerializedCompilerArguments") ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val currentArguments = getCurrentArguments(compileKotlinTask) as? List<String> ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val defaultArguments = getDefaultArguments(compileKotlinTask) as? List<String> ?: return null
|
||||
return KotlinCompilationArgumentsImpl(defaultArguments, currentArguments)
|
||||
}
|
||||
|
||||
private fun buildDependencyClasspath(compileKotlinTask: Task): List<String> {
|
||||
val abstractKotlinCompileClass =
|
||||
compileKotlinTask.javaClass.classLoader.loadClass(AbstractKotlinGradleModelBuilder.ABSTRACT_KOTLIN_COMPILE_CLASS)
|
||||
val getCompileClasspath =
|
||||
abstractKotlinCompileClass.getDeclaredMethodOrNull("getCompileClasspath") ?: return emptyList()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return (getCompileClasspath(compileKotlinTask) as? Collection<File>)?.map { it.path } ?: emptyList()
|
||||
}
|
||||
|
||||
private fun buildCompilationOutput(
|
||||
gradleCompilation: Named,
|
||||
compileKotlinTask: Task
|
||||
): KotlinCompilationOutput? {
|
||||
val compilationClass = gradleCompilation.javaClass
|
||||
val getOutput = compilationClass.getMethodOrNull("getOutput") ?: return null
|
||||
val gradleOutput = getOutput(gradleCompilation) ?: return null
|
||||
val gradleOutputClass = gradleOutput.javaClass
|
||||
val getClassesDirs = gradleOutputClass.getMethodOrNull("getClassesDirs") ?: return null
|
||||
val getResourcesDir = gradleOutputClass.getMethodOrNull("getResourcesDir") ?: return null
|
||||
val compileKotlinTaskClass = compileKotlinTask.javaClass
|
||||
val getDestinationDir = compileKotlinTaskClass.getMethodOrNull("getDestinationDir") ?: return null
|
||||
val classesDirs = getClassesDirs(gradleOutput) as? FileCollection ?: return null
|
||||
val resourcesDir = getResourcesDir(gradleOutput) as? File ?: return null
|
||||
val destinationDir = getDestinationDir(compileKotlinTask) as? File
|
||||
return KotlinCompilationOutputImpl(classesDirs.files, destinationDir, resourcesDir)
|
||||
}
|
||||
|
||||
private fun computeSourceSetsDeferredInfo(
|
||||
sourceSets: Collection<KotlinSourceSetImpl>,
|
||||
targets: Collection<KotlinTarget>
|
||||
) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
for (sourceSet in sourceSets) {
|
||||
val compilations = sourceSetToCompilations[sourceSet] ?: continue
|
||||
sourceSet.platform = compilations.map { it.platform }.distinct().singleOrNull() ?: KotlinPlatform.COMMON
|
||||
sourceSet.dependencies = compilations.flatMapTo(LinkedHashSet()) { it.dependencies }
|
||||
sourceSet.isTestModule = compilations.all { it.isTestModule }
|
||||
sourceSet.isAndroid = compilations.all { it.isAndroid }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val KOTLIN_ANDROID_TARGET_CLASS_NAME = "org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* 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.gradle
|
||||
|
||||
import org.gradle.api.Named
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.SourceDirectorySet
|
||||
import org.jetbrains.plugins.gradle.model.AbstractExternalDependency
|
||||
import org.jetbrains.plugins.gradle.model.DefaultExternalProjectDependency
|
||||
import org.jetbrains.plugins.gradle.model.ExternalDependency
|
||||
import org.jetbrains.plugins.gradle.model.ExternalProjectDependency
|
||||
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
|
||||
import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
|
||||
import org.jetbrains.plugins.gradle.tooling.util.DependencyResolver
|
||||
import org.jetbrains.plugins.gradle.tooling.util.DependencyResolverImpl
|
||||
import org.jetbrains.plugins.gradle.tooling.util.SourceSetCachedFinder
|
||||
import java.io.File
|
||||
import java.lang.Exception
|
||||
|
||||
class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
|
||||
return ErrorMessageBuilder
|
||||
.create(project, e, "Gradle import errors")
|
||||
.withDescription("Unable to build Kotlin project configuration")
|
||||
}
|
||||
|
||||
override fun canBuild(modelName: String?): Boolean {
|
||||
return modelName == KotlinMPPGradleModel::class.java.name
|
||||
}
|
||||
|
||||
override fun buildAll(modelName: String, project: Project): Any? {
|
||||
val dependencyResolver = DependencyResolverImpl(
|
||||
project,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
SourceSetCachedFinder(project)
|
||||
)
|
||||
val sourceSets = buildSourceSets(project) ?: return null
|
||||
val sourceSetMap = sourceSets.map { it.name to it }.toMap()
|
||||
val targets = buildTargets(sourceSetMap, dependencyResolver, project) ?: return null
|
||||
computeSourceSetsDeferredInfo(sourceSets, targets)
|
||||
val coroutinesState = getCoroutinesState(project)
|
||||
return KotlinMPPGradleModelImpl(sourceSetMap, targets, ExtraFeaturesImpl(coroutinesState))
|
||||
}
|
||||
|
||||
private fun getCoroutinesState(project: Project): String? {
|
||||
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
|
||||
val getExperimental = kotlinExt.javaClass.getMethodOrNull("getExperimental") ?: return null
|
||||
val experimentalExt = getExperimental(kotlinExt) ?: return null
|
||||
val getCoroutines = experimentalExt.javaClass.getMethodOrNull("getCoroutines") ?: return null
|
||||
return getCoroutines(experimentalExt) as? String
|
||||
}
|
||||
|
||||
private fun buildSourceSets(project: Project): Collection<KotlinSourceSetImpl>? {
|
||||
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
|
||||
val getSourceSets = kotlinExt.javaClass.getMethodOrNull("getSourceSets") ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val sourceSets =
|
||||
(getSourceSets(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
|
||||
return sourceSets.mapNotNull { buildSourceSet(it) }
|
||||
}
|
||||
|
||||
private fun buildSourceSet(gradleSourceSet: Named): KotlinSourceSetImpl? {
|
||||
val sourceSetClass = gradleSourceSet.javaClass
|
||||
val getSourceDirSet = sourceSetClass.getMethodOrNull("getKotlin") ?: return null
|
||||
val getResourceDirSet = sourceSetClass.getMethodOrNull("getResources") ?: return null
|
||||
val getDependsOn = sourceSetClass.getMethodOrNull("getDependsOn") ?: return null
|
||||
val sourceDirs = (getSourceDirSet(gradleSourceSet) as? SourceDirectorySet)?.srcDirs ?: emptySet()
|
||||
val resourceDirs = (getResourceDirSet(gradleSourceSet) as? SourceDirectorySet)?.srcDirs ?: emptySet()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val dependsOnSourceSets = (getDependsOn(gradleSourceSet) as? Set<Named>)?.mapTo(LinkedHashSet()) { it.name } ?: emptySet<String>()
|
||||
return KotlinSourceSetImpl(gradleSourceSet.name, sourceDirs, resourceDirs, dependsOnSourceSets)
|
||||
}
|
||||
|
||||
private fun buildDependencies(
|
||||
gradleCompilation: Any,
|
||||
dependencyResolver: DependencyResolver,
|
||||
configurationNameAccessor: String,
|
||||
scope: String,
|
||||
project: Project
|
||||
): Collection<KotlinDependency> {
|
||||
val gradleCompilationClass = gradleCompilation.javaClass
|
||||
val getConfigurationName = gradleCompilationClass.getMethodOrNull(configurationNameAccessor) ?: return emptyList()
|
||||
val configurationName = getConfigurationName(gradleCompilation) as? String ?: return emptyList()
|
||||
val configuration = project.configurations.findByName(configurationName) ?: return emptyList()
|
||||
if (!configuration.isCanBeResolved) return emptyList()
|
||||
val artifactsByProjectPath = configuration
|
||||
.resolvedConfiguration
|
||||
.lenientConfiguration
|
||||
.firstLevelModuleDependencies
|
||||
.flatMap { it.moduleArtifacts }
|
||||
.filter { it.id.componentIdentifier is ProjectComponentIdentifier }
|
||||
.groupBy { (it.id.componentIdentifier as ProjectComponentIdentifier).projectPath }
|
||||
return dependencyResolver.resolveDependencies(configuration)
|
||||
.apply {
|
||||
forEach<ExternalDependency?> { (it as? AbstractExternalDependency)?.scope = scope }
|
||||
}
|
||||
.map {
|
||||
if (it !is ExternalProjectDependency || it.configurationName != Dependency.DEFAULT_CONFIGURATION) return@map it
|
||||
val artifacts = artifactsByProjectPath[it.projectPath] ?: return@map it
|
||||
val classifier = artifacts.mapTo(LinkedHashSet()) { it.classifier }.singleOrNull() ?: return@map it
|
||||
DefaultExternalProjectDependency(it).apply {
|
||||
this.classifier = classifier
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildTargets(
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project
|
||||
): Collection<KotlinTarget>? {
|
||||
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
|
||||
val getTargets = kotlinExt.javaClass.getMethodOrNull("getTargets") ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val targets = (getTargets.invoke(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
|
||||
return targets.mapNotNull { buildTarget(it, sourceSetMap, dependencyResolver, project) }
|
||||
}
|
||||
|
||||
private fun buildTarget(
|
||||
gradleTarget: Named,
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project
|
||||
): KotlinTarget? {
|
||||
val targetClass = gradleTarget.javaClass
|
||||
val getPlatformType = targetClass.getMethodOrNull("getPlatformType") ?: return null
|
||||
val getCompilations = targetClass.getMethodOrNull("getCompilations") ?: return null
|
||||
val getDisambiguationClassifier = targetClass.getMethodOrNull("getDisambiguationClassifier") ?: return null
|
||||
val platformId = (getPlatformType.invoke(gradleTarget) as? Named)?.name ?: return null
|
||||
val platform = KotlinPlatform.byId(platformId) ?: return null
|
||||
val disambiguationClassifier = getDisambiguationClassifier(gradleTarget) as? String
|
||||
val isAndroid = targetClass.name == KOTLIN_ANDROID_TARGET_CLASS_NAME
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val gradleCompilations =
|
||||
(getCompilations.invoke(gradleTarget) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
|
||||
val compilations = gradleCompilations.mapNotNull { buildCompilation(it, sourceSetMap, dependencyResolver, isAndroid, project) }
|
||||
val jar = buildTargetJar(gradleTarget, project)
|
||||
val target = KotlinTargetImpl(isAndroid, gradleTarget.name, disambiguationClassifier, platform, compilations, jar)
|
||||
compilations.forEach { it.target = target }
|
||||
return target
|
||||
}
|
||||
|
||||
private fun buildTargetJar(gradleTarget: Named, project: Project): KotlinTargetJar? {
|
||||
val targetClass = gradleTarget.javaClass
|
||||
val getArtifactsTaskName = targetClass.getMethodOrNull("getArtifactsTaskName") ?: return null
|
||||
val artifactsTaskName = getArtifactsTaskName(gradleTarget) as? String ?: return null
|
||||
val jarTask = project.tasks.findByName(artifactsTaskName) ?: return null
|
||||
val jarTaskClass = jarTask.javaClass
|
||||
val getArchivePath = jarTaskClass.getMethodOrNull("getArchivePath")
|
||||
val archiveFile = getArchivePath?.invoke(jarTask) as? File?
|
||||
return KotlinTargetJarImpl(archiveFile)
|
||||
}
|
||||
|
||||
private fun buildCompilation(
|
||||
gradleCompilation: Named,
|
||||
sourceSetMap: Map<String, KotlinSourceSet>,
|
||||
dependencyResolver: DependencyResolver,
|
||||
isAndroid: Boolean,
|
||||
project: Project
|
||||
): KotlinCompilationImpl? {
|
||||
val compilationClass = gradleCompilation.javaClass
|
||||
val getKotlinSourceSets = compilationClass.getMethodOrNull("getKotlinSourceSets") ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val kotlinGradleSourceSets = (getKotlinSourceSets(gradleCompilation) as? Collection<Named>) ?: return null
|
||||
val kotlinSourceSets = kotlinGradleSourceSets.mapNotNull { sourceSetMap[it.name] }
|
||||
val getCompileKotlinTaskName = compilationClass.getMethodOrNull("getCompileKotlinTaskName") ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val compileKotlinTaskName = (getCompileKotlinTaskName(gradleCompilation) as? String) ?: return null
|
||||
val compileKotlinTask = project.tasks.findByName(compileKotlinTaskName) ?: return null
|
||||
val output = buildCompilationOutput(gradleCompilation, compileKotlinTask) ?: return null
|
||||
val arguments = buildCompilationArguments(compileKotlinTask) ?: return null
|
||||
val dependencyClasspath = buildDependencyClasspath(compileKotlinTask)
|
||||
val dependencies = buildDependencies(gradleCompilation, dependencyResolver, project)
|
||||
return KotlinCompilationImpl(isAndroid, gradleCompilation.name, kotlinSourceSets, dependencies, output, arguments, dependencyClasspath)
|
||||
}
|
||||
|
||||
private fun buildDependencies(
|
||||
gradleCompilation: Named,
|
||||
dependencyResolver: DependencyResolver,
|
||||
project: Project
|
||||
): Set<KotlinDependency> {
|
||||
return LinkedHashSet<KotlinDependency>().apply {
|
||||
this += buildDependencies(
|
||||
gradleCompilation, dependencyResolver, "getCompileDependencyConfigurationName", "COMPILE", project
|
||||
)
|
||||
this += buildDependencies(
|
||||
gradleCompilation, dependencyResolver, "getRuntimeDependencyConfigurationName", "RUNTIME", project
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildCompilationArguments(compileKotlinTask: Task): KotlinCompilationArguments? {
|
||||
val compileTaskClass = compileKotlinTask.javaClass
|
||||
val getCurrentArguments = compileTaskClass.getMethodOrNull("getSerializedCompilerArguments") ?: return null
|
||||
val getDefaultArguments = compileTaskClass.getMethodOrNull("getDefaultSerializedCompilerArguments") ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val currentArguments = getCurrentArguments(compileKotlinTask) as? List<String> ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val defaultArguments = getDefaultArguments(compileKotlinTask) as? List<String> ?: return null
|
||||
return KotlinCompilationArgumentsImpl(defaultArguments, currentArguments)
|
||||
}
|
||||
|
||||
private fun buildDependencyClasspath(compileKotlinTask: Task): List<String> {
|
||||
val abstractKotlinCompileClass =
|
||||
compileKotlinTask.javaClass.classLoader.loadClass(AbstractKotlinGradleModelBuilder.ABSTRACT_KOTLIN_COMPILE_CLASS)
|
||||
val getCompileClasspath =
|
||||
abstractKotlinCompileClass.getDeclaredMethodOrNull("getCompileClasspath") ?: return emptyList()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return (getCompileClasspath(compileKotlinTask) as? Collection<File>)?.map { it.path } ?: emptyList()
|
||||
}
|
||||
|
||||
private fun buildCompilationOutput(
|
||||
gradleCompilation: Named,
|
||||
compileKotlinTask: Task
|
||||
): KotlinCompilationOutput? {
|
||||
val compilationClass = gradleCompilation.javaClass
|
||||
val getOutput = compilationClass.getMethodOrNull("getOutput") ?: return null
|
||||
val gradleOutput = getOutput(gradleCompilation) ?: return null
|
||||
val gradleOutputClass = gradleOutput.javaClass
|
||||
val getClassesDirs = gradleOutputClass.getMethodOrNull("getClassesDirs") ?: return null
|
||||
val getResourcesDir = gradleOutputClass.getMethodOrNull("getResourcesDir") ?: return null
|
||||
val compileKotlinTaskClass = compileKotlinTask.javaClass
|
||||
val getDestinationDir = compileKotlinTaskClass.getMethodOrNull("getDestinationDir") ?: return null
|
||||
val classesDirs = getClassesDirs(gradleOutput) as? FileCollection ?: return null
|
||||
val resourcesDir = getResourcesDir(gradleOutput) as? File ?: return null
|
||||
val destinationDir = getDestinationDir(compileKotlinTask) as? File
|
||||
return KotlinCompilationOutputImpl(classesDirs.files, destinationDir, resourcesDir)
|
||||
}
|
||||
|
||||
private fun computeSourceSetsDeferredInfo(
|
||||
sourceSets: Collection<KotlinSourceSetImpl>,
|
||||
targets: Collection<KotlinTarget>
|
||||
) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
for (sourceSet in sourceSets) {
|
||||
val compilations = sourceSetToCompilations[sourceSet] ?: continue
|
||||
sourceSet.platform = compilations.map { it.platform }.distinct().singleOrNull() ?: KotlinPlatform.COMMON
|
||||
sourceSet.dependencies = compilations.flatMapTo(LinkedHashSet()) { it.dependencies }
|
||||
sourceSet.isTestModule = compilations.all { it.isTestModule }
|
||||
sourceSet.isAndroid = compilations.all { it.isAndroid }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val KOTLIN_ANDROID_TARGET_CLASS_NAME = "org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.gradle
|
||||
|
||||
import java.io.File
|
||||
|
||||
class KotlinSourceSetImpl(
|
||||
override val name: String,
|
||||
override val sourceDirs: Set<File>,
|
||||
override val resourceDirs: Set<File>,
|
||||
override val dependsOnSourceSets: Set<String>
|
||||
) : KotlinSourceSet {
|
||||
override var isAndroid: Boolean = false
|
||||
internal set
|
||||
|
||||
override var platform: KotlinPlatform = KotlinPlatform.COMMON
|
||||
internal set
|
||||
|
||||
override var dependencies: Set<KotlinDependency> = emptySet()
|
||||
internal set
|
||||
|
||||
override var isTestModule: Boolean = false
|
||||
internal set
|
||||
|
||||
override fun toString() = name
|
||||
}
|
||||
|
||||
class KotlinCompilationOutputImpl(
|
||||
override val classesDirs: Set<File>,
|
||||
override val effectiveClassesDir: File?,
|
||||
override val resourcesDir: File?
|
||||
) : KotlinCompilationOutput
|
||||
|
||||
class KotlinCompilationArgumentsImpl(
|
||||
override val defaultArguments: List<String>,
|
||||
override val currentArguments: List<String>
|
||||
) : KotlinCompilationArguments
|
||||
|
||||
class KotlinCompilationImpl(
|
||||
override val isAndroid: Boolean,
|
||||
override val name: String,
|
||||
override val sourceSets: Collection<KotlinSourceSet>,
|
||||
override val dependencies: Set<KotlinDependency>,
|
||||
override val output: KotlinCompilationOutput,
|
||||
override val arguments: KotlinCompilationArguments,
|
||||
override val dependencyClasspath: List<String>
|
||||
) : KotlinCompilation {
|
||||
override lateinit var target: KotlinTarget
|
||||
internal set
|
||||
|
||||
override val platform: KotlinPlatform
|
||||
get() = target.platform
|
||||
|
||||
override val isTestModule: Boolean
|
||||
get() = name == KotlinCompilation.TEST_COMPILATION_NAME
|
||||
|
||||
override fun toString() = name
|
||||
}
|
||||
|
||||
class KotlinTargetJarImpl(
|
||||
override val archiveFile: File?
|
||||
) : KotlinTargetJar
|
||||
|
||||
class KotlinTargetImpl(
|
||||
override val isAndroid: Boolean,
|
||||
override val name: String,
|
||||
override val disambiguationClassifier: String?,
|
||||
override val platform: KotlinPlatform,
|
||||
override val compilations: Collection<KotlinCompilation>,
|
||||
override val jar: KotlinTargetJar?
|
||||
) : KotlinTarget {
|
||||
override fun toString() = name
|
||||
}
|
||||
|
||||
class ExtraFeaturesImpl(
|
||||
override val coroutinesState: String?
|
||||
) : ExtraFeatures
|
||||
|
||||
class KotlinMPPGradleModelImpl(
|
||||
override val sourceSets: Map<String, KotlinSourceSet>,
|
||||
override val targets: Collection<KotlinTarget>,
|
||||
override val extraFeatures: ExtraFeatures
|
||||
) : KotlinMPPGradleModel
|
||||
+1
@@ -1 +1,2 @@
|
||||
org.jetbrains.kotlin.gradle.KotlinGradleModelBuilder
|
||||
org.jetbrains.kotlin.gradle.KotlinMPPGradleModelBuilder
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.gradle
|
||||
|
||||
fun Class<*>.getMethodOrNull(name: String, vararg parameterTypes: Class<*>) =
|
||||
try {
|
||||
getMethod(name, *parameterTypes)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
fun Class<*>.getDeclaredMethodOrNull(name: String, vararg parameterTypes: Class<*>) =
|
||||
try {
|
||||
getDeclaredMethod(name, *parameterTypes)?.also { it.isAccessible = true }
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
@@ -72,10 +72,12 @@
|
||||
<referencesSearch implementation="org.jetbrains.kotlin.AndroidExtensionsReferenceSearchExecutor"/>
|
||||
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleLibraryDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleMPPModuleDataService"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||
<projectResolve implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsProjectResolverExtension"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidMPPGradleProjectResolver"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
|
||||
@@ -70,10 +70,12 @@
|
||||
<referencesSearch implementation="org.jetbrains.kotlin.AndroidExtensionsReferenceSearchExecutor"/>
|
||||
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleLibraryDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleMPPModuleDataService"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||
<projectResolve implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsProjectResolverExtension"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidMPPGradleProjectResolver"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
|
||||
@@ -72,10 +72,12 @@
|
||||
<referencesSearch implementation="org.jetbrains.kotlin.AndroidExtensionsReferenceSearchExecutor"/>
|
||||
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleLibraryDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleMPPModuleDataService"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||
<projectResolve implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsProjectResolverExtension"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidMPPGradleProjectResolver"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
|
||||
@@ -72,10 +72,12 @@
|
||||
<referencesSearch implementation="org.jetbrains.kotlin.AndroidExtensionsReferenceSearchExecutor"/>
|
||||
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleLibraryDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleMPPModuleDataService"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||
<projectResolve implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsProjectResolverExtension"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidMPPGradleProjectResolver"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
|
||||
@@ -13,12 +13,15 @@
|
||||
<projectResolve implementation="org.jetbrains.kotlin.allopen.ide.AllOpenProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.noarg.ide.NoArgProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
|
||||
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.core.script.ReloadGradleTemplatesOnSync"/>
|
||||
|
||||
<localInspection
|
||||
|
||||
@@ -13,12 +13,15 @@
|
||||
<projectResolve implementation="org.jetbrains.kotlin.allopen.ide.AllOpenProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.noarg.ide.NoArgProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
|
||||
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.core.script.ReloadGradleTemplatesOnSync"/>
|
||||
|
||||
<localInspection
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<projectResolve implementation="org.jetbrains.kotlin.allopen.ide.AllOpenProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.noarg.ide.NoArgProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver"/>
|
||||
</extensions>
|
||||
|
||||
<extensionPoints>
|
||||
@@ -27,6 +28,8 @@
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
|
||||
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.core.script.ReloadGradleTemplatesOnSync"/>
|
||||
|
||||
<localInspection
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<projectResolve implementation="org.jetbrains.kotlin.allopen.ide.AllOpenProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.noarg.ide.NoArgProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver"/>
|
||||
</extensions>
|
||||
|
||||
<extensionPoints>
|
||||
@@ -27,6 +28,8 @@
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
|
||||
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.core.script.ReloadGradleTemplatesOnSync"/>
|
||||
|
||||
<localInspection
|
||||
|
||||
@@ -252,16 +252,29 @@ fun parseCompilerArgumentsToFacet(
|
||||
defaultArguments: List<String>,
|
||||
kotlinFacet: KotlinFacet,
|
||||
modelsProvider: IdeModifiableModelsProvider?
|
||||
) {
|
||||
val compilerArgumentsClass = kotlinFacet.configuration.settings.compilerArguments?.javaClass ?: return
|
||||
val currentArgumentsBean = compilerArgumentsClass.newInstance()
|
||||
val defaultArgumentsBean = compilerArgumentsClass.newInstance()
|
||||
parseCommandLineArguments(defaultArguments, defaultArgumentsBean)
|
||||
parseCommandLineArguments(arguments, currentArgumentsBean)
|
||||
applyCompilerArgumentsToFacet(currentArgumentsBean, defaultArgumentsBean, kotlinFacet, modelsProvider)
|
||||
}
|
||||
|
||||
fun applyCompilerArgumentsToFacet(
|
||||
arguments: CommonCompilerArguments,
|
||||
defaultArguments: CommonCompilerArguments?,
|
||||
kotlinFacet: KotlinFacet,
|
||||
modelsProvider: IdeModifiableModelsProvider
|
||||
) {
|
||||
with(kotlinFacet.configuration.settings) {
|
||||
val compilerArguments = this.compilerArguments ?: return
|
||||
|
||||
val defaultCompilerArguments = compilerArguments::class.java.newInstance()
|
||||
parseCommandLineArguments(defaultArguments, defaultCompilerArguments)
|
||||
val defaultCompilerArguments = defaultArguments?.let { copyBean(it) } ?: compilerArguments::class.java.newInstance()
|
||||
defaultCompilerArguments.convertPathsToSystemIndependent()
|
||||
|
||||
parseCommandLineArguments(arguments, compilerArguments)
|
||||
|
||||
val emptyArgs = compilerArguments::class.java.newInstance()
|
||||
copyBeanTo(arguments, compilerArguments) { property, value -> value != property.get(emptyArgs) }
|
||||
compilerArguments.convertPathsToSystemIndependent()
|
||||
|
||||
// Retain only fields exposed (and not explicitly ignored) in facet configuration editor.
|
||||
|
||||
Reference in New Issue
Block a user