mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] KTIJ-35769 add support for GradleDslBaseScriptModel
Merge-request: IJ-MR-173210 Merged-by: Vlad Koshkin <Vladislav.Koshkin@jetbrains.com> GitOrigin-RevId: c143b1fa121abff9feb27d81af7632dfdd607292
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ecb6d0fc54
commit
c304e71274
+42
@@ -167,6 +167,48 @@ public final class GradleExecutionHelper {
|
||||
return getBuildEnvironment(connection, context);
|
||||
}
|
||||
|
||||
public static <Model> @NotNull Model getModel(
|
||||
@NotNull ProjectConnection connection,
|
||||
@NotNull GradleExecutionContext context,
|
||||
@NotNull Class<Model> modelClass
|
||||
) {
|
||||
Span span = ExternalSystemTelemetryUtil.getTracer(GradleConstants.SYSTEM_ID)
|
||||
.spanBuilder("GetModel")
|
||||
.setAttribute("modelClass", modelClass.getName())
|
||||
.startSpan();
|
||||
try (Scope ignore = span.makeCurrent()) {
|
||||
ExternalSystemTaskId taskId = context.getTaskId();
|
||||
ExternalSystemTaskNotificationListener listener = context.getListener();
|
||||
|
||||
ModelBuilder<Model> modelBuilder = connection.model(modelClass);
|
||||
|
||||
modelBuilder.withCancellationToken(context.getCancellationToken());
|
||||
|
||||
setupJavaHome(modelBuilder, context.getSettings(), taskId, listener, null);
|
||||
|
||||
// do not use connection.getModel methods since it doesn't allow to handle progress events
|
||||
// and we can miss gradle tooling client side events like distribution download.
|
||||
GradleProgressListener gradleProgressListener = new GradleProgressListener(listener, taskId);
|
||||
modelBuilder.addProgressListener((ProgressListener)gradleProgressListener);
|
||||
modelBuilder.addProgressListener((org.gradle.tooling.events.ProgressListener)gradleProgressListener);
|
||||
modelBuilder.setStandardOutput(new OutputWrapper(listener, taskId, true));
|
||||
modelBuilder.setStandardError(new OutputWrapper(listener, taskId, false));
|
||||
|
||||
return modelBuilder.get();
|
||||
}
|
||||
catch (CancellationException ce) {
|
||||
throw ce;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
span.recordException(ex);
|
||||
span.setStatus(StatusCode.ERROR);
|
||||
throw new RuntimeException(String.format("Failed to obtain model %s from Gradle daemon.", modelClass.getSimpleName()), ex);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use the {@link GradleExecutionHelper#execute} function with {@link GradleExecutionContext} instead
|
||||
*/
|
||||
|
||||
+13
-1
@@ -53,7 +53,8 @@ class GradleIdeaModelHolder(
|
||||
}
|
||||
|
||||
fun <T> getRootModel(modelClazz: Class<T>): T? {
|
||||
return getBuildModel(getRootBuild(), modelClazz)
|
||||
return getModel(getRootModelId(modelClazz), modelClazz)
|
||||
?: rootBuild?.let { getBuildModel(it, modelClazz) }
|
||||
}
|
||||
|
||||
fun <T> getBuildModel(buildModel: BuildModel, modelClass: Class<T>): T? {
|
||||
@@ -99,6 +100,7 @@ class GradleIdeaModelHolder(
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
private fun <T : Any> deserializeModel(model: Any, modelId: GradleModelId, modelClass: Class<T>): T? {
|
||||
if (model !is ByteArray) {
|
||||
return null
|
||||
@@ -116,6 +118,12 @@ class GradleIdeaModelHolder(
|
||||
return deserializedModel
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun <T : Any> addRootModel(modelClass: Class<T>, model: T) {
|
||||
val modelId = getRootModelId(modelClass)
|
||||
models[modelId] = model
|
||||
}
|
||||
|
||||
fun addState(state: GradleModelHolderState) {
|
||||
val rootBuild = state.rootBuild
|
||||
val nestedBuilds = state.nestedBuilds
|
||||
@@ -166,6 +174,10 @@ class GradleIdeaModelHolder(
|
||||
return GradleModelId(modelId.classId, originalBuildId, modelId.projectId)
|
||||
}
|
||||
|
||||
private fun getRootModelId(modelClass: Class<*>): GradleModelId {
|
||||
return GradleModelId.createRootModelId(modelClass)
|
||||
}
|
||||
|
||||
private fun getBuildModelId(buildModel: BuildModel, modelClass: Class<*>): GradleModelId {
|
||||
val modelId = GradleModelId.createBuildModelId(buildModel, modelClass)
|
||||
return applyBuildIdMapping(modelId)
|
||||
|
||||
+7
@@ -44,6 +44,7 @@ import org.gradle.tooling.GradleConnector;
|
||||
import org.gradle.tooling.ProjectConnection;
|
||||
import org.gradle.tooling.model.ProjectModel;
|
||||
import org.gradle.tooling.model.build.BuildEnvironment;
|
||||
import org.gradle.tooling.model.dsl.GradleDslBaseScriptModel;
|
||||
import org.gradle.tooling.model.idea.IdeaModule;
|
||||
import org.gradle.tooling.model.idea.IdeaProject;
|
||||
import org.jetbrains.annotations.*;
|
||||
@@ -282,6 +283,12 @@ public final class GradleProjectResolver implements ExternalSystemProjectResolve
|
||||
.spanBuilder("GradleCall")
|
||||
.startSpan();
|
||||
try (Scope ignore = gradleCallSpan.makeCurrent()) {
|
||||
if (GradleVersionUtil.isGradleAtLeast(resolverContext.getGradleVersion(), "9.2")) {
|
||||
var scriptModel = GradleExecutionHelper.getModel(connection, resolverContext, GradleDslBaseScriptModel.class);
|
||||
models.addRootModel(GradleDslBaseScriptModel.class, scriptModel);
|
||||
GradleSyncProjectConfigurator.runScriptBasePhase(resolverContext);
|
||||
}
|
||||
|
||||
var modelFetchActionResultHandler = GradleSyncProjectConfigurator.createModelFetchResultHandler(resolverContext);
|
||||
GradleModelFetchActionRunner.runAndTraceBuildAction(connection, resolverContext, buildAction, modelFetchActionResultHandler);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ sealed interface GradleSyncPhase : Comparable<GradleSyncPhase> {
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
sealed interface BaseScript: GradleSyncPhase
|
||||
|
||||
/**
|
||||
* In these phases, Gradle sync contributors are executed when models for [modelFetchPhase] are collected on the Gradle daemon side.
|
||||
*/
|
||||
@@ -61,6 +64,13 @@ sealed interface GradleSyncPhase : Comparable<GradleSyncPhase> {
|
||||
@JvmField
|
||||
val DECLARATIVE_PHASE: GradleSyncPhase = Static(1000, "DECLARATIVE_PHASE")
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@JvmField
|
||||
@ApiStatus.Internal
|
||||
val BASE_SCRIPT_MODEL_PHASE: GradleSyncPhase = GradleBaseScriptSyncPhase
|
||||
|
||||
/**
|
||||
* In this phase, Gradle sync contributors,
|
||||
* contribute to the IDE module and content root structure for each Gradle project.
|
||||
@@ -82,6 +92,12 @@ sealed interface GradleSyncPhase : Comparable<GradleSyncPhase> {
|
||||
@JvmField
|
||||
val DEPENDENCY_MODEL_PHASE: GradleSyncPhase = GradleModelFetchPhase.PROJECT_SOURCE_SET_DEPENDENCY_PHASE.asSyncPhase()
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@JvmField
|
||||
val SCRIPT_MODEL_PHASE: GradleSyncPhase = GradleModelFetchPhase.SCRIPT_MODEL_PHASE.asSyncPhase()
|
||||
|
||||
/**
|
||||
* In this phase, Gradle sync contributors,
|
||||
* contribute to the IDE project model for a rich experience in IntelliJ IDEA.
|
||||
@@ -105,6 +121,7 @@ private class GradleStaticSyncPhase(
|
||||
override fun compareTo(other: GradleSyncPhase): Int {
|
||||
return when (other) {
|
||||
is GradleStaticSyncPhase -> order.compareTo(other.order)
|
||||
is GradleBaseScriptSyncPhase -> -1
|
||||
is GradleDynamicSyncPhase -> -1
|
||||
}
|
||||
}
|
||||
@@ -134,6 +151,7 @@ private class GradleDynamicSyncPhase(
|
||||
override fun compareTo(other: GradleSyncPhase): Int {
|
||||
return when (other) {
|
||||
is GradleStaticSyncPhase -> 1
|
||||
is GradleBaseScriptSyncPhase -> 1
|
||||
is GradleDynamicSyncPhase -> modelFetchPhase.compareTo(other.modelFetchPhase)
|
||||
}
|
||||
}
|
||||
@@ -150,4 +168,17 @@ private class GradleDynamicSyncPhase(
|
||||
override fun hashCode(): Int {
|
||||
return modelFetchPhase.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
private data object GradleBaseScriptSyncPhase: GradleSyncPhase.BaseScript {
|
||||
|
||||
override val name: String = "BASE_SCRIPT_MODEL"
|
||||
|
||||
override fun compareTo(other: GradleSyncPhase): Int {
|
||||
return when (other) {
|
||||
is GradleStaticSyncPhase -> 1
|
||||
is GradleBaseScriptSyncPhase -> 0
|
||||
is GradleDynamicSyncPhase -> -1
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -40,6 +40,16 @@ object GradleSyncProjectConfigurator {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun runScriptBasePhase(context: ProjectResolverContext) {
|
||||
require(!application.isWriteAccessAllowed) {
|
||||
"Must not execute inside write action"
|
||||
}
|
||||
runBlockingCancellable {
|
||||
GradleSyncActionRunner().performSyncContributors(context) { it is GradleSyncPhase.BaseScript }
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createModelFetchResultHandler(context: ProjectResolverContext): GradleModelFetchActionListener {
|
||||
return object : GradleModelFetchActionListener {
|
||||
|
||||
+2
@@ -490,6 +490,8 @@ class GradleOutputParsersMessagesImportingTest : GradleOutputParsersMessagesImpo
|
||||
val text = it.lineSequence()
|
||||
.dropWhile { s -> s == "Starting Gradle Daemon..."
|
||||
|| s.startsWith("Gradle Daemon started in")
|
||||
|| s == ""
|
||||
|| s.startsWith("CONFIGURE SUCCESSFUL")
|
||||
|| s.startsWith("Download ") }
|
||||
.joinToString(separator = "\n")
|
||||
|
||||
|
||||
+8
@@ -174,6 +174,7 @@ class GradlePhasedSyncTest : GradlePhasedSyncTestCase() {
|
||||
val syncPhaseCompletionAssertions = ListenerAssertion()
|
||||
|
||||
val allPhases = DEFAULT_SYNC_PHASES
|
||||
val allStaticPhases = allPhases.filterIsInstance<GradleSyncPhase.Static>()
|
||||
val allDynamicPhases = allPhases.filterIsInstance<GradleSyncPhase.Dynamic>()
|
||||
val completedPhases = CopyOnWriteArrayList<GradleSyncPhase>()
|
||||
|
||||
@@ -192,12 +193,17 @@ class GradlePhasedSyncTest : GradlePhasedSyncTestCase() {
|
||||
whenSyncPhaseCompleted(phase, disposable) { _ ->
|
||||
syncPhaseCompletionAssertions.trace {
|
||||
val completedStaticPhases = completedPhases.filterIsInstance<GradleSyncPhase.Static>()
|
||||
val completedBaseScriptPhases = completedPhases.filterIsInstance<GradleSyncPhase.BaseScript>()
|
||||
val completedDynamicPhases = completedPhases.filterIsInstance<GradleSyncPhase.Dynamic>()
|
||||
val expectedEntities = when (phase) {
|
||||
is GradleSyncPhase.Static -> when (isSecondarySync) {
|
||||
true -> completedStaticPhases + allDynamicPhases
|
||||
else -> completedStaticPhases
|
||||
}
|
||||
is GradleSyncPhase.BaseScript -> when (isSecondarySync) {
|
||||
true -> allStaticPhases + completedBaseScriptPhases + allDynamicPhases
|
||||
else -> completedBaseScriptPhases
|
||||
}
|
||||
is GradleSyncPhase.Dynamic -> when (isSecondarySync) {
|
||||
true -> allDynamicPhases
|
||||
else -> completedDynamicPhases
|
||||
@@ -259,9 +265,11 @@ class GradlePhasedSyncTest : GradlePhasedSyncTestCase() {
|
||||
whenSyncPhaseCompleted(phase, disposable) { _ ->
|
||||
syncPhaseCompletionAssertions.trace {
|
||||
val completedStaticPhases = completedPhases.filterIsInstance<GradleSyncPhase.Static>()
|
||||
val completedBaseScriptPhases = completedPhases.filterIsInstance<GradleSyncPhase.BaseScript>()
|
||||
val completedDynamicPhases = completedPhases.filterIsInstance<GradleSyncPhase.Dynamic>()
|
||||
val expectedEntities = when (phase) {
|
||||
is GradleSyncPhase.Static -> completedStaticPhases
|
||||
is GradleSyncPhase.BaseScript -> completedBaseScriptPhases
|
||||
is GradleSyncPhase.Dynamic -> completedDynamicPhases
|
||||
}
|
||||
WorkspaceAssertions.assertEntities(myProject, expectedEntities.map { GradleTestEntityId(it) }) {
|
||||
|
||||
+7
-1
@@ -79,13 +79,19 @@ sealed interface GradleModelFetchPhase : Comparable<GradleModelFetchPhase>, Seri
|
||||
@JvmField
|
||||
val PROJECT_SOURCE_SET_DEPENDENCY_PHASE: GradleModelFetchPhase = BuildFinished(2000, "DEPENDENCY_MODEL_PHASE")
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@JvmField
|
||||
val SCRIPT_MODEL_PHASE: GradleModelFetchPhase = BuildFinished(3000, "SCRIPT_MODEL_PHASE")
|
||||
|
||||
/**
|
||||
* In this phase, Gradle model providers fetch rest of Gradle models, which needed for rich experience in IntelliJ IDEA.
|
||||
* It is a code insight in Gradle scripts, data for run configuration creation and for code completion in him,
|
||||
* data for code profiling, etc.
|
||||
*/
|
||||
@JvmField
|
||||
val ADDITIONAL_MODEL_PHASE: GradleModelFetchPhase = BuildFinished(3000, "ADDITIONAL_MODEL_PHASE")
|
||||
val ADDITIONAL_MODEL_PHASE: GradleModelFetchPhase = BuildFinished(4000, "ADDITIONAL_MODEL_PHASE")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -70,6 +70,12 @@ public final class GradleModelId implements Serializable {
|
||||
return new GradleModelId(classId, buildId, projectId);
|
||||
}
|
||||
|
||||
public static @NotNull GradleModelId createRootModelId(@NotNull Class<?> modelClass) {
|
||||
String classId = createClassId(modelClass);
|
||||
String projectId = ":";
|
||||
return new GradleModelId(classId, "", projectId);
|
||||
}
|
||||
|
||||
public static @NotNull GradleModelId createProjectModelId(@NotNull ProjectModel projectModel, @NotNull Class<?> modelClass) {
|
||||
ProjectIdentifier projectIdentifier = getProjectIdentifier(projectModel);
|
||||
BuildIdentifier buildIdentifier = projectIdentifier.getBuildIdentifier();
|
||||
|
||||
@@ -63,6 +63,7 @@ jvm_library(
|
||||
"//plugins/kotlin/base/scripting/scripting.shared",
|
||||
"//plugins/kotlin/highlighting/highlighting-shared:kotlin-highlighting-shared",
|
||||
"//platform/lang-core",
|
||||
"//platform/backend/observation",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -130,6 +131,8 @@ jvm_library(
|
||||
"//platform/testFramework",
|
||||
"//platform/testFramework:testFramework_test_lib",
|
||||
"//plugins/kotlin/base/test:test_test_lib",
|
||||
"//platform/backend/observation",
|
||||
"//platform/backend/observation:observation_test_lib",
|
||||
]
|
||||
)
|
||||
### auto-generated section `build intellij.kotlin.base.scripting` end
|
||||
|
||||
@@ -63,5 +63,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.lang.core" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.base.test" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.backend.observation" />
|
||||
</component>
|
||||
</module>
|
||||
+20
-11
@@ -8,17 +8,19 @@ import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.relativizeToClosestAncestor
|
||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||
import com.intellij.platform.backend.observation.launchTracked
|
||||
import com.intellij.util.application
|
||||
import com.intellij.util.concurrency.ThreadingAssertions
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.kotlin.analysis.api.platform.modification.publishGlobalModuleStateModificationEvent
|
||||
import org.jetbrains.kotlin.analysis.api.platform.modification.publishGlobalScriptModuleStateModificationEvent
|
||||
import org.jetbrains.kotlin.idea.core.script.k2.configurations.getConfigurationResolver
|
||||
import org.jetbrains.kotlin.idea.core.script.k2.configurations.getWorkspaceModelManager
|
||||
import org.jetbrains.kotlin.idea.core.script.k2.highlighting.KotlinScriptResolutionService.Companion.dropKotlinScriptCaches
|
||||
import org.jetbrains.kotlin.idea.core.script.k2.highlighting.KotlinScriptResolutionService.Companion.dropKotlinScriptCachesUnderWriteAction
|
||||
import org.jetbrains.kotlin.idea.core.script.shared.KotlinScriptProcessingFilter
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.ScriptDependenciesModificationTracker
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.alwaysVirtualFile
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.awaitExternalSystemInitialization
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.scriptingDebugLog
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
@@ -56,7 +58,8 @@ class KotlinScriptResolutionService(
|
||||
* @param ktFile the Kotlin script to be processed.
|
||||
*/
|
||||
fun launchProcessing(ktFile: KtFile) {
|
||||
coroutineScope.launch {
|
||||
coroutineScope.launchTracked {
|
||||
project.awaitExternalSystemInitialization()
|
||||
process(listOf(ktFile))
|
||||
}
|
||||
}
|
||||
@@ -112,7 +115,7 @@ class KotlinScriptResolutionService(
|
||||
* - Tries to get an existing configuration for the file; if absent, creates it.
|
||||
* - Accumulates configurations and applies them to the workspace model in a single batch update.
|
||||
*
|
||||
* After updating the model, Kotlin script-related caches are dropped via [dropKotlinScriptCaches].
|
||||
* After updating the model, Kotlin script-related caches are dropped via [dropKotlinScriptCachesUnderWriteAction].
|
||||
*
|
||||
* @param definitionByFile mapping of script files to their resolved [ScriptDefinition].
|
||||
*/
|
||||
@@ -128,23 +131,29 @@ class KotlinScriptResolutionService(
|
||||
}
|
||||
|
||||
assert(!application.isWriteAccessAllowed)
|
||||
projectModelUpdater.updateWorkspaceModel(configurationPerVirtualFile)
|
||||
|
||||
dropKotlinScriptCaches(project)
|
||||
dropKotlinScriptCachesUnderWriteAction(project)
|
||||
projectModelUpdater.updateWorkspaceModel(configurationPerVirtualFile)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): KotlinScriptResolutionService = project.service()
|
||||
|
||||
suspend fun dropKotlinScriptCaches(project: Project) {
|
||||
suspend fun dropKotlinScriptCachesUnderWriteAction(project: Project) {
|
||||
edtWriteAction {
|
||||
dropKotlinScriptCaches(project)
|
||||
}
|
||||
}
|
||||
|
||||
fun dropKotlinScriptCaches(project: Project) {
|
||||
ThreadingAssertions.assertWriteAccess()
|
||||
|
||||
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
|
||||
HighlightingSettingsPerFile.getInstance(project).incModificationCount()
|
||||
|
||||
edtWriteAction {
|
||||
project.publishGlobalModuleStateModificationEvent()
|
||||
project.publishGlobalScriptModuleStateModificationEvent()
|
||||
}
|
||||
project.publishGlobalModuleStateModificationEvent()
|
||||
project.publishGlobalScriptModuleStateModificationEvent()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,8 @@ jvm_library(
|
||||
"//plugins/kotlin/highlighting/highlighting-shared:kotlin-highlighting-shared",
|
||||
"//java/java-psi-impl:psi-impl",
|
||||
"//platform/indexing-api:indexing",
|
||||
"//platform/external-system-impl:externalSystem-impl",
|
||||
"//platform/external-system-api:externalSystem",
|
||||
]
|
||||
)
|
||||
### auto-generated section `build intellij.kotlin.base.scripting.shared` end
|
||||
+2
@@ -35,5 +35,7 @@
|
||||
<orderEntry type="module" module-name="kotlin.highlighting.shared" />
|
||||
<orderEntry type="module" module-name="intellij.java.psi.impl" />
|
||||
<orderEntry type="module" module-name="intellij.platform.indexing" />
|
||||
<orderEntry type="module" module-name="intellij.platform.externalSystem.impl" />
|
||||
<orderEntry type="module" module-name="intellij.platform.externalSystem" />
|
||||
</component>
|
||||
</module>
|
||||
+11
@@ -5,11 +5,14 @@ package org.jetbrains.kotlin.idea.core.script.v1
|
||||
import com.intellij.openapi.application.Application
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
@@ -67,4 +70,12 @@ fun Project.getKtFile(virtualFile: VirtualFile?, ktFile: KtFile? = null): KtFile
|
||||
} else {
|
||||
return runReadAction { PsiManager.getInstance(this).findFile(virtualFile) as? KtFile }
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun Project.awaitExternalSystemInitialization() {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
ExternalProjectsManagerImpl.getInstance(this).runWhenInitialized {
|
||||
continuation.resumeWith(Result.success(Unit))
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.k2.codeInsight.gradle.navigation
|
||||
|
||||
import org.jetbrains.kotlin.gradle.AbstractKotlinGradleResilientHighlightingTest
|
||||
import org.jetbrains.kotlin.idea.test.AssertKotlinPluginMode
|
||||
import org.jetbrains.kotlin.idea.test.UseK2PluginMode
|
||||
import org.jetbrains.plugins.gradle.testFramework.fixtures.application.GradleProjectTestApplication
|
||||
|
||||
@UseK2PluginMode
|
||||
@GradleProjectTestApplication
|
||||
@AssertKotlinPluginMode
|
||||
class K2GradleResilientHighlightingTest : AbstractKotlinGradleResilientHighlightingTest()
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import com.intellij.testFramework.runInEdtAndWait
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.idea.base.plugin.useK2Plugin
|
||||
import org.jetbrains.kotlin.idea.base.test.IgnoreTests
|
||||
import org.jetbrains.kotlin.idea.base.test.TestRoot
|
||||
import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.HighlightingConfiguration
|
||||
import org.jetbrains.kotlin.idea.highlighter.CHECK_SYMBOL_NAMES
|
||||
import org.jetbrains.kotlin.idea.highlighter.checkHighlighting
|
||||
import org.jetbrains.kotlin.idea.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestMetadata
|
||||
import org.jetbrains.plugins.gradle.frameworkSupport.GradleDsl
|
||||
import org.jetbrains.plugins.gradle.testFramework.GradleTestFixtureBuilder
|
||||
import org.jetbrains.plugins.gradle.testFramework.annotations.BaseGradleVersionSource
|
||||
import org.jetbrains.plugins.gradle.testFramework.util.withBuildFile
|
||||
import org.jetbrains.plugins.gradle.testFramework.util.withSettingsFile
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import java.io.File
|
||||
|
||||
@TestRoot("idea/tests/testData/")
|
||||
@TestDataPath($$"$CONTENT_ROOT")
|
||||
@TestMetadata("../../../idea/tests/testData/gradle/highlighting/")
|
||||
abstract class AbstractKotlinGradleResilientHighlightingTest : AbstractGradleCodeInsightTest() {
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
@TestMetadata("resilient/simple.test")
|
||||
fun testSimple(gradleVersion: GradleVersion) {
|
||||
verifyHighlighting(gradleVersion)
|
||||
}
|
||||
|
||||
private val outputFileExtensions: List<String> = listOfNotNull(".highlighting.k2".takeIf { useK2Plugin == true }, ".highlighting")
|
||||
|
||||
private fun verifyHighlighting(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, GRADLE_KOTLIN_FIXTURE_WITH_ERROR) {
|
||||
val mainFile = mainTestDataPsiFile
|
||||
|
||||
val ktsFileUnderTest = mainFile.virtualFile.toNioPath().toFile()
|
||||
val path = ktsFileUnderTest.path
|
||||
val ktsFileHighlighting = outputFileExtensions.firstNotNullOfOrNull { ext ->
|
||||
val resolveSibling = ktsFileUnderTest.resolveSibling("$path$ext")
|
||||
resolveSibling.takeIf(File::exists)
|
||||
} ?: error("highlighting file does not exist for ${ktsFileUnderTest.path}")
|
||||
|
||||
val directives = KotlinTestUtils.parseDirectives(mainTestDataFile.content).also {
|
||||
it.put(CHECK_SYMBOL_NAMES, true.toString())
|
||||
}
|
||||
|
||||
runInEdtAndWait {
|
||||
IgnoreTests.runTestIfNotDisabledByFileDirective(
|
||||
mainFile.virtualFile.toNioPath(),
|
||||
if (useK2Plugin == true) IgnoreTests.DIRECTIVES.IGNORE_K2 else IgnoreTests.DIRECTIVES.IGNORE_K1
|
||||
) {
|
||||
checkHighlighting(
|
||||
mainFile,
|
||||
ktsFileHighlighting,
|
||||
directives,
|
||||
project,
|
||||
highlightWarnings = true,
|
||||
severityOption = HighlightingConfiguration.SeverityRenderingOption.ALWAYS
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val GRADLE_KOTLIN_FIXTURE_WITH_ERROR: GradleTestFixtureBuilder = GradleTestFixtureBuilder.create("GradleKotlinFixture") { gradleVersion ->
|
||||
withSettingsFile(gradleVersion, gradleDsl = GradleDsl.KOTLIN) {
|
||||
setProjectName("GradleKotlinFixture")
|
||||
include(":module1")
|
||||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||
}
|
||||
withBuildFile(gradleVersion, gradleDsl = GradleDsl.KOTLIN) {
|
||||
call("some-error-code")
|
||||
}
|
||||
withBuildFile(gradleVersion, "module1", gradleDsl = GradleDsl.KOTLIN) {
|
||||
withKotlinDsl()
|
||||
withMavenCentral()
|
||||
}
|
||||
withFile(
|
||||
"gradle.properties", """
|
||||
kotlin.code.style=official
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+4
@@ -2,6 +2,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.gradleTooling
|
||||
|
||||
import com.intellij.gradle.toolingExtension.modelAction.GradleModelFetchPhase
|
||||
import org.gradle.tooling.BuildController
|
||||
import org.gradle.tooling.model.gradle.GradleBuild
|
||||
import org.gradle.tooling.model.kotlin.dsl.KotlinDslScriptsModel
|
||||
@@ -9,8 +10,11 @@ import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider
|
||||
import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider.GradleModelConsumer
|
||||
|
||||
class KotlinDslScriptModelProvider : ProjectImportModelProvider {
|
||||
|
||||
private val kotlinDslScriptModelClass: Class<*> = KotlinDslScriptsModel::class.java
|
||||
|
||||
override fun getPhase(): GradleModelFetchPhase = GradleModelFetchPhase.SCRIPT_MODEL_PHASE
|
||||
|
||||
override fun populateModels(
|
||||
controller: BuildController,
|
||||
buildModels: Collection<GradleBuild>,
|
||||
|
||||
+3
-2
@@ -6,9 +6,10 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.gradle.scripting.k1.roots.GradleBuildRootsLocatorImpl
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.GradleDefinitionsParams
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.KotlinGradleScriptingBundle
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.ErrorGradleScriptDefinition
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.GradleDefinitionsParams
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.loadGradleDefinitions
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.GradleBuildRootsLocator
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.Imported
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.WithoutScriptModels
|
||||
@@ -124,7 +125,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return org.jetbrains.kotlin.gradle.scripting.shared.loadGradleDefinitions(
|
||||
return loadGradleDefinitions(
|
||||
GradleDefinitionsParams(
|
||||
workingDir = root.workingDir,
|
||||
gradleHome = root.gradleHome,
|
||||
|
||||
+7
-34
@@ -3,26 +3,21 @@ package org.jetbrains.kotlin.gradle.scripting.k1.roots
|
||||
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.util.io.DataExternalizer
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.GradleKotlinScriptConfigurationInputs
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.importing.KotlinDslScriptModel
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.*
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.readString
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.AbstractGradleBuildRootDataSerializer
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.GradleBuildRootData
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.StringsPool
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.writeList
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.writeString
|
||||
import java.io.DataInput
|
||||
import java.io.DataOutput
|
||||
|
||||
class GradleBuildRootDataSerializer : AbstractGradleBuildRootDataSerializer() {
|
||||
override val externalizer: DataExternalizer<GradleBuildRootData>
|
||||
get() = object : DataExternalizer<GradleBuildRootData> {
|
||||
override fun save(out: DataOutput, value: GradleBuildRootData) =
|
||||
writeKotlinDslScriptModels(out, value)
|
||||
|
||||
override fun read(`in`: DataInput): GradleBuildRootData =
|
||||
readKotlinDslScriptModels(`in`, currentBuildRoot.get().path)
|
||||
override fun getExternalizer(): DataExternalizer<GradleBuildRootData> = object : DataExternalizer<GradleBuildRootData> {
|
||||
override fun save(out: DataOutput, value: GradleBuildRootData) = writeKotlinDslScriptModels(out, value)
|
||||
override fun read(`in`: DataInput): GradleBuildRootData = readKotlinDslScriptModels(`in`, currentBuildRoot.get().path)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@IntellijInternalApi
|
||||
fun writeKotlinDslScriptModels(output: DataOutput, data: GradleBuildRootData) {
|
||||
val strings = StringsPool.writer(output)
|
||||
@@ -49,28 +44,6 @@ class GradleBuildRootDataSerializer : AbstractGradleBuildRootDataSerializer() {
|
||||
strings.writeStringIds(it.imports)
|
||||
}
|
||||
}
|
||||
|
||||
@IntellijInternalApi
|
||||
fun readKotlinDslScriptModels(input: DataInput, buildRoot: String): GradleBuildRootData {
|
||||
val strings = StringsPool.reader(input)
|
||||
|
||||
val importTs = input.readLong()
|
||||
val projectRoots = strings.readStrings()
|
||||
val gradleHome = strings.readString()
|
||||
val javaHome = strings.readNullableString()
|
||||
val models = input.readList {
|
||||
KotlinDslScriptModel(
|
||||
strings.readString(),
|
||||
GradleKotlinScriptConfigurationInputs(input.readString(), input.readLong(), buildRoot),
|
||||
strings.readStrings(),
|
||||
strings.readStrings(),
|
||||
strings.readStrings(),
|
||||
listOf()
|
||||
)
|
||||
}
|
||||
|
||||
return GradleBuildRootData(importTs, projectRoots, gradleHome, javaHome, models)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+13
-2
@@ -16,7 +16,8 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.kotlin.gradle.scripting.k1.GradleScriptDefinitionsContributor
|
||||
import org.jetbrains.kotlin.gradle.scripting.k1.roots.GradleScriptingSupport.Companion.isApplicable
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.getDefinitionsTemplateClasspath
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.getFullDefinitionsClasspath
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.toGradleHomePath
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.importing.KotlinDslScriptModel
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.kotlinDslScriptsModelImportSupported
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.*
|
||||
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.idea.core.script.k1.configuration.DefaultScriptingSu
|
||||
import org.jetbrains.kotlin.idea.core.script.k1.configuration.ScriptingSupport
|
||||
import org.jetbrains.kotlin.idea.core.script.k1.settings.KotlinScriptingSettingsImpl
|
||||
import org.jetbrains.kotlin.idea.core.script.k1.ucache.ScriptClassRootsBuilder
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.scriptingInfoLog
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||
@@ -35,6 +37,7 @@ import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.io.path.invariantSeparatorsPathString
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.gradle.scripting.shared.roots.GradleBuildRoot] is a linked gradle build (don't confuse with gradle project and included build).
|
||||
@@ -330,10 +333,18 @@ class GradleScriptingSupport(val project: Project) : ScriptingSupport {
|
||||
return definitions.firstOrNull { it.isScript(scriptSource) }
|
||||
}
|
||||
|
||||
private fun getDefinitionsTemplateClasspath(gradleHome: String?): List<String> = try {
|
||||
getFullDefinitionsClasspath(gradleHome.toGradleHomePath()).map { it.invariantSeparatorsPathString }
|
||||
} catch (e: Throwable) {
|
||||
scriptingInfoLog("cannot get gradle classpath for Gradle Kotlin DSL scripts: ${e.message}")
|
||||
|
||||
emptyList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun isApplicable(file: VirtualFile, project: Project): Boolean {
|
||||
val support = ScriptingSupport.EP_NAME.findExtension(GradleScriptingSupport::class.java, project) ?: return false
|
||||
return support.isApplicable(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle.scripting.k1.gradle
|
||||
import org.jetbrains.kotlin.gradle.scripting.k1.roots.GradleBuildRootDataSerializer
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.GradleKotlinScriptConfigurationInputs
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.importing.KotlinDslScriptModel
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.AbstractGradleBuildRootDataSerializer
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.GradleBuildRootData
|
||||
import org.junit.Test
|
||||
import java.io.ByteArrayInputStream
|
||||
@@ -44,7 +45,7 @@ class GradleBuildRootDataSerializerTest {
|
||||
val buffer = ByteArrayOutputStream()
|
||||
GradleBuildRootDataSerializer.writeKotlinDslScriptModels(DataOutputStream(buffer), data)
|
||||
|
||||
val restored = GradleBuildRootDataSerializer.readKotlinDslScriptModels(DataInputStream(ByteArrayInputStream(buffer.toByteArray())), "a")
|
||||
val restored = AbstractGradleBuildRootDataSerializer.readKotlinDslScriptModels(DataInputStream(ByteArrayInputStream(buffer.toByteArray())), "a")
|
||||
|
||||
assertEquals(data.toString(), restored.toString())
|
||||
}
|
||||
@@ -62,7 +63,7 @@ class GradleBuildRootDataSerializerTest {
|
||||
val buffer = ByteArrayOutputStream()
|
||||
GradleBuildRootDataSerializer.writeKotlinDslScriptModels(DataOutputStream(buffer), data)
|
||||
|
||||
val restored = GradleBuildRootDataSerializer.readKotlinDslScriptModels(DataInputStream(ByteArrayInputStream(buffer.toByteArray())), "a")
|
||||
val restored = AbstractGradleBuildRootDataSerializer.readKotlinDslScriptModels(DataInputStream(ByteArrayInputStream(buffer.toByteArray())), "a")
|
||||
|
||||
assertEquals(data.toString(), restored.toString())
|
||||
}
|
||||
|
||||
+1
@@ -3,6 +3,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel
|
||||
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.platform.workspace.storage.*
|
||||
import org.jetbrains.kotlin.idea.core.script.k2.modules.ScriptCompilationConfigurationEntity
|
||||
import org.jetbrains.kotlin.idea.core.script.k2.modules.ScriptEvaluationConfigurationEntity
|
||||
|
||||
+1
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.impl
|
||||
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.platform.workspace.storage.*
|
||||
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
|
||||
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
|
||||
|
||||
+13
@@ -16,6 +16,16 @@ internal object MetadataStorageImpl : MetadataStorageBase() {
|
||||
|
||||
var typeMetadata: StorageTypeMetadata
|
||||
|
||||
typeMetadata = FinalClassMetadata.ObjectMetadata(
|
||||
fqName = "org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.KotlinGradleScriptEntitySource", properties = listOf(
|
||||
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "virtualFileUrl",
|
||||
valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = true,
|
||||
typeMetadata = FinalClassMetadata.KnownClass(
|
||||
fqName = "com.intellij.platform.workspace.storage.url.VirtualFileUrl")),
|
||||
withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.EntitySource"))
|
||||
|
||||
addMetadata(typeMetadata)
|
||||
|
||||
typeMetadata = FinalClassMetadata.ClassMetadata(
|
||||
fqName = "org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.GradleScriptDefinitionEntityId", properties = listOf(
|
||||
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "id", valueType = primitiveTypeStringNotNullable,
|
||||
@@ -128,6 +138,9 @@ internal object MetadataStorageImpl : MetadataStorageBase() {
|
||||
metadataHash = -362496579)
|
||||
addMetadataHash(typeFqn = "org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.GradleScriptDefinitionEntityId",
|
||||
metadataHash = -1956757513)
|
||||
addMetadataHash(typeFqn = "com.intellij.platform.workspace.storage.EntitySource", metadataHash = 1287228111)
|
||||
addMetadataHash(typeFqn = "org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.KotlinGradleScriptEntitySource",
|
||||
metadataHash = -532489477)
|
||||
addMetadataHash(typeFqn = "com.intellij.platform.workspace.storage.SymbolicEntityId", metadataHash = 1136338439)
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -16,6 +16,7 @@
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||
<syncExtension implementation="org.jetbrains.kotlin.gradle.scripting.k2.importing.KotlinDslScriptSyncExtension"/>
|
||||
<syncContributor implementation="org.jetbrains.kotlin.gradle.scripting.k2.importing.KotlinDslBaseScriptSyncContributor"/>
|
||||
<syncContributor implementation="org.jetbrains.kotlin.gradle.scripting.k2.importing.KotlinDslScriptSyncContributor"/>
|
||||
</extensions>
|
||||
|
||||
|
||||
+99
-95
@@ -18,16 +18,17 @@ import com.intellij.platform.workspace.storage.MutableEntityStorage
|
||||
import com.intellij.platform.workspace.storage.VersionedStorageChange
|
||||
import com.intellij.platform.workspace.storage.toBuilder
|
||||
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
|
||||
import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.definition.withIdeKeys
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.importing.GradleScriptData
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.importing.GradleScriptModel
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.GradleScriptDefinitionEntity
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.KotlinGradleScriptEntitySource
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.asEntity
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.deserialize
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.KotlinGradleScriptEntitySource
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.GradleScriptDefinition
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.loadGradleDefinitions
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.loadGradleDefinitions
|
||||
import org.jetbrains.kotlin.idea.core.script.k2.configurations.sdkId
|
||||
import org.jetbrains.kotlin.idea.core.script.k2.configurations.toVirtualFileUrl
|
||||
import org.jetbrains.kotlin.idea.core.script.k2.definitions.ScriptDefinitionsModificationTracker
|
||||
@@ -37,7 +38,6 @@ import org.jetbrains.kotlin.idea.core.script.v1.indexSourceRootsEagerly
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.scriptingDebugLog
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.scriptingWarnLog
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.*
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.io.File
|
||||
@@ -48,65 +48,91 @@ import kotlin.script.experimental.jvm.JvmDependency
|
||||
import kotlin.script.experimental.jvm.jdkHome
|
||||
import kotlin.script.experimental.jvm.jvm
|
||||
|
||||
private sealed interface CachedCompilationConfigurationResult {
|
||||
data class Some(val value: ScriptCompilationConfigurationResult) : CachedCompilationConfigurationResult
|
||||
data object None : CachedCompilationConfigurationResult
|
||||
}
|
||||
|
||||
private fun ScriptCompilationConfigurationResult?.cached(): CachedCompilationConfigurationResult =
|
||||
if (this == null) CachedCompilationConfigurationResult.None else CachedCompilationConfigurationResult.Some(this)
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
class GradleKotlinScriptService(val project: Project) : ScriptRefinedConfigurationResolver, ScriptWorkspaceModelManager {
|
||||
private val data = ConcurrentHashMap<VirtualFileUrl, ScriptCompilationConfigurationResult>()
|
||||
private val data = ConcurrentHashMap<VirtualFileUrl, CachedCompilationConfigurationResult>()
|
||||
|
||||
override suspend fun create(virtualFile: VirtualFile, definition: ScriptDefinition): ScriptCompilationConfigurationResult? = null
|
||||
private val urlManager: VirtualFileUrlManager
|
||||
get() = project.workspaceModel.getVirtualFileUrlManager()
|
||||
|
||||
override fun get(virtualFile: VirtualFile): ScriptCompilationConfigurationResult? {
|
||||
val url = virtualFile.toVirtualFileUrl(project.workspaceModel.getVirtualFileUrlManager())
|
||||
val result = data.computeIfAbsent(url) { url ->
|
||||
val entity = project.workspaceModel.currentSnapshot.getVirtualFileUrlIndex().findEntitiesByUrl(url)
|
||||
.firstOrNull {
|
||||
it.entitySource is KotlinGradleScriptEntitySource && it is KotlinScriptEntity
|
||||
} as? KotlinScriptEntity
|
||||
private val VirtualFile.virtualFileUrl: VirtualFileUrl
|
||||
get() = toVirtualFileUrl(urlManager)
|
||||
|
||||
entity?.toConfigurationResult() ?: ResultWithDiagnostics.Failure()
|
||||
}
|
||||
override suspend fun create(virtualFile: VirtualFile, definition: ScriptDefinition): ScriptCompilationConfigurationResult {
|
||||
val updatedConfiguration = refineScriptCompilationConfiguration(VirtualFileScriptSource(virtualFile), definition, project)
|
||||
data[virtualFile.virtualFileUrl] = updatedConfiguration.cached()
|
||||
|
||||
return if (result == ResultWithDiagnostics.Failure()) null else result
|
||||
return updatedConfiguration
|
||||
}
|
||||
|
||||
fun processScripts(
|
||||
override fun get(virtualFile: VirtualFile): ScriptCompilationConfigurationResult? {
|
||||
val wrapped = data.computeIfAbsent(virtualFile.virtualFileUrl) { key ->
|
||||
val entity = project.workspaceModel.currentSnapshot.getVirtualFileUrlIndex().findEntitiesByUrl(key)
|
||||
.singleOrNull { it.entitySource is KotlinGradleScriptEntitySource && it is KotlinScriptEntity } as? KotlinScriptEntity
|
||||
|
||||
entity?.toConfigurationResult().cached()
|
||||
}
|
||||
|
||||
return (wrapped as? CachedCompilationConfigurationResult.Some)?.value
|
||||
}
|
||||
|
||||
fun updateStorage(
|
||||
scriptData: GradleScriptData,
|
||||
storageToUpdate: MutableEntityStorage
|
||||
) {
|
||||
val updatedStorage = MutableEntityStorage.create()
|
||||
|
||||
val javaHome = scriptData.definitionsParams.javaHome
|
||||
val definitions = loadGradleDefinitions(scriptData.definitionsParams).map { it.withIdeKeys(project) }
|
||||
updatedStorage.enrichWithDefinitions(definitions)
|
||||
updatedStorage.enrichWithConfigurations(scriptData, definitions)
|
||||
|
||||
storageToUpdate.applyChangesFrom(updatedStorage)
|
||||
val updatedStorage = MutableEntityStorage.create().apply {
|
||||
updateStorage(this, scriptData.models, definitions, javaHome)
|
||||
}
|
||||
storageToUpdate.replaceBySource({ it is KotlinGradleScriptEntitySource }, updatedStorage)
|
||||
}
|
||||
|
||||
private fun MutableEntityStorage.enrichWithConfigurations(
|
||||
scriptsData: GradleScriptData,
|
||||
definitions: List<GradleScriptDefinition>
|
||||
fun updateStorage(
|
||||
storage: MutableEntityStorage,
|
||||
models: Collection<GradleScriptModel>,
|
||||
definitions: Collection<GradleScriptDefinition>,
|
||||
javaHome: String? = null
|
||||
) {
|
||||
val sdk = scriptsData.definitionsParams.javaHome.resolveSdk()
|
||||
val javaHomePath = sdk?.homePath?.let { File(it) }
|
||||
definitions.forEach {
|
||||
storage addEntity GradleScriptDefinitionEntity(
|
||||
it.definitionId,
|
||||
it.compilationConfiguration.asEntity(),
|
||||
it.hostConfiguration.asEntity(),
|
||||
KotlinGradleScriptEntitySource
|
||||
) {
|
||||
evaluationConfiguration = it.evaluationConfiguration?.asEntity()
|
||||
}
|
||||
}
|
||||
|
||||
val configurations = scriptsData.models.associate { gradleScript: GradleScriptModel ->
|
||||
val sourceCode = VirtualFileScriptSource(gradleScript.virtualFile)
|
||||
val definition = definitions.firstOrNull { it.isScript(sourceCode) } ?: findScriptDefinition(project, sourceCode)
|
||||
val javaHomePath = javaHome.resolveSdk()?.homePath?.let { File(it) }
|
||||
val configurations = mutableMapOf<VirtualFile, ScriptCompilationConfigurationResult>()
|
||||
|
||||
for (model in models) {
|
||||
val sourceCode = VirtualFileScriptSource(model.virtualFile)
|
||||
val definition = definitions.firstOrNull { it.isScript(sourceCode) } ?: continue
|
||||
|
||||
val configuration = definition.compilationConfiguration.with {
|
||||
if (javaHomePath != null) {
|
||||
jvm.jdkHome(javaHomePath)
|
||||
}
|
||||
defaultImports(gradleScript.imports)
|
||||
dependencies(JvmDependency(gradleScript.classPath.map { File(it) }))
|
||||
ide.dependenciesSources(JvmDependency(gradleScript.sourcePath.map { File(it) }))
|
||||
defaultImports(model.imports)
|
||||
dependencies(JvmDependency(model.classPath.map { File(it) }))
|
||||
ide.dependenciesSources(JvmDependency(model.sourcePath.map { File(it) }))
|
||||
}.adjustByDefinition(definition)
|
||||
|
||||
val updatedConfiguration = refineScriptCompilationConfiguration(sourceCode, definition, project, configuration)
|
||||
|
||||
gradleScript.virtualFile to updatedConfiguration
|
||||
configurations[model.virtualFile] = refineScriptCompilationConfiguration(sourceCode, definition, project, configuration)
|
||||
}
|
||||
|
||||
enrichStorage(configurations)
|
||||
storage.enrichStorage(configurations)
|
||||
}
|
||||
|
||||
private fun String?.resolveSdk(): Sdk? {
|
||||
@@ -120,46 +146,39 @@ class GradleKotlinScriptService(val project: Project) : ScriptRefinedConfigurati
|
||||
}
|
||||
|
||||
override suspend fun updateWorkspaceModel(configurationPerFile: Map<VirtualFile, ScriptCompilationConfigurationResult>) {
|
||||
if (configurationPerFile.size == 1) {
|
||||
val currentStorage = project.workspaceModel.currentSnapshot.toBuilder()
|
||||
project.workspaceModel.update("updating .gradle.kts scripts") { storage ->
|
||||
currentStorage.enrichStorage(configurationPerFile) // under writeAction from workspaceModel.update
|
||||
storage.applyChangesFrom(currentStorage)
|
||||
}
|
||||
val currentStorage = project.workspaceModel.currentSnapshot.toBuilder()
|
||||
project.workspaceModel.update("updating .gradle.kts scripts") { storage ->
|
||||
currentStorage.enrichStorage(configurationPerFile) // under writeAction from workspaceModel.update
|
||||
storage.applyChangesFrom(currentStorage)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableEntityStorage.enrichStorage(
|
||||
fun MutableEntityStorage.enrichStorage(
|
||||
configurations: Map<VirtualFile, ScriptCompilationConfigurationResult>,
|
||||
) {
|
||||
val fileUrlManager = project.workspaceModel.getVirtualFileUrlManager()
|
||||
|
||||
for ((scriptFile, configurationResult) in configurations) {
|
||||
val configurationWrapper = configurationResult.valueOrNull() ?: continue
|
||||
if (getVirtualFileUrlIndex().findEntitiesByUrl(scriptFile.virtualFileUrl).any()) continue
|
||||
|
||||
val scriptUrl = scriptFile.toVirtualFileUrl(fileUrlManager)
|
||||
|
||||
val classes = configurationWrapper.dependenciesClassPath.sorted().map { it.path.toVirtualFileUrl(fileUrlManager) }.toMutableSet()
|
||||
val sources = configurationWrapper.dependenciesSources.sorted().map { it.path.toVirtualFileUrl(fileUrlManager) }.toMutableSet()
|
||||
val classes =
|
||||
configurationWrapper.dependenciesClassPath.sorted().map { it.path.toVirtualFileUrl(urlManager) }.toMutableSet()
|
||||
val sources = configurationWrapper.dependenciesSources.sorted().map { it.path.toVirtualFileUrl(urlManager) }.toMutableSet()
|
||||
|
||||
val dependencies = buildList {
|
||||
addIfNotNull(
|
||||
extractRootsByPredicate(classes, sources) {
|
||||
it.url.contains("kotlin-stdlib")
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
addIfNotNull(
|
||||
extractRootsByPredicate(classes, sources) {
|
||||
it.url.contains("accessors")
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
addIfNotNull(
|
||||
extractRootsByPredicate(classes, sources) {
|
||||
it.url.contains("kotlin-gradle-plugin")
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
if (indexSourceRootsEagerly() || AdvancedSettings.getBoolean("gradle.attach.scripts.dependencies.sources")) {
|
||||
addAll(extractDependenciesWithSources(classes, sources))
|
||||
@@ -169,21 +188,17 @@ class GradleKotlinScriptService(val project: Project) : ScriptRefinedConfigurati
|
||||
addAll(
|
||||
classes.map {
|
||||
getOrCreateScriptLibrary(it, sources)
|
||||
}
|
||||
)
|
||||
})
|
||||
} else {
|
||||
addAll(
|
||||
classes.map {
|
||||
getOrCreateScriptLibrary(it)
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this addEntity KotlinScriptEntity(
|
||||
scriptUrl,
|
||||
dependencies,
|
||||
KotlinGradleScriptEntitySource
|
||||
scriptFile.virtualFileUrl, dependencies, KotlinGradleScriptEntitySource
|
||||
) {
|
||||
this.configuration = configurationWrapper.configuration?.asEntity()
|
||||
this.reports = configurationResult.reports.map { it.toData() }.toMutableList()
|
||||
@@ -193,16 +208,13 @@ class GradleKotlinScriptService(val project: Project) : ScriptRefinedConfigurati
|
||||
}
|
||||
|
||||
private fun MutableEntityStorage.getOrCreateScriptLibrary(
|
||||
jar: VirtualFileUrl,
|
||||
sources: Collection<VirtualFileUrl>
|
||||
jar: VirtualFileUrl, sources: Collection<VirtualFileUrl>
|
||||
): KotlinScriptLibraryEntityId {
|
||||
val id = KotlinScriptLibraryEntityId(listOf(jar), sources.toList())
|
||||
|
||||
if (!contains(id)) {
|
||||
this addEntity KotlinScriptLibraryEntity(
|
||||
id.classes,
|
||||
id.sources,
|
||||
KotlinGradleScriptEntitySource
|
||||
id.classes, id.sources, KotlinGradleScriptEntitySource
|
||||
)
|
||||
}
|
||||
|
||||
@@ -216,9 +228,7 @@ class GradleKotlinScriptService(val project: Project) : ScriptRefinedConfigurati
|
||||
|
||||
if (!contains(id)) {
|
||||
this addEntity KotlinScriptLibraryEntity(
|
||||
id.classes,
|
||||
id.sources,
|
||||
KotlinGradleScriptEntitySource
|
||||
id.classes, id.sources, KotlinGradleScriptEntitySource
|
||||
)
|
||||
}
|
||||
|
||||
@@ -275,9 +285,7 @@ class GradleKotlinScriptService(val project: Project) : ScriptRefinedConfigurati
|
||||
}
|
||||
|
||||
private fun MutableEntityStorage.extractRootsByPredicate(
|
||||
classes: MutableSet<VirtualFileUrl>,
|
||||
sources: MutableSet<VirtualFileUrl>,
|
||||
predicate: Predicate<VirtualFileUrl>
|
||||
classes: MutableSet<VirtualFileUrl>, sources: MutableSet<VirtualFileUrl>, predicate: Predicate<VirtualFileUrl>
|
||||
): KotlinScriptLibraryEntityId? {
|
||||
val groupedClasses = classes.removeOnMatch(predicate)
|
||||
if (groupedClasses.isEmpty()) return null
|
||||
@@ -305,29 +313,28 @@ class GradleKotlinScriptService(val project: Project) : ScriptRefinedConfigurati
|
||||
return removed
|
||||
}
|
||||
|
||||
private fun MutableEntityStorage.enrichWithDefinitions(definitions: List<GradleScriptDefinition>) {
|
||||
definitions.forEach {
|
||||
this addEntity GradleScriptDefinitionEntity(
|
||||
it.definitionId,
|
||||
it.compilationConfiguration.asEntity(),
|
||||
it.hostConfiguration.asEntity(),
|
||||
KotlinGradleScriptEntitySource
|
||||
) {
|
||||
evaluationConfiguration = it.evaluationConfiguration?.asEntity()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
private class GradleWorkspaceModelListener(val project: Project, val scope: CoroutineScope) : WorkspaceModelChangeListener {
|
||||
override fun changed(event: VersionedStorageChange) = scope.launchTracked {
|
||||
override fun beforeChanged(event: VersionedStorageChange) {
|
||||
val definitionChanges = event.getChanges(GradleScriptDefinitionEntity::class.java)
|
||||
val configurationChanges = event.getChanges(KotlinScriptEntity::class.java)
|
||||
|
||||
if (event.getChanges(GradleScriptDefinitionEntity::class.java).any()) {
|
||||
if (definitionChanges.any() || configurationChanges.any()) {
|
||||
KotlinScriptResolutionService.dropKotlinScriptCaches(project)
|
||||
}
|
||||
}
|
||||
|
||||
override fun changed(event: VersionedStorageChange) = scope.launchTracked {
|
||||
val definitionChanges = event.getChanges(GradleScriptDefinitionEntity::class.java)
|
||||
val configurationChanges = event.getChanges(KotlinScriptEntity::class.java)
|
||||
if (definitionChanges.none() && configurationChanges.none()) return@launchTracked
|
||||
|
||||
if (definitionChanges.any()) {
|
||||
ScriptDefinitionsModificationTracker.getInstance(project).incModificationCount()
|
||||
}
|
||||
|
||||
val updatedData = mutableMapOf<VirtualFileUrl, ScriptCompilationConfigurationResult>()
|
||||
for (entityChange in event.getChanges(KotlinScriptEntity::class.java)) {
|
||||
for (entityChange in configurationChanges) {
|
||||
if (entityChange is EntityChange.Removed) continue
|
||||
val entity = entityChange.newEntity ?: continue
|
||||
if (entity.entitySource !is KotlinGradleScriptEntitySource) continue
|
||||
@@ -340,7 +347,6 @@ class GradleKotlinScriptService(val project: Project) : ScriptRefinedConfigurati
|
||||
|
||||
if (updatedData.any()) {
|
||||
getInstance(project).data.clear()
|
||||
KotlinScriptResolutionService.dropKotlinScriptCaches(project)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,10 +366,8 @@ fun KotlinScriptEntity.toConfigurationResult(): ScriptCompilationConfigurationRe
|
||||
} else {
|
||||
ResultWithDiagnostics.Success<ScriptCompilationConfigurationWrapper>(
|
||||
ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(
|
||||
VirtualFileScriptSource(virtualFile),
|
||||
configuration?.deserialize()
|
||||
), reports.map { report -> report.toScriptDiagnostic() }
|
||||
)
|
||||
VirtualFileScriptSource(virtualFile), configuration?.deserialize()
|
||||
), reports.map { report -> report.toScriptDiagnostic() })
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
+2
-2
@@ -13,13 +13,13 @@ import com.intellij.platform.backend.workspace.WorkspaceModel
|
||||
import com.intellij.ui.EditorNotificationPanel
|
||||
import com.intellij.ui.EditorNotificationPanel.Status
|
||||
import com.intellij.ui.EditorNotificationProvider
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.KotlinGradleScriptEntitySource
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.KotlinGradleScriptEntitySource
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.KotlinGradleScriptingBundle
|
||||
import org.jetbrains.kotlin.idea.core.script.k2.modules.KotlinScriptLibraryEntity
|
||||
import java.util.function.Function
|
||||
import javax.swing.JComponent
|
||||
|
||||
class OpenAdvancedSettingsNotificationProvider() : EditorNotificationProvider {
|
||||
class OpenAdvancedSettingsNotificationProvider : EditorNotificationProvider {
|
||||
override fun collectNotificationData(
|
||||
project: Project,
|
||||
file: VirtualFile
|
||||
|
||||
+3
-12
@@ -2,13 +2,12 @@
|
||||
package org.jetbrains.kotlin.gradle.scripting.k2
|
||||
|
||||
import com.intellij.openapi.application.edtWriteAction
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.backend.observation.launchTracked
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.getGradleVersion
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.GradleBuildRootsLocator
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.awaitExternalSystemInitialization
|
||||
import org.jetbrains.plugins.gradle.service.GradleInstallationManager
|
||||
import org.jetbrains.plugins.gradle.settings.DistributionType
|
||||
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
|
||||
@@ -23,7 +22,7 @@ class ProjectGradleSettingsListener(
|
||||
override fun onProjectsLinked(settings: MutableCollection<GradleProjectSettings>) {
|
||||
val buildRootsManager = GradleBuildRootsLocator.getInstance(project)
|
||||
coroutineScope.launchTracked {
|
||||
awaitExternalSystemInitialization()
|
||||
project.awaitExternalSystemInitialization()
|
||||
settings.forEach {
|
||||
val gradleVersion = getGradleVersion(project, it)
|
||||
edtWriteAction {
|
||||
@@ -37,7 +36,7 @@ class ProjectGradleSettingsListener(
|
||||
override fun onProjectsLoaded(settings: Collection<GradleProjectSettings>) {
|
||||
val buildRootsManager = GradleBuildRootsLocator.getInstance(project)
|
||||
coroutineScope.launchTracked {
|
||||
awaitExternalSystemInitialization()
|
||||
project.awaitExternalSystemInitialization()
|
||||
settings.forEach {
|
||||
val gradleVersion = getGradleVersion(project, it)
|
||||
edtWriteAction {
|
||||
@@ -47,14 +46,6 @@ class ProjectGradleSettingsListener(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun awaitExternalSystemInitialization() {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
ExternalProjectsManagerImpl.getInstance(project).runWhenInitialized {
|
||||
continuation.resumeWith(Result.success(Unit))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProjectsUnlinked(linkedProjectPaths: MutableSet<String>) {
|
||||
val buildRootsManager = GradleBuildRootsLocator.getInstance(project)
|
||||
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.gradle.scripting.k2.importing
|
||||
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.platform.workspace.storage.ImmutableEntityStorage
|
||||
import com.intellij.platform.workspace.storage.toBuilder
|
||||
import org.gradle.tooling.model.dsl.GradleDslBaseScriptModel
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.GradleKotlinScriptService
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.BaseScriptDefinition
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.ErrorGradleScriptDefinition
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.getGradleTemplatesNames
|
||||
import org.jetbrains.kotlin.idea.core.script.shared.definition.loadDefinitionsFromTemplates
|
||||
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||
import org.jetbrains.plugins.gradle.service.syncAction.GradleSyncContributor
|
||||
import org.jetbrains.plugins.gradle.service.syncAction.GradleSyncPhase
|
||||
import kotlin.script.experimental.api.defaultImports
|
||||
import kotlin.script.experimental.api.dependencies
|
||||
import kotlin.script.experimental.jvm.JvmDependency
|
||||
|
||||
internal class KotlinDslBaseScriptSyncContributor : GradleSyncContributor {
|
||||
override val name: String = "Kotlin DSL Base Script"
|
||||
|
||||
override val phase: GradleSyncPhase = GradleSyncPhase.BASE_SCRIPT_MODEL_PHASE
|
||||
|
||||
override suspend fun createProjectModel(
|
||||
context: ProjectResolverContext, storage: ImmutableEntityStorage
|
||||
): ImmutableEntityStorage {
|
||||
|
||||
val baseModel = context.getRootModel(GradleDslBaseScriptModel::class.java)?.kotlinDslBaseScriptModel ?: return storage
|
||||
val templateClasspath = (baseModel.scriptTemplatesClassPath + baseModel.compileClassPath).map { it.toPath() }
|
||||
val templateClasses = getGradleTemplatesNames(context.gradleVersion)
|
||||
|
||||
val definitions = loadDefinitionsFromTemplates(templateClasses, templateClasspath).map {
|
||||
BaseScriptDefinition(it)
|
||||
}.ifEmpty { sequenceOf(ErrorGradleScriptDefinition()) }.toList().map {
|
||||
it.with {
|
||||
dependencies(JvmDependency(baseModel.compileClassPath))
|
||||
defaultImports(baseModel.implicitImports)
|
||||
}
|
||||
}
|
||||
|
||||
val builder = storage.toBuilder()
|
||||
builder.also { storage ->
|
||||
val models = readAction {
|
||||
FileEditorManager.getInstance(context.project).allEditors
|
||||
}.filter {
|
||||
it.file.name.endsWith(".gradle.kts")
|
||||
}.map { fileEditor ->
|
||||
GradleScriptModel(
|
||||
fileEditor.file, baseModel.compileClassPath.map { it.path }, listOf(), baseModel.implicitImports
|
||||
)
|
||||
}
|
||||
|
||||
GradleKotlinScriptService.getInstance(context.project).updateStorage(
|
||||
storage,
|
||||
models,
|
||||
definitions,
|
||||
)
|
||||
}
|
||||
return builder.toSnapshot()
|
||||
}
|
||||
}
|
||||
+2
-17
@@ -6,11 +6,9 @@ import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.platform.eel.provider.getEelDescriptor
|
||||
import com.intellij.platform.eel.provider.utils.asNio
|
||||
import com.intellij.platform.workspace.storage.ImmutableEntityStorage
|
||||
import com.intellij.platform.workspace.storage.MutableEntityStorage
|
||||
import com.intellij.platform.workspace.storage.toBuilder
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.GradleKotlinScriptService
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.GradleDefinitionsParams
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.KotlinGradleScriptEntitySource
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.GradleDefinitionsParams
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.importing.collectErrors
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.importing.getKotlinDslScripts
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.importing.kotlinDslSyncListenerInstance
|
||||
@@ -18,24 +16,11 @@ import org.jetbrains.kotlin.gradle.scripting.shared.importing.saveGradleBuildEnv
|
||||
import org.jetbrains.plugins.gradle.model.GradleBuildScriptClasspathModel
|
||||
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||
import org.jetbrains.plugins.gradle.service.syncAction.GradleSyncContributor
|
||||
import org.jetbrains.plugins.gradle.service.syncAction.GradleSyncExtension
|
||||
import org.jetbrains.plugins.gradle.service.syncAction.GradleSyncPhase
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
internal class KotlinDslScriptSyncExtension : GradleSyncExtension {
|
||||
|
||||
override fun updateProjectModel(
|
||||
context: ProjectResolverContext, syncStorage: MutableEntityStorage, projectStorage: MutableEntityStorage, phase: GradleSyncPhase
|
||||
) {
|
||||
if (phase == GradleSyncPhase.ADDITIONAL_MODEL_PHASE) {
|
||||
projectStorage.replaceBySource({ it is KotlinGradleScriptEntitySource }, syncStorage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class KotlinDslScriptSyncContributor : GradleSyncContributor {
|
||||
|
||||
override val name: String = "Kotlin DSL Script"
|
||||
|
||||
override val phase: GradleSyncPhase = GradleSyncPhase.ADDITIONAL_MODEL_PHASE
|
||||
@@ -95,7 +80,7 @@ internal class KotlinDslScriptSyncContributor : GradleSyncContributor {
|
||||
)
|
||||
)
|
||||
|
||||
GradleKotlinScriptService.getInstance(project).processScripts(scriptData, builder)
|
||||
GradleKotlinScriptService.getInstance(project).updateStorage(scriptData, builder)
|
||||
|
||||
return builder.toSnapshot()
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.gradle.scripting.k2.importing
|
||||
|
||||
import com.intellij.platform.workspace.storage.MutableEntityStorage
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.workspaceModel.KotlinGradleScriptEntitySource
|
||||
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||
import org.jetbrains.plugins.gradle.service.syncAction.GradleSyncExtension
|
||||
import org.jetbrains.plugins.gradle.service.syncAction.GradleSyncPhase
|
||||
|
||||
internal class KotlinDslScriptSyncExtension : GradleSyncExtension {
|
||||
|
||||
override fun updateProjectModel(
|
||||
context: ProjectResolverContext, syncStorage: MutableEntityStorage, projectStorage: MutableEntityStorage, phase: GradleSyncPhase
|
||||
) {
|
||||
if (phase == GradleSyncPhase.BASE_SCRIPT_MODEL_PHASE || phase == GradleSyncPhase.ADDITIONAL_MODEL_PHASE) {
|
||||
projectStorage.replaceBySource({ it is KotlinGradleScriptEntitySource }, syncStorage)
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-19
@@ -10,13 +10,9 @@ import java.io.DataInput
|
||||
import java.io.DataOutput
|
||||
|
||||
class GradleBuildRootDataSerializer : AbstractGradleBuildRootDataSerializer() {
|
||||
override val externalizer: DataExternalizer<GradleBuildRootData>
|
||||
get() = object : DataExternalizer<GradleBuildRootData> {
|
||||
override fun save(out: DataOutput, value: GradleBuildRootData) =
|
||||
writeKotlinDslScriptModels(out, value)
|
||||
|
||||
override fun read(`in`: DataInput): GradleBuildRootData =
|
||||
readKotlinDslScriptModels(`in`)
|
||||
override fun getExternalizer(): DataExternalizer<GradleBuildRootData> = object : DataExternalizer<GradleBuildRootData> {
|
||||
override fun save(out: DataOutput, value: GradleBuildRootData) = writeKotlinDslScriptModels(out, value)
|
||||
override fun read(`in`: DataInput): GradleBuildRootData = readKotlinDslScriptModels(`in`, currentBuildRoot.get().path)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -31,18 +27,7 @@ class GradleBuildRootDataSerializer : AbstractGradleBuildRootDataSerializer() {
|
||||
strings.writeStringIds(data.projectRoots)
|
||||
strings.writeStringId(data.gradleHome)
|
||||
strings.writeStringId(data.javaHome)
|
||||
}
|
||||
|
||||
@IntellijInternalApi
|
||||
fun readKotlinDslScriptModels(input: DataInput): GradleBuildRootData {
|
||||
val strings = StringsPool.reader(input)
|
||||
|
||||
val importTs = input.readLong()
|
||||
val projectRoots = strings.readStrings()
|
||||
val gradleHome = strings.readString()
|
||||
val javaHome = strings.readNullableString()
|
||||
|
||||
return GradleBuildRootData(importTs, projectRoots, gradleHome, javaHome, listOf())
|
||||
output.writeInt(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -20,3 +20,5 @@ interface GradleScriptDefinitionEntity : WorkspaceEntityWithSymbolicId {
|
||||
override val symbolicId: GradleScriptDefinitionEntityId
|
||||
get() = GradleScriptDefinitionEntityId(definitionId)
|
||||
}
|
||||
|
||||
object KotlinGradleScriptEntitySource : EntitySource
|
||||
|
||||
+3
-2
@@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle.scripting.k2
|
||||
import org.jetbrains.kotlin.gradle.scripting.k2.roots.GradleBuildRootDataSerializer
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.GradleKotlinScriptConfigurationInputs
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.importing.KotlinDslScriptModel
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.AbstractGradleBuildRootDataSerializer
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.GradleBuildRootData
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
@@ -52,7 +53,7 @@ class GradleBuildRootDataSerializerTest {
|
||||
val buffer = ByteArrayOutputStream()
|
||||
GradleBuildRootDataSerializer.writeKotlinDslScriptModels(DataOutputStream(buffer), dataToWrite)
|
||||
|
||||
val restored = GradleBuildRootDataSerializer.readKotlinDslScriptModels(DataInputStream(ByteArrayInputStream(buffer.toByteArray())))
|
||||
val restored = AbstractGradleBuildRootDataSerializer.readKotlinDslScriptModels(DataInputStream(ByteArrayInputStream(buffer.toByteArray())), "a")
|
||||
|
||||
assertEquals(dataToRead.toString(), restored.toString())
|
||||
}
|
||||
@@ -70,7 +71,7 @@ class GradleBuildRootDataSerializerTest {
|
||||
val buffer = ByteArrayOutputStream()
|
||||
GradleBuildRootDataSerializer.writeKotlinDslScriptModels(DataOutputStream(buffer), data)
|
||||
|
||||
val restored = GradleBuildRootDataSerializer.readKotlinDslScriptModels(DataInputStream(ByteArrayInputStream(buffer.toByteArray())))
|
||||
val restored = AbstractGradleBuildRootDataSerializer.readKotlinDslScriptModels(DataInputStream(ByteArrayInputStream(buffer.toByteArray())), "a")
|
||||
|
||||
assertEquals(data.toString(), restored.toString())
|
||||
}
|
||||
|
||||
+26
-14
@@ -2,8 +2,6 @@
|
||||
package org.jetbrains.kotlin.gradle.scripting.shared.definition
|
||||
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.KotlinGradleScriptingBundle
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.externalProjectPath
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.gradle
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptCompilationConfigurationFromDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
@@ -13,7 +11,7 @@ import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
import kotlin.script.templates.standard.ScriptTemplateWithArgs
|
||||
|
||||
open class GradleScriptDefinition(
|
||||
compilationConfiguration: ScriptCompilationConfiguration,
|
||||
private val initialConfiguration: ScriptCompilationConfiguration,
|
||||
override val hostConfiguration: ScriptingHostConfiguration,
|
||||
override val evaluationConfiguration: ScriptEvaluationConfiguration?,
|
||||
override val defaultCompilerOptions: Iterable<String> = emptyList(),
|
||||
@@ -27,15 +25,16 @@ open class GradleScriptDefinition(
|
||||
override val canDefinitionBeSwitchedOff: Boolean = false
|
||||
|
||||
override val compilationConfiguration: ScriptCompilationConfiguration by lazy {
|
||||
compilationConfiguration.with {
|
||||
mutator()
|
||||
gradle {
|
||||
externalProjectPath(_externalProjectPath)
|
||||
initialConfiguration
|
||||
.with(configurationBody)
|
||||
.with {
|
||||
gradle {
|
||||
externalProjectPath(_externalProjectPath)
|
||||
}
|
||||
ide {
|
||||
acceptedLocations.put(listOf(ScriptAcceptedLocation.Project))
|
||||
}
|
||||
}
|
||||
ide {
|
||||
acceptedLocations.put(listOf(ScriptAcceptedLocation.Project))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun with(body: ScriptCompilationConfiguration.Builder.() -> Unit): GradleScriptDefinition {
|
||||
@@ -45,7 +44,20 @@ open class GradleScriptDefinition(
|
||||
)
|
||||
}
|
||||
|
||||
open val mutator: ScriptCompilationConfiguration.Builder.() -> Unit = {}
|
||||
protected open val configurationBody: ScriptCompilationConfiguration.Builder.() -> Unit = {}
|
||||
}
|
||||
|
||||
class BaseScriptDefinition(private val definition: ScriptDefinition) : GradleScriptDefinition(
|
||||
definition.compilationConfiguration,
|
||||
definition.hostConfiguration,
|
||||
definition.evaluationConfiguration,
|
||||
definition.defaultCompilerOptions,
|
||||
) {
|
||||
override val configurationBody: ScriptCompilationConfiguration.Builder.() -> Unit = {
|
||||
displayName("${definition.name} (Base)")
|
||||
}
|
||||
|
||||
override val definitionId: String = "${super.definitionId}_base"
|
||||
}
|
||||
|
||||
class LegacyGradleScriptDefinition(
|
||||
@@ -59,7 +71,7 @@ class LegacyGradleScriptDefinition(
|
||||
hostConfiguration, _legacyDefinition
|
||||
), hostConfiguration, evaluationConfiguration, defaultCompilerOptions, externalProjectPath
|
||||
) {
|
||||
override val mutator: ScriptCompilationConfiguration.Builder.() -> Unit = {
|
||||
override val configurationBody: ScriptCompilationConfiguration.Builder.() -> Unit = {
|
||||
@Suppress("DEPRECATION_ERROR") fileNamePattern.put(_legacyDefinition.scriptFilePattern.pattern)
|
||||
}
|
||||
}
|
||||
@@ -71,7 +83,7 @@ class ErrorGradleScriptDefinition : GradleScriptDefinition(
|
||||
hostConfiguration(ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration))
|
||||
}) {
|
||||
|
||||
override val mutator: ScriptCompilationConfiguration.Builder.() -> Unit = {
|
||||
override val configurationBody: ScriptCompilationConfiguration.Builder.() -> Unit = {
|
||||
fileExtension("gradle.kts")
|
||||
baseClass(KotlinType(ScriptTemplateWithArgs::class))
|
||||
displayName(KotlinGradleScriptingBundle.message("text.default.kotlin.gradle.script"))
|
||||
|
||||
+42
-56
@@ -1,22 +1,22 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.gradle.scripting.shared
|
||||
package org.jetbrains.kotlin.gradle.scripting.shared.definition
|
||||
|
||||
import com.intellij.gradle.toolingExtension.util.GradleVersionUtil.isGradleAtLeast
|
||||
import com.intellij.platform.workspace.storage.EntitySource
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.ErrorGradleScriptDefinition
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.GradleScriptDefinition
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.definition.LegacyGradleScriptDefinition
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.KotlinGradleScriptingBundle
|
||||
import org.jetbrains.kotlin.idea.core.script.shared.definition.loadDefinitionsFromTemplates
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.scriptingDebugLog
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.scriptingInfoLog
|
||||
import org.jetbrains.kotlin.scripting.definitions.getEnvironment
|
||||
import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import java.io.File
|
||||
import java.nio.file.DirectoryStream
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.*
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.isDirectory
|
||||
import kotlin.io.path.name
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfigurationKeys
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
@@ -39,7 +39,28 @@ fun loadGradleDefinitions(params: GradleDefinitionsParams): List<GradleScriptDef
|
||||
val kotlinLibsClassPath = kotlinStdlibAndCompiler(gradleLibDir)
|
||||
val languageVersionCompilerOptions = findStdLibLanguageVersion(kotlinLibsClassPath)
|
||||
|
||||
val templateClasses = if (params.gradleVersion != null && isGradleAtLeast(params.gradleVersion, GRADLE_WITH_NEW_SCRIPTING_TEMPLATES)) {
|
||||
val templateClasses = getGradleTemplatesNames(params.gradleVersion?.let { GradleVersion.version(it) })
|
||||
|
||||
val hostConfiguration = params.toHostConfiguration()
|
||||
return loadDefinitionsFromTemplates(
|
||||
templateClassNames = templateClasses,
|
||||
templateClasspath = templateClasspath,
|
||||
additionalResolverClasspath = kotlinLibsClassPath,
|
||||
baseHostConfiguration = hostConfiguration,
|
||||
defaultCompilerOptions = languageVersionCompilerOptions
|
||||
).map {
|
||||
it.asLegacyOrNull<KotlinScriptDefinitionFromAnnotatedTemplate>()?.let { legacyDefinition ->
|
||||
LegacyGradleScriptDefinition(
|
||||
legacyDefinition, it.hostConfiguration, it.evaluationConfiguration, it.defaultCompilerOptions, params.workingDir
|
||||
)
|
||||
} ?: GradleScriptDefinition(
|
||||
it.compilationConfiguration, it.hostConfiguration, it.evaluationConfiguration, it.defaultCompilerOptions, params.workingDir
|
||||
)
|
||||
}.ifEmpty { sequenceOf(ErrorGradleScriptDefinition()) }.toList()
|
||||
}
|
||||
|
||||
fun getGradleTemplatesNames(gradleVersion: GradleVersion?): List<String> {
|
||||
val templateClasses = if (gradleVersion != null && isGradleAtLeast(gradleVersion, GRADLE_WITH_NEW_SCRIPTING_TEMPLATES)) {
|
||||
listOf(
|
||||
"org.gradle.kotlin.dsl.KotlinGradleScriptTemplate",
|
||||
"org.gradle.kotlin.dsl.KotlinSettingsScriptTemplate",
|
||||
@@ -52,33 +73,7 @@ fun loadGradleDefinitions(params: GradleDefinitionsParams): List<GradleScriptDef
|
||||
"org.gradle.kotlin.dsl.KotlinBuildScript",
|
||||
)
|
||||
}
|
||||
|
||||
val hostConfiguration = params.toHostConfiguration()
|
||||
return loadDefinitionsFromTemplates(
|
||||
templateClassNames = templateClasses,
|
||||
templateClasspath = templateClasspath,
|
||||
additionalResolverClasspath = kotlinLibsClassPath,
|
||||
baseHostConfiguration = hostConfiguration,
|
||||
defaultCompilerOptions = languageVersionCompilerOptions
|
||||
).map {
|
||||
it.asLegacyOrNull<KotlinScriptDefinitionFromAnnotatedTemplate>()?.let { legacyDefinition ->
|
||||
LegacyGradleScriptDefinition(
|
||||
legacyDefinition,
|
||||
it.hostConfiguration,
|
||||
it.evaluationConfiguration,
|
||||
it.defaultCompilerOptions,
|
||||
params.workingDir
|
||||
)
|
||||
} ?: GradleScriptDefinition(
|
||||
it.compilationConfiguration,
|
||||
it.hostConfiguration,
|
||||
it.evaluationConfiguration,
|
||||
it.defaultCompilerOptions,
|
||||
params.workingDir
|
||||
)
|
||||
}.ifEmpty {
|
||||
sequenceOf(ErrorGradleScriptDefinition())
|
||||
}.toList()
|
||||
return templateClasses
|
||||
}
|
||||
|
||||
private fun findStdLibLanguageVersion(kotlinLibsClassPath: List<Path>): List<String> {
|
||||
@@ -89,8 +84,7 @@ private fun findStdLibLanguageVersion(kotlinLibsClassPath: List<Path>): List<Str
|
||||
|
||||
if (result.groupValues.size < 3) return emptyList()
|
||||
val version = result.groupValues[2]
|
||||
return LanguageVersion.fromVersionString(version)?.let { listOf("-language-version", it.versionString) }
|
||||
?: emptyList()
|
||||
return LanguageVersion.fromVersionString(version)?.let { listOf("-language-version", it.versionString) } ?: emptyList()
|
||||
}
|
||||
|
||||
private fun GradleDefinitionsParams.toHostConfiguration(): ScriptingHostConfiguration =
|
||||
@@ -107,12 +101,16 @@ private fun GradleDefinitionsParams.toHostConfiguration(): ScriptingHostConfigur
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.toGradleHomePath(): Path = Path(this, "lib").let {
|
||||
it.takeIf { it.exists() && it.isDirectory() }
|
||||
?: error(KotlinGradleScriptingBundle.message("error.text.invalid.gradle.libraries.directory", it))
|
||||
fun String?.toGradleHomePath(): Path {
|
||||
if (this == null) error(KotlinGradleScriptingBundle.message("error.text.unable.to.get.gradle.home.directory"))
|
||||
|
||||
return Path(this, "lib").let {
|
||||
it.takeIf { it.exists() && it.isDirectory() }
|
||||
?: error(KotlinGradleScriptingBundle.message("error.text.invalid.gradle.libraries.directory", it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFullDefinitionsClasspath(gradleLibDir: Path): List<Path> {
|
||||
fun getFullDefinitionsClasspath(gradleLibDir: Path): List<Path> {
|
||||
val templateClasspath = Files.newDirectoryStream(gradleLibDir) { kotlinDslDependencySelector.matches(it.name) }
|
||||
.use(DirectoryStream<Path>::toList)
|
||||
.ifEmpty { error(KotlinGradleScriptingBundle.message("error.text.missing.jars.in.gradle.directory")) }
|
||||
@@ -123,8 +121,7 @@ private fun getFullDefinitionsClasspath(gradleLibDir: Path): List<Path> {
|
||||
}
|
||||
|
||||
private fun kotlinStdlibAndCompiler(gradleLibDir: Path): List<Path> {
|
||||
val stdlibPath = gradleLibDir.findFirst("kotlin-stdlib-[1-9]*")
|
||||
// additionally need compiler jar to load gradle resolver
|
||||
val stdlibPath = gradleLibDir.findFirst("kotlin-stdlib-[1-9]*") // additionally need compiler jar to load gradle resolver
|
||||
val compilerPath = gradleLibDir.findFirst("kotlin-compiler-embeddable*")
|
||||
return listOfNotNull(stdlibPath, compilerPath)
|
||||
}
|
||||
@@ -133,25 +130,14 @@ private fun Path.findFirst(pattern: String): Path? = Files.newDirectoryStream(th
|
||||
|
||||
private val kotlinDslDependencySelector = Regex("^gradle-(?:kotlin-dsl|core|base-services).*\\.jar\$")
|
||||
|
||||
fun getDefinitionsTemplateClasspath(gradleHome: String): List<String> = try {
|
||||
getFullDefinitionsClasspath(gradleHome.toGradleHomePath()).map { it.invariantSeparatorsPathString }
|
||||
} catch (e: Throwable) {
|
||||
scriptingInfoLog("cannot get classpath for Gradle Kotlin DSL scripts: ${e.message}")
|
||||
|
||||
emptyList()
|
||||
}
|
||||
|
||||
interface GradleScriptCompilationConfigurationKeys
|
||||
|
||||
open class GradleScriptCompilationConfigurationBuilder : PropertiesCollection.Builder(),
|
||||
GradleScriptCompilationConfigurationKeys {
|
||||
open class GradleScriptCompilationConfigurationBuilder : PropertiesCollection.Builder(), GradleScriptCompilationConfigurationKeys {
|
||||
companion object : GradleScriptCompilationConfigurationKeys
|
||||
}
|
||||
|
||||
@Suppress("UnusedReceiverParameter")
|
||||
val ScriptCompilationConfigurationKeys.gradle: GradleScriptCompilationConfigurationBuilder
|
||||
get() = GradleScriptCompilationConfigurationBuilder()
|
||||
|
||||
val GradleScriptCompilationConfigurationKeys.externalProjectPath: PropertiesCollection.Key<String?> by PropertiesCollection.key()
|
||||
|
||||
|
||||
object KotlinGradleScriptEntitySource : EntitySource
|
||||
+28
-3
@@ -3,16 +3,19 @@
|
||||
package org.jetbrains.kotlin.gradle.scripting.shared.roots
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.gist.storage.GistStorage
|
||||
import com.intellij.util.io.DataExternalizer
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.GradleKotlinScriptConfigurationInputs
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.LastModifiedFiles
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.importing.KotlinDslScriptModel
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.readString
|
||||
import org.jetbrains.kotlin.idea.core.script.v1.writeString
|
||||
import java.io.DataInput
|
||||
import java.io.DataOutput
|
||||
|
||||
private const val BINARY_FORMAT_VERSION = 1
|
||||
private const val BINARY_FORMAT_VERSION = 2
|
||||
private const val NO_TRACK_GIST_STAMP = 0
|
||||
|
||||
abstract class AbstractGradleBuildRootDataSerializer {
|
||||
@@ -20,9 +23,9 @@ abstract class AbstractGradleBuildRootDataSerializer {
|
||||
protected val currentBuildRoot: ThreadLocal<VirtualFile> = ThreadLocal()
|
||||
|
||||
private val buildRootDataGist =
|
||||
GistStorage.getInstance().newGist("GradleBuildRootData", BINARY_FORMAT_VERSION, externalizer)
|
||||
GistStorage.getInstance().newGist("GradleBuildRootData", BINARY_FORMAT_VERSION, getExternalizer())
|
||||
|
||||
protected abstract val externalizer: DataExternalizer<GradleBuildRootData>
|
||||
protected abstract fun getExternalizer(): DataExternalizer<GradleBuildRootData>
|
||||
|
||||
fun read(buildRoot: VirtualFile): GradleBuildRootData? {
|
||||
currentBuildRoot.set(buildRoot)
|
||||
@@ -40,6 +43,28 @@ abstract class AbstractGradleBuildRootDataSerializer {
|
||||
}
|
||||
|
||||
companion object {
|
||||
@IntellijInternalApi
|
||||
fun readKotlinDslScriptModels(input: DataInput, buildRoot: String): GradleBuildRootData {
|
||||
val strings = StringsPool.reader(input)
|
||||
|
||||
val importTs = input.readLong()
|
||||
val projectRoots = strings.readStrings()
|
||||
val gradleHome = strings.readString()
|
||||
val javaHome = strings.readNullableString()
|
||||
val models = input.readList {
|
||||
KotlinDslScriptModel(
|
||||
strings.readString(),
|
||||
GradleKotlinScriptConfigurationInputs(input.readString(), input.readLong(), buildRoot),
|
||||
strings.readStrings(),
|
||||
strings.readStrings(),
|
||||
strings.readStrings(),
|
||||
listOf()
|
||||
)
|
||||
}
|
||||
|
||||
return GradleBuildRootData(importTs, projectRoots, gradleHome, javaHome, models)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getInstance(): AbstractGradleBuildRootDataSerializer = service()
|
||||
}
|
||||
|
||||
+2
@@ -4,10 +4,12 @@ package org.jetbrains.kotlin.gradle.scripting.shared
|
||||
|
||||
import com.intellij.gradle.toolingExtension.util.GradleVersionUtil
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import org.jetbrains.kotlin.gradle.scripting.shared.roots.GradleBuildRootsLocator
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// FILE: build.gradle.kts
|
||||
// ALLOW_ERRORS
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":module1"))
|
||||
}
|
||||
|
||||
// FILE: settings.gradle.kts
|
||||
include("module1")
|
||||
|
||||
// FILE: build.gradle.kts.highlighting.k2
|
||||
// ALLOW_ERRORS
|
||||
<!HIGHLIGHTING("severity='DSL_TYPE_SEVERITY'")!>plugins<!> {
|
||||
<!HIGHLIGHTING("severity='SYMBOL_TYPE_SEVERITY'")!>`kotlin-dsl`<!>
|
||||
}
|
||||
|
||||
<!HIGHLIGHTING("severity='SYMBOL_TYPE_SEVERITY'")!>repositories<!> {
|
||||
<!HIGHLIGHTING("severity='SYMBOL_TYPE_SEVERITY'")!>mavenCentral<!>()
|
||||
}
|
||||
|
||||
<!HIGHLIGHTING("severity='SYMBOL_TYPE_SEVERITY'")!>dependencies<!> {
|
||||
<!HIGHLIGHTING("severity='ERROR'; descr='[UNRESOLVED_REFERENCE] Unresolved reference 'implementation'.'")!>implementation<!>(<!HIGHLIGHTING("severity='SYMBOL_TYPE_SEVERITY'")!>project<!>(":module1"))
|
||||
}
|
||||
|
||||
// FILE: settings.gradle.kts
|
||||
include("module1")
|
||||
|
||||
// FILE: module1/build.gradle.kts
|
||||
plugins {
|
||||
java
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
Reference in New Issue
Block a user