Merge branch 'slava/mpp-import-experiments'

# Conflicts:
#	idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt
This commit is contained in:
Vyacheslav Karpukhin
2020-02-18 14:14:23 +01:00
8 changed files with 274 additions and 43 deletions
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.idea.configuration
import com.google.common.graph.GraphBuilder
import com.google.common.graph.Graphs
import com.intellij.ide.plugins.PluginManager
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.*
@@ -73,6 +75,10 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
initializeModuleData(gradleModule, moduleDataNode, projectDataNode, resolverCtx)
}
override fun getExtraCommandLineArgs(): List<String> {
return if (!androidPluginPresent) listOf("-Pkotlin.include.android.dependencies=true") else emptyList()
}
override fun populateModuleExtraModels(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
if (ExternalSystemApiUtil.find(ideModule, BuildScriptClasspathData.KEY) == null) {
val buildScriptClasspathData = buildClasspathData(gradleModule, resolverCtx)
@@ -228,6 +234,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
val proxyObjectCloningCache = WeakHashMap<Any, Any>()
private var nativeDebugAdvertised = false
private val androidPluginPresent = PluginManager.getPlugin(PluginId.findId("org.jetbrains.android"))?.isEnabled ?: false
fun initializeModuleData(
gradleModule: IdeaModule,
@@ -279,7 +286,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
val sourceSetToCompilationData = LinkedHashMap<KotlinSourceSet, MutableSet<GradleSourceSetData>>()
for (target in mppModel.targets) {
if (target.platform == KotlinPlatform.ANDROID) continue
if (delegateToAndroidPlugin(target)) continue
if (target.name == KotlinTarget.METADATA_TARGET_NAME) continue
val targetData = KotlinTargetData(target.name).also {
it.archiveFile = target.jar?.archiveFile
@@ -353,7 +360,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
val ignoreCommonSourceSets by lazy { externalProject.notImportedCommonSourceSets() }
for (sourceSet in mppModel.sourceSets.values) {
if (sourceSet.actualPlatforms.platforms.singleOrNull() == KotlinPlatform.ANDROID) continue
if (delegateToAndroidPlugin(sourceSet)) continue
if (sourceSet.actualPlatforms.supports(KotlinPlatform.COMMON) && ignoreCommonSourceSets) continue
val moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
val existingSourceSetDataNode = sourceSetMap[moduleId]?.first
@@ -451,7 +458,8 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
.toMap()
if (resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java) == null) return
processSourceSets(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, sourceSet ->
if (dataNode == null || sourceSet.actualPlatforms.platforms.singleOrNull() == KotlinPlatform.ANDROID) return@processSourceSets
if (dataNode == null || delegateToAndroidPlugin(sourceSet)) return@processSourceSets
createContentRootData(
sourceSet.sourceDirs,
sourceSet.sourceType,
@@ -561,7 +569,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
}
val closedSourceSetGraph = Graphs.transitiveClosure(sourceSetGraph)
for (sourceSet in closedSourceSetGraph.nodes()) {
val isAndroid = sourceSet.actualPlatforms.platforms.singleOrNull() == KotlinPlatform.ANDROID
val isAndroid = delegateToAndroidPlugin(sourceSet)
val fromDataNode = if (isAndroid) {
ideModule
} else {
@@ -581,7 +589,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
sourceSetInfo.addSourceSets(dependeeSourceSets, selfName, gradleModule, resolverCtx)
}
}
if (sourceSet.actualPlatforms.platforms.singleOrNull() == KotlinPlatform.ANDROID) continue
if (delegateToAndroidPlugin(sourceSet)) continue
for (dependeeSourceSet in dependeeSourceSets) {
val toDataNode = getSiblingKotlinModuleData(dependeeSourceSet, gradleModule, ideModule, resolverCtx) ?: continue
addDependency(fromDataNode, toDataNode, dependeeSourceSet.isTestModule)
@@ -750,7 +758,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
}
}
for (target in mppModel.targets) {
if (target.platform == KotlinPlatform.ANDROID) continue
if (delegateToAndroidPlugin(target)) continue
for (compilation in target.compilations) {
val moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx)
val moduleDataNode = sourceSetsMap[moduleId] ?: continue
@@ -971,6 +979,12 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
"true",
ignoreCase = true
) ?: false
private fun delegateToAndroidPlugin(kotlinTarget: KotlinTarget): Boolean =
androidPluginPresent && kotlinTarget.platform == KotlinPlatform.ANDROID
private fun delegateToAndroidPlugin(kotlinSourceSet: KotlinSourceSet): Boolean =
androidPluginPresent && kotlinSourceSet.actualPlatforms.platforms.singleOrNull() == KotlinPlatform.ANDROID
}
}
@@ -20,6 +20,7 @@ import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Exec
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel.Companion.NO_KOTLIN_NATIVE_HOME
import org.jetbrains.plugins.gradle.DefaultExternalDependencyId
import org.jetbrains.plugins.gradle.model.*
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
@@ -144,12 +145,13 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
@Suppress("UNCHECKED_CAST")
val sourceSets =
(getSourceSets(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
val androidDeps = buildAndroidDeps(kotlinExt.javaClass.classLoader, project)
// Some performance optimisation: do not build metadata dependencies if source set is not common
val doBuildMetadataDependencies =
project.properties["build_metadata_dependencies_for_actualised_source_sets"]?.toString()?.toBoolean()
?: DEFAULT_BUILD_METADATA_DEPENDENCIES_FOR_ACTUALISED_SOURCE_SETS
val allSourceSetsProtos = sourceSets.mapNotNull { buildSourceSet(it, dependencyResolver, project, dependencyMapper) }
val allSourceSetsProtos = sourceSets.mapNotNull { buildSourceSet(it, dependencyResolver, project, dependencyMapper, androidDeps) }
val allSourceSets = if (doBuildMetadataDependencies) {
allSourceSetsProtos.map { proto -> proto.buildKotlinSourceSetImpl(true) }
} else {
@@ -173,11 +175,28 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
}
}
private fun buildAndroidDeps(classLoader: ClassLoader, project: Project): Map<String, List<Any>>? {
val includeAndroidDeps = project.properties["kotlin.include.android.dependencies"]?.toString()?.toBoolean() == true
if (includeAndroidDeps) {
try {
val resolverClass = classLoader.loadClass("org.jetbrains.kotlin.gradle.targets.android.internal.AndroidDependencyResolver")
val getAndroidSourceSetDependencies = resolverClass.getMethodOrNull("getAndroidSourceSetDependencies", Project::class.java)
val resolver = resolverClass.getField("INSTANCE").get(null)
@Suppress("UNCHECKED_CAST")
return getAndroidSourceSetDependencies?.let { it(resolver, project) } as Map<String, List<Any>>?
} catch (e: Exception) {
logger.info("Unexpected exception", e)
}
}
return null
}
private fun buildSourceSet(
gradleSourceSet: Named,
dependencyResolver: DependencyResolver,
project: Project,
dependencyMapper: KotlinDependencyMapper
dependencyMapper: KotlinDependencyMapper,
androidDeps: Map<String, List<Any>>?
): KotlinSourceSetProto? {
val sourceSetClass = gradleSourceSet.javaClass
val getLanguageSettings = sourceSetClass.getMethodOrNull("getLanguageSettings") ?: return null
@@ -192,7 +211,7 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
val dependsOnSourceSets = (getDependsOn(gradleSourceSet) as? Set<Named>)?.mapTo(LinkedHashSet()) { it.name } ?: emptySet<String>()
val sourceSetDependenciesBuilder: () -> Array<KotlinDependencyId> = {
buildSourceSetDependencies(gradleSourceSet, dependencyResolver, project).map { dependencyMapper.getId(it) }.distinct()
buildSourceSetDependencies(gradleSourceSet, dependencyResolver, project, androidDeps).map { dependencyMapper.getId(it) }.distinct()
.toTypedArray()
}
return KotlinSourceSetProto(
@@ -598,7 +617,8 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
private fun buildSourceSetDependencies(
gradleSourceSet: Named,
dependencyResolver: DependencyResolver,
project: Project
project: Project,
androidDeps: Map<String, List<Any>>?
): List<KotlinDependency> {
return ArrayList<KotlinDependency>().apply {
val transformationBuilder = MetadataDependencyTransformationBuilder(gradleSourceSet)
@@ -614,9 +634,33 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
this += buildDependencies(
gradleSourceSet, dependencyResolver, "getRuntimeOnlyMetadataConfigurationName", "RUNTIME", project, transformationBuilder
)
this += buildAndroidSourceSetDependencies(androidDeps, gradleSourceSet)
}
}
private fun buildAndroidSourceSetDependencies(
androidDeps: Map<String, List<Any>>?,
gradleSourceSet: Named
): Collection<KotlinDependency> {
return androidDeps?.get(gradleSourceSet.name)?.map { it ->
@Suppress("UNCHECKED_CAST")
val collection = it["getCollection"] as Set<File>?
if (collection == null) {
DefaultExternalLibraryDependency().apply {
(id as? DefaultExternalDependencyId)?.apply {
name = it["getName"] as String?
group = it["getGroup"] as String?
version = it["getVersion"] as String?
}
file = it["getJar"] as File
source = it["getSource"] as File?
}
} else {
DefaultFileCollectionDependency(collection)
}
} ?: emptyList()
}
@Suppress("UNCHECKED_CAST")
private fun safelyGetArguments(compileKotlinTask: Task, accessor: Method?) = try {
accessor?.invoke(compileKotlinTask) as? List<String>