[Gradle] Implement IdeResolveDependenciesTask

KT-54977
This commit is contained in:
Sebastian Sellmair
2022-11-29 15:45:02 +01:00
committed by Space Team
parent d268a7e117
commit 0ad45cc196
7 changed files with 125 additions and 3 deletions
@@ -49,6 +49,10 @@ data class IdeaKotlinProjectArtifactCoordinates(
val artifactFile: File
) : IdeaKotlinDependencyCoordinates {
override fun toString(): String {
return "$project${File.pathSeparator}$artifactFile"
}
internal companion object {
const val serialVersionUID = 0L
}
@@ -5,8 +5,12 @@
package org.jetbrains.kotlin.gradle.plugin.ide
import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.tooling.core.extrasKeyOf
import org.jetbrains.kotlin.tooling.core.getValue
import org.jetbrains.kotlin.tooling.core.setValue
fun interface IdeDependencyResolver {
fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency>
@@ -14,6 +18,11 @@ fun interface IdeDependencyResolver {
object Empty : IdeDependencyResolver {
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> = emptySet()
}
companion object {
var IdeaKotlinDependency.resolvedBy: IdeDependencyResolver? by extrasKeyOf("resolvedBy")
var IdeaKotlinDependency.gradleArtifact: ResolvedArtifactResult? by extrasKeyOf("gradleArtifact")
}
}
fun IdeDependencyResolver(
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationContext
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.kpm.idea.IdeaSerializationContext
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver.Companion.resolvedBy
import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.*
import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.Companion.logger
import org.jetbrains.kotlin.tooling.core.Extras
@@ -161,6 +162,7 @@ internal class IdeMultiplatformImportImpl(
return runCatching { resolver.resolve(sourceSet) }
.onFailure { error -> reportError(sourceSet, error) }
.onSuccess { dependencies -> reportSuccess(sourceSet, dependencies) }
.onSuccess { dependencies -> attachResolvedByExtra(dependencies) }
.getOrNull().orEmpty()
}
@@ -172,5 +174,12 @@ internal class IdeMultiplatformImportImpl(
if (!logger.isDebugEnabled) return
logger.debug("${resolver::class.java.name} resolved on ${IdeaKotlinSourceCoordinates(sourceSet)}: $dependencies")
}
private fun attachResolvedByExtra(dependencies: Iterable<IdeaKotlinDependency>) {
dependencies.forEach { dependency ->
if (dependency.resolvedBy == null) dependency.resolvedBy = resolver
}
}
}
}
@@ -0,0 +1,96 @@
/*
* Copyright 2010-2022 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.
*/
package org.jetbrains.kotlin.gradle.plugin.ide
import com.google.gson.*
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependencyCoordinates
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import org.jetbrains.kotlin.gradle.utils.notCompatibleWithConfigurationCacheCompat
import org.jetbrains.kotlin.tooling.core.Extras
import java.io.File
import java.lang.reflect.Type
internal fun Project.locateOrRegisterIdeResolveDependenciesTask(): TaskProvider<IdeResolveDependenciesTask> {
return locateOrRegisterTask("resolveIdeDependencies") { task ->
task.description = "Debugging/Diagnosing task that will resolve dependencies for the IDE"
task.group = "ide"
task.notCompatibleWithConfigurationCacheCompat("Just a debugging util")
}
}
/**
* Task intended to be use for debugging/diagnosing purposes.
* This will invoke the [IdeMultiplatformImport] to resolve all dependencies (like the IDE would).
* Outputs are written as json and protobufs
*/
internal open class IdeResolveDependenciesTask : DefaultTask() {
@TaskAction
fun resolveDependencies() {
val outputDirectory = project.buildDir.resolve("ide/dependencies")
outputDirectory.deleteRecursively()
val gson = GsonBuilder().setLenient().setPrettyPrinting()
.registerTypeHierarchyAdapter(IdeDependencyResolver::class.java, IdeDependencyResolverAdapter)
.registerTypeHierarchyAdapter(Extras::class.java, ExtrasAdapter)
.registerTypeHierarchyAdapter(IdeaKotlinDependencyCoordinates::class.java, IdeaKotlinDependencyCoordinatesAdapter)
.registerTypeAdapter(File::class.java, FileAdapter(project))
.create()
val extension = project.kotlinExtension
extension.sourceSets.forEach { sourceSet ->
val dependencies = project.kotlinIdeMultiplatformImport.resolveDependencies(sourceSet)
val jsonOutput = outputDirectory.resolve("json/${sourceSet.name}.json")
jsonOutput.parentFile.mkdirs()
jsonOutput.writeText(gson.toJson(dependencies))
project.kotlinIdeMultiplatformImport.serialize(dependencies).forEachIndexed { index, proto ->
val protoOutput = outputDirectory.resolve("proto/${sourceSet.name}/$index.bin")
protoOutput.parentFile.mkdirs()
protoOutput.writeBytes(proto)
}
}
}
private object IdeDependencyResolverAdapter : JsonSerializer<IdeDependencyResolver> {
override fun serialize(src: IdeDependencyResolver, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
return JsonPrimitive(src.javaClass.name)
}
}
private object IdeaKotlinDependencyCoordinatesAdapter : JsonSerializer<IdeaKotlinDependencyCoordinates> {
override fun serialize(src: IdeaKotlinDependencyCoordinates, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
return JsonPrimitive(src.toString())
}
}
private object ExtrasAdapter : JsonSerializer<Extras> {
override fun serialize(src: Extras, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
return JsonObject().apply {
src.entries.forEach { entry ->
val valueElement = runCatching { context.serialize(entry.value) }.getOrElse { JsonPrimitive(entry.value.toString()) }
add(entry.key.stableString, valueElement)
}
}
}
}
private class FileAdapter(private val project: Project) : JsonSerializer<File> {
override fun serialize(src: File, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
return if (src.startsWith(project.projectDir)) {
JsonPrimitive(src.relativeTo(project.projectDir).path)
} else if (src.startsWith(project.rootDir)) {
JsonPrimitive(src.relativeTo(project.rootDir).path)
} else {
JsonPrimitive(src.path)
}
}
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.gradle.idea.tcs.*
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver.Companion.gradleArtifact
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinBinaryCoordinates
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinProjectCoordinates
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataCompilation
@@ -119,7 +120,7 @@ internal class IdePlatformDependencyResolver(
logger.warn("Unhandled componentId: ${componentId.javaClass}")
null
}
}
}?.also { dependency -> dependency.gradleArtifact = artifact }
}.toSet()
return resolvedDependencies + unresolvedDependencies
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets.MetadataProvider.ArtifactMetadataProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.kotlinTransformedMetadataLibraryDirectoryForIde
@@ -26,7 +25,6 @@ internal object IdeTransformedMetadataDependencyResolver : IdeDependencyResolver
private fun resolve(sourceSet: KotlinSourceSet, resolution: ChooseVisibleSourceSets): Iterable<IdeaKotlinDependency> {
val metadataProvider = resolution.metadataProvider as? ArtifactMetadataProvider ?: return emptySet()
return metadataProvider.read { artifactContent ->
resolution.allVisibleSourceSetNames.mapNotNull { visibleSourceSet ->
val sourceSetContent = artifactContent.findSourceSet(visibleSourceSet) ?: return@mapNotNull null
@@ -18,6 +18,8 @@ import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.ide.IdeResolveDependenciesTask
import org.jetbrains.kotlin.gradle.plugin.ide.locateOrRegisterIdeResolveDependenciesTask
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin.Companion.sourceSetFreeCompilerArgsPropertyName
import org.jetbrains.kotlin.gradle.plugin.mpp.internal.handleHierarchicalStructureFlagsMigration
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
@@ -34,6 +36,7 @@ import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinWasmTargetPreset
import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.registerKotlinArtifactsExtension
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.*
@@ -76,6 +79,8 @@ class KotlinMultiplatformPlugin : Plugin<Project> {
project.pluginManager.apply(ScriptingGradleSubplugin::class.java)
exportProjectStructureMetadataForOtherBuilds(kotlinMultiplatformExtension)
project.locateOrRegisterIdeResolveDependenciesTask()
}
private fun exportProjectStructureMetadataForOtherBuilds(