Modules: Support production-on-test dependency
This feature is supported in IDEA project configuration and can be used in Maven/Gradle-based projects #KT-20112 Fixed
This commit is contained in:
+27
-10
@@ -21,6 +21,7 @@ import com.intellij.openapi.module.impl.scopes.LibraryScopeBase
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.*
|
||||
import com.intellij.openapi.roots.impl.ModuleOrderEntryImpl
|
||||
import com.intellij.openapi.roots.impl.libraries.LibraryEx
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import com.intellij.openapi.util.ModificationTracker
|
||||
@@ -35,6 +36,7 @@ import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.analyzer.TrackableModuleInfo
|
||||
import org.jetbrains.kotlin.caches.resolve.LibraryModuleInfo
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinPluginUtil
|
||||
import org.jetbrains.kotlin.idea.framework.getLibraryPlatform
|
||||
import org.jetbrains.kotlin.idea.project.KotlinModuleModificationTracker
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
@@ -58,8 +60,8 @@ interface IdeaModuleInfo : ModuleInfo {
|
||||
override fun dependencies(): List<IdeaModuleInfo>
|
||||
}
|
||||
|
||||
private fun orderEntryToModuleInfo(project: Project, orderEntry: OrderEntry, productionOnly: Boolean): List<IdeaModuleInfo> {
|
||||
fun Module.toInfos() = correspondingModuleInfos().filter { !productionOnly || it is ModuleProductionSourceInfo }
|
||||
private fun orderEntryToModuleInfo(project: Project, orderEntry: OrderEntry, forProduction: Boolean): List<IdeaModuleInfo> {
|
||||
fun Module.toInfos() = correspondingModuleInfos().filter { !forProduction || it is ModuleProductionSourceInfo }
|
||||
|
||||
if (!orderEntry.isValid) return emptyList()
|
||||
|
||||
@@ -68,7 +70,13 @@ private fun orderEntryToModuleInfo(project: Project, orderEntry: OrderEntry, pro
|
||||
orderEntry.getOwnerModule().toInfos()
|
||||
}
|
||||
is ModuleOrderEntry -> {
|
||||
orderEntry.module?.toInfos().orEmpty()
|
||||
val module = orderEntry.module ?: return emptyList()
|
||||
if (forProduction && orderEntry is ModuleOrderEntryImpl && orderEntry.isProductionOnTestDependency) {
|
||||
listOfNotNull(module.testSourceInfo())
|
||||
}
|
||||
else {
|
||||
module.toInfos()
|
||||
}
|
||||
}
|
||||
is LibraryOrderEntry -> {
|
||||
val library = orderEntry.library ?: return listOf()
|
||||
@@ -88,16 +96,25 @@ fun <T> Module.cached(provider: CachedValueProvider<T>): T {
|
||||
return CachedValuesManager.getManager(project).getCachedValue(this, provider)
|
||||
}
|
||||
|
||||
private fun ideaModelDependencies(module: Module, productionOnly: Boolean): List<IdeaModuleInfo> {
|
||||
private fun OrderEntry.acceptAsDependency(forProduction: Boolean): Boolean {
|
||||
return this !is ExportableOrderEntry
|
||||
|| !forProduction
|
||||
// this is needed for Maven/Gradle projects with "production-on-test" dependency
|
||||
|| this is ModuleOrderEntryImpl && isProductionOnTestDependency
|
||||
|| scope.isForProductionCompile
|
||||
}
|
||||
|
||||
private fun ideaModelDependencies(module: Module, forProduction: Boolean): List<IdeaModuleInfo> {
|
||||
//NOTE: lib dependencies can be processed several times during recursive traversal
|
||||
val result = LinkedHashSet<IdeaModuleInfo>()
|
||||
val dependencyEnumerator = ModuleRootManager.getInstance(module).orderEntries().compileOnly().recursively().exportedOnly()
|
||||
if (productionOnly) {
|
||||
if (forProduction && !(KotlinPluginUtil.isMavenModule(module) || KotlinPluginUtil.isGradleModule(module))) {
|
||||
dependencyEnumerator.productionOnly()
|
||||
}
|
||||
dependencyEnumerator.forEach {
|
||||
orderEntry ->
|
||||
result.addAll(orderEntryToModuleInfo(module.project, orderEntry!!, productionOnly))
|
||||
dependencyEnumerator.forEach { orderEntry ->
|
||||
if (orderEntry.acceptAsDependency(forProduction)) {
|
||||
result.addAll(orderEntryToModuleInfo(module.project, orderEntry!!, forProduction))
|
||||
}
|
||||
true
|
||||
}
|
||||
return result.toList()
|
||||
@@ -125,7 +142,7 @@ data class ModuleProductionSourceInfo internal constructor(override val module:
|
||||
|
||||
override fun dependencies() = module.cached(CachedValueProvider {
|
||||
CachedValueProvider.Result(
|
||||
ideaModelDependencies(module, productionOnly = true),
|
||||
ideaModelDependencies(module, forProduction = true),
|
||||
ProjectRootModificationTracker.getInstance(module.project))
|
||||
})
|
||||
}
|
||||
@@ -140,7 +157,7 @@ data class ModuleTestSourceInfo internal constructor(override val module: Module
|
||||
|
||||
override fun dependencies() = module.cached(CachedValueProvider {
|
||||
CachedValueProvider.Result(
|
||||
ideaModelDependencies(module, productionOnly = false),
|
||||
ideaModelDependencies(module, forProduction = false),
|
||||
ProjectRootModificationTracker.getInstance(module.project))
|
||||
})
|
||||
|
||||
|
||||
@@ -23,12 +23,16 @@ import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||
import com.intellij.openapi.roots.LibraryOrderEntry
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.roots.impl.libraries.LibraryEx
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
|
||||
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
|
||||
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
|
||||
@@ -1787,6 +1791,217 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
fun testProductionOnTestDependency() {
|
||||
createProjectSubDirs(
|
||||
"module-with-java/src/main/java",
|
||||
"module-with-java/src/test/java",
|
||||
"module-with-kotlin/src/main/kotlin",
|
||||
"module-with-kotlin/src/test/kotlin"
|
||||
)
|
||||
|
||||
val dummyFile = createProjectSubFile(
|
||||
"module-with-kotlin/src/main/kotlin/foo/dummy.kt",
|
||||
"""
|
||||
package foo
|
||||
|
||||
fun dummy() {
|
||||
}
|
||||
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val pomA = createModulePom(
|
||||
"module-with-java",
|
||||
"""
|
||||
<parent>
|
||||
<groupId>test-group</groupId>
|
||||
<artifactId>mvnktest</artifactId>
|
||||
<version>0.0.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>module-with-java</artifactId>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val pomB = createModulePom(
|
||||
"module-with-kotlin",
|
||||
"""
|
||||
<parent>
|
||||
<groupId>test-group</groupId>
|
||||
<artifactId>mvnktest</artifactId>
|
||||
<version>0.0.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>module-with-kotlin</artifactId>
|
||||
|
||||
<properties>
|
||||
<kotlin.version>1.1.4</kotlin.version>
|
||||
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
|
||||
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${"$"}{kotlin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-runtime</artifactId>
|
||||
<version>${"$"}{kotlin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
<version>${"$"}{kotlin.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>test-group</groupId>
|
||||
<artifactId>module-with-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>test-group</groupId>
|
||||
<artifactId>module-with-java</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<version>${"$"}{kotlin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<goals> <goal>compile</goal> </goals>
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>${"$"}{project.basedir}/src/main/kotlin</sourceDir>
|
||||
<sourceDir>${"$"}{project.basedir}/src/main/java</sourceDir>
|
||||
</sourceDirs>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<goals> <goal>test-compile</goal> </goals>
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>${"$"}{project.basedir}/src/test/kotlin</sourceDir>
|
||||
<sourceDir>${"$"}{project.basedir}/src/test/java</sourceDir>
|
||||
</sourceDirs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<executions>
|
||||
<!-- Replacing default-compile as it is treated specially by maven -->
|
||||
<execution>
|
||||
<id>default-compile</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
<!-- Replacing default-testCompile as it is treated specially by maven -->
|
||||
<execution>
|
||||
<id>default-testCompile</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>java-compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals> <goal>compile</goal> </goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>java-test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals> <goal>testCompile</goal> </goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val pomMain = createModulePom(
|
||||
"",
|
||||
"""
|
||||
<groupId>test-group</groupId>
|
||||
<artifactId>mvnktest</artifactId>
|
||||
<version>0.0.0.0-SNAPSHOT</version>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<kotlin.version>1.1.4</kotlin.version>
|
||||
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
|
||||
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>module-with-java</module>
|
||||
<module>module-with-kotlin</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>test-group</groupId>
|
||||
<artifactId>module-with-kotlin</artifactId>
|
||||
<version>${"$"}{project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>test-group</groupId>
|
||||
<artifactId>module-with-java</artifactId>
|
||||
<version>${"$"}{project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>test-group</groupId>
|
||||
<artifactId>module-with-java</artifactId>
|
||||
<version>${"$"}{project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
importProjects(pomMain, pomA, pomB)
|
||||
|
||||
assertModules("module-with-kotlin", "module-with-java", "mvnktest")
|
||||
|
||||
val dependencies = (dummyFile.toPsiFile(myProject) as KtFile).analyzeAndGetResult().moduleDescriptor.allDependencyModules
|
||||
TestCase.assertTrue(dependencies.any { it.name.asString() == "<production sources for module module-with-java>" })
|
||||
TestCase.assertTrue(dependencies.any { it.name.asString() == "<test sources for module module-with-java>" })
|
||||
}
|
||||
|
||||
private fun assertImporterStatePresent() {
|
||||
assertNotNull("Kotlin importer component is not present", myTestFixture.module.getComponent(KotlinImporterComponent::class.java))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user