diff --git a/libraries/tools/kotlin-gradle-plugin-idea/api/kotlin-gradle-plugin-idea.api b/libraries/tools/kotlin-gradle-plugin-idea/api/kotlin-gradle-plugin-idea.api index ca31a922c94..6a700bb3368 100644 --- a/libraries/tools/kotlin-gradle-plugin-idea/api/kotlin-gradle-plugin-idea.api +++ b/libraries/tools/kotlin-gradle-plugin-idea/api/kotlin-gradle-plugin-idea.api @@ -576,10 +576,13 @@ public final class org/jetbrains/kotlin/gradle/idea/tcs/extras/PrimitiveExtrasKt public static final fun isNativeDistributionKey ()Lorg/jetbrains/kotlin/tooling/core/Extras$Key; public static final fun isNativeStdlib (Lorg/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinBinaryDependency;)Z public static final fun isNativeStdlibKey ()Lorg/jetbrains/kotlin/tooling/core/Extras$Key; + public static final fun isOpaqueFileDependency (Lorg/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinBinaryDependency;)Z + public static final fun isOpaqueFileDependencyKey ()Lorg/jetbrains/kotlin/tooling/core/Extras$Key; public static final fun setCommonized (Lorg/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinBinaryDependency;Z)V public static final fun setIdeaProjectLevel (Lorg/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinBinaryDependency;Z)V public static final fun setNativeDistribution (Lorg/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinBinaryDependency;Z)V public static final fun setNativeStdlib (Lorg/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinBinaryDependency;Z)V + public static final fun setOpaqueFileDependency (Lorg/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinBinaryDependency;Z)V } public final class org/jetbrains/kotlin/gradle/idea/tcs/extras/ProjectArtifactClasspathExtrasKt { diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/extras/primitiveExtras.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/extras/primitiveExtras.kt index 1f99d98a94e..7e3527e24c0 100644 --- a/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/extras/primitiveExtras.kt +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/main/kotlin/org/jetbrains/kotlin/gradle/idea/tcs/extras/primitiveExtras.kt @@ -41,3 +41,24 @@ val isCommonizedKey = extrasKeyOf("isCommonized") * Marks dependencies produced by the commonizer */ var IdeaKotlinBinaryDependency.isCommonized by isCommonizedKey.readWriteProperty.notNull(false) + + +/** + * @see isOpaqueFileDependencyKey + */ +val isOpaqueFileDependencyKey = extrasKeyOf("isOpaqueFileDependencyKey") + +/** + * Marks a dependency as 'opaque' (meaning that we cannot really know about the actual binary coordiantes) + * + * Example: File dependencies are 'opaque' + * ```kotlin + * kotlin { + * sourceSets.jvmMain.dependencies { + * implementation(files("libs/foo.jar")) // <- OPAQUE + * implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.2") // <- NOT OPAQUE + * } + * } + * ``` + */ +var IdeaKotlinBinaryDependency.isOpaqueFileDependency by isOpaqueFileDependencyKey.readWriteProperty.notNull(false) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver.kt index aa3a6ded0e6..4f575edf4bf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeBinaryDependencyResolver.kt @@ -15,8 +15,9 @@ import org.gradle.internal.resolve.ModuleVersionResolveException import org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi import org.jetbrains.kotlin.gradle.idea.tcs.* import org.jetbrains.kotlin.gradle.idea.tcs.extras.artifactsClasspath -import org.jetbrains.kotlin.gradle.idea.tcs.extras.isIdeaProjectLevel +import org.jetbrains.kotlin.gradle.idea.tcs.extras.isOpaqueFileDependency import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinOutputDependencyIdentifier import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.ide.* @@ -32,6 +33,7 @@ import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.sources.InternalKotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.sources.internal import org.jetbrains.kotlin.gradle.utils.markResolvable +import org.jetbrains.kotlin.gradle.utils.relativeOrAbsolute import org.jetbrains.kotlin.tooling.core.mutableExtrasOf /** @@ -171,18 +173,31 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor( is OpaqueComponentArtifactIdentifier -> { /* Such dependencies *would* require implementing a resolver */ - null + IdeaKotlinResolvedBinaryDependency( + binaryType = binaryType, coordinates = IdeaKotlinBinaryCoordinates( + group = "", + module = componentId.file.relativeOrAbsolute(sourceSet.project.rootDir), + version = null, + sourceSetName = null + ), + classpath = IdeaKotlinClasspath(componentId.file) + ).also { dependency -> + dependency.isOpaqueFileDependency = true + } } + /* + Such dependencies (e.g. associate compilations, cinterops, ...) + Will have dedicated resolvers implemented + */ + is KotlinOutputDependencyIdentifier -> null + else -> { logger.warn("Unhandled componentId: ${componentId.javaClass}") null } }?.also { dependency -> dependency.gradleArtifact = artifact - if (dependency is IdeaKotlinResolvedBinaryDependency) { - dependency.isIdeaProjectLevel = false - } } }.toSet() @@ -235,11 +250,7 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor( private fun ArtifactResolutionStrategy.createArtifactViewFromConfiguration( sourceSet: KotlinSourceSet, configuration: Configuration, - ): ArtifactView = configuration.incoming - .apply { - val dependencyFilter = dependencyFilter - if (dependencyFilter != null) dependencies.removeIf { dependency -> !dependencyFilter.invoke(dependency) } - } + ): ArtifactView = (if (dependencyFilter != null) configuration.copyRecursive(dependencyFilter) else configuration).incoming .artifactView { view -> view.isLenient = true view.attributes.setupArtifactViewAttributes(sourceSet) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/kotlinExtrasSerialization.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/kotlinExtrasSerialization.kt index 3e5e1cb9541..f8696027e9b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/kotlinExtrasSerialization.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/kotlinExtrasSerialization.kt @@ -24,4 +24,5 @@ val kotlinExtrasSerialization = IdeaKotlinExtrasSerializationExtension { register(sourcesClasspathKey, IdeaKotlinClasspathSerializer) register(documentationClasspathKey, IdeaKotlinClasspathSerializer) register(projectArtifactsClasspathKey, IdeaKotlinClasspathSerializer) + register(isOpaqueFileDependencyKey, IdeaKotlinBooleanExtrasSerializer) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/dependencyResolutionTests/tcs/IdeOpaqueFileDependencyResolutionTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/dependencyResolutionTests/tcs/IdeOpaqueFileDependencyResolutionTest.kt new file mode 100644 index 00000000000..0017fd6d83e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/dependencyResolutionTests/tcs/IdeOpaqueFileDependencyResolutionTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("FunctionName") + +package org.jetbrains.kotlin.gradle.dependencyResolutionTests.tcs + +import org.jetbrains.kotlin.gradle.dependencyResolutionTests.mavenCentralCacheRedirector +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformSourceSetConventionsImpl.dependencies +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformSourceSetConventionsImpl.jvmMain +import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency +import org.jetbrains.kotlin.gradle.idea.tcs.extras.isOpaqueFileDependency +import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.* +import org.jetbrains.kotlin.gradle.plugin.ide.kotlinIdeMultiplatformImport +import org.jetbrains.kotlin.gradle.util.applyMultiplatformPlugin +import org.jetbrains.kotlin.gradle.util.buildProject +import org.jetbrains.kotlin.gradle.util.enableDefaultStdlibDependency +import org.jetbrains.kotlin.gradle.util.enableDependencyVerification +import kotlin.test.Test +import kotlin.test.assertTrue +import kotlin.test.fail + +class IdeOpaqueFileDependencyResolutionTest { + @Test + fun `test - simple jar file`() { + val project = buildProject { + enableDefaultStdlibDependency(false) + enableDependencyVerification(false) + applyMultiplatformPlugin() + repositories.mavenCentralCacheRedirector() + + val kotlin = project.multiplatformExtension + kotlin.jvm() + + /* + Setup opaque file dependency to 'foo.jar' + */ + kotlin.sourceSets.jvmMain.dependencies { + implementation(project.files("libs/foo.jar")) + } + } + + project.evaluate() + + /* Check dependencies on jvmMain */ + val fooJarMatcher = binaryCoordinates(Regex(""".*:libs[/\\]foo\.jar""")) + + val fooJarDependency = project.kotlinIdeMultiplatformImport.resolveDependencies("jvmMain").assertMatches( + dependsOnDependency(":/commonMain"), + fooJarMatcher + ).getOrFail(fooJarMatcher) + + if (fooJarDependency !is IdeaKotlinResolvedBinaryDependency) { + fail("Expected 'foo.jar' to be resolved. Found $fooJarDependency") + } + + assertTrue( + fooJarDependency.isOpaqueFileDependency, + "Expected 'foo.jar' to be marked as 'opaque file dependency'" + ) + + /* Check dependencies on jvmTest */ + project.kotlinIdeMultiplatformImport.resolveDependencies("jvmTest").assertMatches( + friendSourceDependency(":/commonMain"), + friendSourceDependency(":/jvmMain"), + dependsOnDependency(":/commonTest"), + fooJarMatcher + ) + } +} \ No newline at end of file