diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptDefinitionsProvider.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptDefinitionsProvider.kt index e3a0ac4ed18..6235683fbe8 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptDefinitionsProvider.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptDefinitionsProvider.kt @@ -46,7 +46,7 @@ import kotlin.script.templates.standard.ScriptTemplateWithArgs class GradleScriptDefinitionsContributor(private val project: Project) : ScriptDefinitionSourceAsContributor { companion object { - fun getDefinitions(project: Project, workingDir: String, gradleHome: String?): List? { + fun getDefinitions(project: Project, workingDir: String, gradleHome: String?, javaHome: String?): List? { val contributor = ScriptDefinitionContributor.EP_NAME.getExtensions(project) .filterIsInstance() .singleOrNull() @@ -63,7 +63,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD return null } - val root = LightGradleBuildRoot(workingDir, gradleHome) + val root = LightGradleBuildRoot(workingDir, gradleHome, javaHome) val definitions = contributor.definitionsByRoots[root] if (definitions == null) { scriptingInfoLog( @@ -128,7 +128,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD override val id: String = "Gradle Kotlin DSL" - private data class LightGradleBuildRoot(val workingDir: String, val gradleHome: String?) + private data class LightGradleBuildRoot(val workingDir: String, val gradleHome: String?, val javaHome: String?) private val definitionsByRoots = ConcurrentHashMap>() @@ -148,8 +148,8 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD } // TODO: remove old roots - fun reloadIfNeeded(workingDir: String, gradleHome: String?) { - val root = LightGradleBuildRoot(workingDir, gradleHome) + fun reloadIfNeeded(workingDir: String, gradleHome: String?, javaHome: String?) { + val root = LightGradleBuildRoot(workingDir, gradleHome, javaHome) val value = definitionsByRoots[root] if (value != null) { if (root.isError()) { @@ -177,15 +177,17 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD loadGradleTemplates( projectPath, templateClass = "org.gradle.kotlin.dsl.KotlinInitScript", - root.gradleHome, - templateClasspath, - additionalClassPath + gradleHome = root.gradleHome, + javaHome = root.javaHome, + templateClasspath = templateClasspath, + additionalClassPath = additionalClassPath ).let { kotlinDslTemplates.addAll(it) } loadGradleTemplates( projectPath, templateClass = "org.gradle.kotlin.dsl.KotlinSettingsScript", gradleHome = root.gradleHome, + javaHome = root.javaHome, templateClasspath = templateClasspath, additionalClassPath = additionalClassPath ).let { kotlinDslTemplates.addAll(it) } @@ -195,6 +197,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD projectPath, templateClass = "org.gradle.kotlin.dsl.KotlinBuildScript", gradleHome = root.gradleHome, + javaHome = root.javaHome, templateClasspath = templateClasspath, additionalClassPath = additionalClassPath ).let { kotlinDslTemplates.addAll(it) } @@ -223,6 +226,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD projectPath: String, templateClass: String, gradleHome: String?, + javaHome: String?, templateClasspath: List, additionalClassPath: List ): List { @@ -231,7 +235,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD projectPath, GradleConstants.SYSTEM_ID ) - val hostConfiguration = createHostConfiguration(projectPath, gradleHome, gradleExeSettings) + val hostConfiguration = createHostConfiguration(projectPath, gradleHome, javaHome, gradleExeSettings) return loadDefinitionsFromTemplates( listOf(templateClass), templateClasspath, @@ -253,6 +257,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD private fun createHostConfiguration( projectPath: String, gradleHome: String?, + javaHome: String?, gradleExeSettings: GradleExecutionSettings ): ScriptingHostConfiguration { val gradleJvmOptions = gradleExeSettings.daemonVmOptions?.let { vmOptions -> @@ -264,7 +269,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD val environment = mapOf( "gradleHome" to gradleHome?.let(::File), - "gradleJavaHome" to gradleExeSettings.javaHome, // TODO: should be taken from information from gradle sync + "gradleJavaHome" to javaHome, "projectRoot" to projectPath.let(::File), @@ -317,19 +322,20 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD // otherwise KotlinDslSyncListener should run reloadIfNeeded for valid roots GradleBuildRootsManager.getInstance(project).getAllRoots().forEach { val workingDir = it.pathPrefix - val gradleHome = when (it) { + val (gradleHome, javaHome) = when (it) { is Imported -> { - it.data.gradleHome + it.data.gradleHome to it.data.javaHome } is WithoutScriptModels -> { - ExternalSystemApiUtil.getExecutionSettings( + val settings = ExternalSystemApiUtil.getExecutionSettings( project, workingDir, GradleConstants.SYSTEM_ID - ).gradleHome + ) + settings.gradleHome to settings.javaHome } } - val root = LightGradleBuildRoot(workingDir, gradleHome) + val root = LightGradleBuildRoot(workingDir, gradleHome, javaHome) definitionsByRoots[root] = loadGradleDefinitions(root) } } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelProcessor.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelProcessor.kt index aeb32267c15..0bfd0a14d6d 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelProcessor.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScriptModelProcessor.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle import org.jetbrains.kotlin.idea.scripting.gradle.getGradleScriptInputsStamp import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager import org.jetbrains.plugins.gradle.model.BuildScriptClasspathModel +import org.jetbrains.plugins.gradle.service.project.DefaultProjectResolverContext import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext import java.io.File @@ -28,6 +29,10 @@ fun saveGradleBuildEnvironment(resolverCtx: ProjectResolverContext) { ?: resolverCtx.settings?.gradleHome synchronized(sync) { sync.gradleVersion = resolverCtx.projectGradleVersion + sync.javaHome = (resolverCtx as? DefaultProjectResolverContext) + ?.buildEnvironment + ?.java?.javaHome?.canonicalPath + ?.let { toSystemIndependentName(it) } if (gradleHome != null) { sync.gradleHome = toSystemIndependentName(gradleHome) @@ -125,6 +130,7 @@ class KotlinDslGradleBuildSync(val workingDir: String, val taskId: ExternalSyste var project: Project? = null var gradleVersion: String? = null var gradleHome: String? = null + var javaHome: String? = null val projectRoots = mutableSetOf() val models = mutableListOf() var failed = false diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslSyncListener.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslSyncListener.kt index b3e2daef63d..7e304c834df 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslSyncListener.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslSyncListener.kt @@ -10,11 +10,15 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID import org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptDefinitionsContributor import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager import org.jetbrains.plugins.gradle.service.GradleInstallationManager +import org.jetbrains.plugins.gradle.settings.GradleExecutionSettings +import org.jetbrains.plugins.gradle.util.GradleConstants +import java.io.File import java.util.* class KotlinDslSyncListener : ExternalSystemTaskNotificationListenerAdapter() { @@ -54,8 +58,16 @@ class KotlinDslSyncListener : ExternalSystemTaskNotificationListenerAdapter() { ?.canonicalPath } + if (sync.javaHome == null) { + sync.javaHome = ExternalSystemApiUtil + .getExecutionSettings(project, sync.workingDir, GradleConstants.SYSTEM_ID) + .javaHome + } + @Suppress("DEPRECATION") - ScriptDefinitionContributor.find(project)?.reloadIfNeeded(sync.workingDir, sync.gradleHome) + ScriptDefinitionContributor.find(project)?.reloadIfNeeded( + sync.workingDir, sync.gradleHome, sync.javaHome + ) saveScriptModels(project, sync) } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRoot.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRoot.kt index 05b2b75c94a..8058f1d5cb5 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRoot.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRoot.kt @@ -88,19 +88,20 @@ class New( */ class Imported( override val pathPrefix: String, - val javaHome: File?, val data: GradleBuildRootData, lastModifiedFiles: LastModifiedFiles ) : GradleBuildRoot(lastModifiedFiles) { override val projectRoots: Collection get() = data.projectRoots + val javaHome = data.javaHome?.takeIf { it.isNotBlank() }?.let { File(it) } + fun collectConfigurations(builder: ScriptClassRootsBuilder) { if (javaHome != null) { builder.sdks.addSdk(javaHome) } - val definitions = GradleScriptDefinitionsContributor.getDefinitions(builder.project, pathPrefix, data.gradleHome) + val definitions = GradleScriptDefinitionsContributor.getDefinitions(builder.project, pathPrefix, data.gradleHome, data.javaHome) if (definitions == null) { // needed to recreate classRoots if correct script definitions weren't loaded at this moment // in this case classRoots will be recreated after script definitions update diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootData.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootData.kt index 6704da8b41d..899aab6f84e 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootData.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootData.kt @@ -11,5 +11,6 @@ data class GradleBuildRootData( val importTs: Long, val projectRoots: Collection, val gradleHome: String, + val javaHome: String?, val models: Collection ) \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootDataSerializer.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootDataSerializer.kt index 8f5789ab500..1de257bc5c2 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootDataSerializer.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootDataSerializer.kt @@ -19,7 +19,7 @@ import java.io.DataInputStream import java.io.DataOutput internal object GradleBuildRootDataSerializer { - private val attribute = FileAttribute("kotlin-dsl-script-models", 7, false) + private val attribute = FileAttribute("kotlin-dsl-script-models", 8, false) fun read(buildRoot: VirtualFile): GradleBuildRootData? { return attribute.readAttribute(buildRoot)?.use { @@ -47,6 +47,7 @@ internal fun writeKotlinDslScriptModels(output: DataOutput, data: GradleBuildRoo val strings = StringsPool.writer(output) strings.addStrings(data.projectRoots) strings.addString(data.gradleHome) + strings.addString(data.javaHome) data.models.forEach { strings.addString(it.file) strings.addStrings(it.classPath) @@ -57,6 +58,7 @@ internal fun writeKotlinDslScriptModels(output: DataOutput, data: GradleBuildRoo output.writeLong(data.importTs) strings.writeStringIds(data.projectRoots) strings.writeStringId(data.gradleHome) + strings.writeStringId(data.javaHome) output.writeList(data.models) { strings.writeStringId(it.file) output.writeString(it.inputs.sections) @@ -73,6 +75,7 @@ internal fun readKotlinDslScriptModels(input: DataInputStream, buildRoot: String val importTs = input.readLong() val projectRoots = strings.readStrings() val gradleHome = strings.readString() + val javaHome = strings.readNullableString() val models = input.readList { KotlinDslScriptModel( strings.readString(), @@ -84,7 +87,7 @@ internal fun readKotlinDslScriptModels(input: DataInputStream, buildRoot: String ) } - return GradleBuildRootData(importTs, projectRoots, gradleHome, models) + return GradleBuildRootData(importTs, projectRoots, gradleHome, javaHome, models) } private object StringsPool { @@ -99,8 +102,8 @@ private object StringsPool { ids.size } - fun addString(string: String) { - getStringId(string) + fun addString(string: String?) { + getStringId(string ?: "null") } fun addStrings(list: Collection) { @@ -119,8 +122,8 @@ private object StringsPool { } } - fun writeStringId(it: String) { - output.writeInt(getStringId(it)) + fun writeStringId(it: String?) { + output.writeInt(getStringId(it ?: "null")) } fun writeStringIds(strings: Collection) { @@ -140,6 +143,11 @@ private object StringsPool { fun getString(id: Int) = strings[id] fun readString() = getString(input.readInt()) + fun readNullableString(): String? { + val string = getString(input.readInt()) + if (string == "null") return null + return string + } fun readStrings(): List = input.readList { readString() } } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt index 0be78159dac..6e2890178ae 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt @@ -161,7 +161,10 @@ class GradleBuildRootsManager(val project: Project) : GradleBuildRootsLocator(), return } - val newData = GradleBuildRootData(sync.ts, sync.projectRoots, gradleHome, sync.models) + + val newData = GradleBuildRootData( + sync.ts, sync.projectRoots, gradleHome, sync.javaHome, sync.models + ) val mergedData = if (sync.failed && oldRoot is Imported) merge(oldRoot.data, newData) else newData val lastModifiedFilesReset = LastModifiedFiles() @@ -183,7 +186,7 @@ class GradleBuildRootsManager(val project: Project) : GradleBuildRootsLocator(), val models = old.models.associateByTo(mutableMapOf()) { it.file } new.models.associateByTo(models) { it.file } - return GradleBuildRootData(new.importTs, roots, new.gradleHome, models.values) + return GradleBuildRootData(new.importTs, roots, new.gradleHome, new.javaHome, models.values) } private val modifiedFilesCheckScheduled = AtomicBoolean() @@ -345,12 +348,8 @@ class GradleBuildRootsManager(val project: Project) : GradleBuildRootsLocator(), ): Imported? { val buildRoot = VfsUtil.findFile(Paths.get(externalProjectPath), true) ?: return null val data = dataProvider(buildRoot) ?: return null - // TODO: can be outdated, should be taken from sync - val javaHome = ExternalSystemApiUtil - .getExecutionSettings(project, externalProjectPath, GradleConstants.SYSTEM_ID) - .javaHome?.let { File(it) } - return Imported(externalProjectPath, javaHome, data, lastModifiedFiles) + return Imported(externalProjectPath, data, lastModifiedFiles) } private fun add(newRoot: GradleBuildRoot) { diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleBuildRootDataSerializerTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleBuildRootDataSerializerTest.kt index a59a5f2ef2b..951bad18de0 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleBuildRootDataSerializerTest.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleBuildRootDataSerializerTest.kt @@ -22,10 +22,11 @@ class GradleBuildRootDataSerializerTest { val data = GradleBuildRootData( 123, listOf("a", "b", "c"), - "a", + "gradleHome", + "javaHome", listOf( KotlinDslScriptModel( - "a", + "gradleHome", GradleKotlinScriptConfigurationInputs("b", 1, "a"), listOf("c", "a", "b"), listOf("b", "c", "a"), @@ -33,7 +34,7 @@ class GradleBuildRootDataSerializerTest { listOf() ), KotlinDslScriptModel( - "a", + "gradleHome", GradleKotlinScriptConfigurationInputs("b", 1, "a"), listOf("c", "a", "b"), listOf("b", "c", "a"), @@ -50,4 +51,22 @@ class GradleBuildRootDataSerializerTest { assertEquals(data.toString(), restored.toString()) } + + @Test + fun writeNullable() { + val data = GradleBuildRootData( + 0, + listOf(), + "null", + null, + listOf() + ) + + val buffer = ByteArrayOutputStream() + writeKotlinDslScriptModels(DataOutputStream(buffer), data) + + val restored = readKotlinDslScriptModels(DataInputStream(ByteArrayInputStream(buffer.toByteArray())), "a") + + assertEquals(data.toString(), restored.toString()) + } } \ No newline at end of file diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/roots/AbstractGradleBuildRootsLocatorTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/roots/AbstractGradleBuildRootsLocatorTest.kt index 4654809daac..c328966846d 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/roots/AbstractGradleBuildRootsLocatorTest.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/roots/AbstractGradleBuildRootsLocatorTest.kt @@ -35,11 +35,11 @@ open class AbstractGradleBuildRootsLocatorTest { val pathPrefix = "$dir/" val root = Imported( dir, - null, GradleBuildRootData( ts, relativeProjectRoots.map { (pathPrefix + it).removeSuffix("/") }, - "", + "gradleHome", + "javaHome", listOf() ), LastModifiedFiles()