*.gradle.kts: get java home from build environment instead of execution settings

Note that getting GradleExecutionSettings may lead to write action
because it link javaHome with existing sdks

^KT-39317
This commit is contained in:
Natalia Selezneva
2020-06-29 22:37:52 +03:00
parent 5cdf053c8e
commit c7c7ffb0e0
9 changed files with 88 additions and 36 deletions
@@ -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<ScriptDefinition>? {
fun getDefinitions(project: Project, workingDir: String, gradleHome: String?, javaHome: String?): List<ScriptDefinition>? {
val contributor = ScriptDefinitionContributor.EP_NAME.getExtensions(project)
.filterIsInstance<GradleScriptDefinitionsContributor>()
.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<LightGradleBuildRoot, List<ScriptDefinition>>()
@@ -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<File>,
additionalClassPath: List<File>
): List<ScriptDefinition> {
@@ -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<GradleExecutionSettings>(
val settings = ExternalSystemApiUtil.getExecutionSettings<GradleExecutionSettings>(
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)
}
}
@@ -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<String>()
val models = mutableListOf<KotlinDslScriptModel>()
var failed = false
@@ -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<GradleExecutionSettings>(project, sync.workingDir, GradleConstants.SYSTEM_ID)
.javaHome
}
@Suppress("DEPRECATION")
ScriptDefinitionContributor.find<GradleScriptDefinitionsContributor>(project)?.reloadIfNeeded(sync.workingDir, sync.gradleHome)
ScriptDefinitionContributor.find<GradleScriptDefinitionsContributor>(project)?.reloadIfNeeded(
sync.workingDir, sync.gradleHome, sync.javaHome
)
saveScriptModels(project, sync)
}
@@ -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<String>
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
@@ -11,5 +11,6 @@ data class GradleBuildRootData(
val importTs: Long,
val projectRoots: Collection<String>,
val gradleHome: String,
val javaHome: String?,
val models: Collection<KotlinDslScriptModel>
)
@@ -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<String>) {
@@ -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<String>) {
@@ -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<String> = input.readList { readString() }
}
@@ -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<GradleExecutionSettings>(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) {
@@ -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())
}
}
@@ -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()