From 36975786e88d396632641a113d4ccac8066655a5 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Wed, 18 Apr 2018 17:10:23 +0300 Subject: [PATCH] Gradle: Import project dependency with non-default configuration by its artifacts --- .../KotlinGradleProjectResolverExtension.kt | 32 +++-- .../MultiplatformProjectImportingTest.kt | 114 ++++++++++++++++++ .../ExternalSystemImportingTestCase.java | 2 +- 3 files changed, 135 insertions(+), 13 deletions(-) diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt index 7cf30d4b199..308304a3971 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt @@ -25,6 +25,7 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.roots.DependencyScope import com.intellij.openapi.util.Key import com.intellij.openapi.util.io.FileUtil +import org.gradle.api.artifacts.Dependency import org.gradle.tooling.model.idea.IdeaModule import org.jetbrains.kotlin.gradle.CompilerArgumentsBySourceSet import org.jetbrains.kotlin.gradle.KotlinGradleModel @@ -37,6 +38,7 @@ import org.jetbrains.plugins.gradle.model.FileCollectionDependency 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 java.io.File import java.util.* var DataNode.isResolved @@ -84,6 +86,14 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension() val gradleIdeaProject = gradleModule.project + fun getDependencyByFiles(files: Collection) = files + .mapTo(HashSet()) { + val path = FileUtil.toSystemIndependentName(it.path) + val targetSourceSetId = outputToSourceSet?.get(path)?.first ?: return@mapTo null + sourceSetByName?.get(targetSourceSetId)?.first + } + .singleOrNull() + fun DataNode.getDependencies(): Collection> { if (useModulePerSourceSet()) { if (sourceSetByName == null) return emptySet() @@ -91,20 +101,18 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension() return externalSourceSet.dependencies.mapNotNullTo(LinkedHashSet()) { dependency -> when (dependency) { is ExternalProjectDependency -> { - val targetModuleNode = ExternalSystemApiUtil.findFirstRecursively(ideProject) { - (it.data as? ModuleData)?.id == dependency.projectPath - } as DataNode? ?: return@mapNotNullTo null - ExternalSystemApiUtil.findAll(targetModuleNode, GradleSourceSetData.KEY) - .firstOrNull { it.sourceSetName == "main" } + if (dependency.configurationName == Dependency.DEFAULT_CONFIGURATION) { + val targetModuleNode = ExternalSystemApiUtil.findFirstRecursively(ideProject) { + (it.data as? ModuleData)?.id == dependency.projectPath + } as DataNode? ?: return@mapNotNullTo null + ExternalSystemApiUtil.findAll(targetModuleNode, GradleSourceSetData.KEY) + .firstOrNull { it.sourceSetName == "main" } + } else { + getDependencyByFiles(dependency.projectDependencyArtifacts) + } } is FileCollectionDependency -> { - dependency.files - .mapTo(HashSet()) { - val path = FileUtil.toSystemIndependentName(it.path) - val targetSourceSetId = outputToSourceSet?.get(path)?.first ?: return@mapTo null - sourceSetByName[targetSourceSetId]?.first - } - .singleOrNull() + getDependencyByFiles(dependency.files) } else -> null } diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/gradle/MultiplatformProjectImportingTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/gradle/MultiplatformProjectImportingTest.kt index 2d61be4149e..827008b5de1 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/gradle/MultiplatformProjectImportingTest.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/gradle/MultiplatformProjectImportingTest.kt @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.gradle import com.intellij.openapi.roots.DependencyScope +import com.intellij.openapi.roots.LibraryOrderEntry +import com.intellij.openapi.roots.OrderRootType import com.intellij.util.PathUtil import junit.framework.TestCase import org.jetbrains.kotlin.idea.codeInsight.gradle.GradleImportingTestCase @@ -26,6 +28,12 @@ import org.jetbrains.kotlin.test.KotlinTestUtils import org.junit.Test class MultiplatformProjectImportingTest : GradleImportingTestCase() { + private fun getDependencyLibraryUrls(moduleName: String) = + getRootManager(moduleName) + .orderEntries + .filterIsInstance() + .flatMap { it.getUrls(OrderRootType.CLASSES).map { it.replace(projectPath, "") } } + @Test fun testPlatformToCommonDependency() { createProjectSubFile("settings.gradle", "include ':common', ':jvm', ':js'") @@ -492,6 +500,112 @@ class MultiplatformProjectImportingTest : GradleImportingTestCase() { } } + @Test + fun testTransitiveImplementWithNonDefaultConfig() { + createProjectSubFile( + "settings.gradle", + "include ':project1', ':project2', ':project3'" + ) + + val kotlinVersion = "1.2.31" + + createProjectSubFile( + "build.gradle", """ + buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") + } + } + + project('project1') { + apply plugin: 'kotlin-platform-common' + } + + project('project2') { + repositories { + mavenCentral() + } + + apply plugin: 'kotlin-platform-jvm' + + sourceSets { + main + main2 + } + + task myJar(type: Jar) { + baseName = 'project2-jar' + from sourceSets.main.output + from sourceSets.main2.output + } + + configurations { + myConfig + } + + artifacts { + myConfig myJar + } + + dependencies { + implement project(':project1') + } + } + + project('project3') { + repositories { + mavenCentral() + } + + apply plugin: 'kotlin-platform-jvm' + apply plugin: 'kotlin' + + dependencies { + compile(project(path: ':project2', configuration: 'myConfig')) { transitive = false } + } + } + """ + ) + + val isResolveModulePerSourceSet = getCurrentExternalProjectSettings().isResolveModulePerSourceSet + + try { + currentExternalProjectSettings.isResolveModulePerSourceSet = true + importProject() + + assertModuleModuleDepScope("project2_main", "project1_main", DependencyScope.COMPILE) + assertModuleModuleDepScope("project3_main", "project2_main", DependencyScope.COMPILE) + assertNoDepForModule("project3_main", "project1_main") + + TestCase.assertEquals( + listOf("jar:///project2/build/libs/project2-jar.jar!/"), + getDependencyLibraryUrls("project3_main") + ) + + currentExternalProjectSettings.isResolveModulePerSourceSet = false + importProject() + + /* + * Note that currently such dependencies can't be imported correctly in "No separate module per source set" mode + * due to IDEA importer limitations + */ + assertModuleModuleDepScope("project2", "project1", DependencyScope.COMPILE) + assertModuleModuleDepScope("project3", "project2", DependencyScope.TEST, DependencyScope.PROVIDED, DependencyScope.RUNTIME) + assertModuleModuleDepScope("project3", "project1", DependencyScope.COMPILE) + + TestCase.assertEquals( + emptyList(), + getDependencyLibraryUrls("project3") + ) + } finally { + currentExternalProjectSettings.isResolveModulePerSourceSet = isResolveModulePerSourceSet + } + } + @Test fun testTransitiveImplementWithAndroid() { createProjectSubFile( diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ExternalSystemImportingTestCase.java b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ExternalSystemImportingTestCase.java index e9969d65842..03cb8eaaf5f 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ExternalSystemImportingTestCase.java +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ExternalSystemImportingTestCase.java @@ -138,7 +138,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest return getModuleDep(moduleName, depName, ModuleOrderEntry.class); } - private ModuleRootManager getRootManager(String module) { + protected ModuleRootManager getRootManager(String module) { return ModuleRootManager.getInstance(getModule(module)); }