diff --git a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt index 18ee563a14e..9af1518638e 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt +++ b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt @@ -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 @@ -170,13 +171,13 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { } } - private fun buildAndroidDeps(kotlinExt: Any, project: Project): Map>? { + private fun buildAndroidDeps(kotlinExt: Any, project: Project): Map>? { val includeAndroidDeps = project.properties["kotlin.include.android.dependencies"]?.toString()?.toBoolean() == true if (includeAndroidDeps) { val getAndroidSourceSetDependencies = kotlinExt.javaClass.getMethodOrNull("getAndroidSourceSetDependencies", Project::class.java) @Suppress("UNCHECKED_CAST") - return getAndroidSourceSetDependencies?.let { it(kotlinExt, project) } as Map>? + return getAndroidSourceSetDependencies?.let { it(kotlinExt, project) } as Map>? } else { return emptyMap() } @@ -187,7 +188,7 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { dependencyResolver: DependencyResolver, project: Project, dependencyMapper: KotlinDependencyMapper, - androidDeps: Map>? + androidDeps: Map>? ): KotlinSourceSetProto? { val sourceSetClass = gradleSourceSet.javaClass val getLanguageSettings = sourceSetClass.getMethodOrNull("getLanguageSettings") ?: return null @@ -607,7 +608,7 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { gradleSourceSet: Named, dependencyResolver: DependencyResolver, project: Project, - androidDeps: Map>? + androidDeps: Map>? ): List { return ArrayList().apply { val transformationBuilder = MetadataDependencyTransformationBuilder(gradleSourceSet) @@ -623,11 +624,33 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { this += buildDependencies( gradleSourceSet, dependencyResolver, "getRuntimeOnlyMetadataConfigurationName", "RUNTIME", project, transformationBuilder ) - - androidDeps?.get(gradleSourceSet.name)?.let { this += DefaultFileCollectionDependency(it) } + this += buildAndroidSourceSetDependencies(androidDeps, gradleSourceSet) } } + private fun buildAndroidSourceSetDependencies( + androidDeps: Map>?, + gradleSourceSet: Named + ): Collection { + return androidDeps?.get(gradleSourceSet.name)?.map { it -> + @Suppress("UNCHECKED_CAST") + val collection = it["getCollection"] as Set? + 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 diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt index ae65af38ec6..f1dde142656 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt @@ -19,12 +19,11 @@ import org.gradle.api.InvalidUserCodeException import org.gradle.api.NamedDomainObjectCollection import org.gradle.api.Project import org.gradle.api.artifacts.* +import org.gradle.api.artifacts.component.ModuleComponentIdentifier import org.gradle.api.artifacts.component.ModuleComponentSelector import org.gradle.api.artifacts.result.ResolvedComponentResult import org.gradle.api.file.FileSystemLocation -import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency import org.gradle.api.provider.Provider -import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier import org.gradle.util.ConfigureUtil import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.* @@ -73,7 +72,16 @@ open class KotlinMultiplatformExtension : KotlinSoftwareComponentWithCoordinatesAndPublication("kotlin", targets) } - private fun getAndroidSdkJar(project: Project): File? { + data class AndroidDependency( + val name: String? = null, + val jar: File? = null, + val source: File? = null, + val group: String? = null, + val version: String? = null, + val collection: Set? = null + ) + + private fun getAndroidSdkJar(project: Project): AndroidDependency? { val androidExtension = project.extensions.findByName("android") as BaseExtension? ?: return null val sdkLocation = getClassOrNull("com.android.build.gradle.internal.SdkLocationSourceSet")?.let { sdkLocationSourceSetClass -> val sdkLocationSourceSet = sdkLocationSourceSetClass.kotlin.constructors.firstOrNull()?.let { callable -> @@ -90,7 +98,11 @@ open class KotlinMultiplatformExtension : val sdkHandler = AndroidSdkHandler.getInstance(sdkLocation) val logger = LoggerProgressIndicatorWrapper(LoggerWrapper(project.logger)) val androidTarget = sdkHandler.getAndroidTargetManager(logger).getTargetFromHashString(androidExtension.compileSdkVersion, logger) - return File(androidTarget.getPath(IAndroidTarget.ANDROID_JAR)) + return AndroidDependency( + androidTarget.fullName, + File(androidTarget.getPath(IAndroidTarget.ANDROID_JAR)), + File(androidTarget.getPath(IAndroidTarget.SOURCES)) + ) } private fun getClassOrNull(s: String) = @@ -118,7 +130,7 @@ open class KotlinMultiplatformExtension : return Version.parseVersion(version)?.isOrGreaterThan(3, 6) ?: false } - fun getAndroidSourceSetDependencies(project: Project): Map?> { + fun getAndroidSourceSetDependencies(project: Project): Map?> { if (!isAndroidPluginCompatible()) return emptyMap() data class SourceSetConfigs(val implConfig: Configuration, val compileConfig: Configuration) @@ -139,8 +151,8 @@ open class KotlinMultiplatformExtension : return sourceSet2Impl.mapValues { entry -> val dependencies = findDependencies(allImplConfigs, entry.value.implConfig) - val selfResolved = dependencies.filterIsInstance().flatMap { it.resolve() } - val resolvedExternal = dependencies.filterIsInstance() + val selfResolved = dependencies.filterIsInstance().map { AndroidDependency(collection = it.resolve()) } + val resolvedExternal = dependencies.filterIsInstance() .flatMap { collectDependencies(it.module, entry.value.compileConfig) } val result = (selfResolved + resolvedExternal + androidSdkJar).toMutableList() @@ -152,7 +164,7 @@ open class KotlinMultiplatformExtension : @Suppress("UNCHECKED_CAST") val rClassOutputJar = linkAppClass.getMethodOrNull("getRClassOutputJar")?.invoke(task) as Provider? - rClassOutputJar?.orNull?.asFile?.let { result += it } + rClassOutputJar?.orNull?.asFile?.let { result += AndroidDependency("R.jar", it) } } } @@ -164,15 +176,16 @@ open class KotlinMultiplatformExtension : private fun collectDependencies( module: ModuleIdentifier, compileClasspathConf: Configuration - ): List { + ): List { val viewConfig: (ArtifactView.ViewConfiguration) -> Unit = { config -> config.attributes { it.attribute(ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.JAR.type) } config.isLenient = true } val resolvedArtifacts = compileClasspathConf.incoming.artifactView(viewConfig).artifacts.mapNotNull { - val id = (it.id.componentIdentifier as? DefaultModuleComponentIdentifier)?.moduleIdentifier ?: return@mapNotNull null - id to it + val componentIdentifier = it.id.componentIdentifier as? ModuleComponentIdentifier ?: return@mapNotNull null + val id = componentIdentifier.moduleIdentifier ?: return@mapNotNull null + id to AndroidDependency(id.name, it.file, null, id.group, componentIdentifier.version) }.toMap() val resolutionResults = compileClasspathConf.incoming.resolutionResult.allComponents.mapNotNull { @@ -181,7 +194,7 @@ open class KotlinMultiplatformExtension : }.toMap() val deps = HashSet().also { doCollectDependencies(listOf(module), resolutionResults, it) } - return deps.mapNotNull { resolvedArtifacts[it] }.map { it.file } + return deps.mapNotNull { resolvedArtifacts[it] } } @Suppress("UnstableApiUsage")