Scripting: save inputs stamp and diagnostics to file attributes
Check if they are up to date and initiate configuration update only in case they are out of date ^KT-35205
This commit is contained in:
+2
@@ -225,6 +225,8 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
// todo: cache.clear()
|
// todo: cache.clear()
|
||||||
clearClassRootsCaches()
|
clearClassRootsCaches()
|
||||||
|
|
||||||
|
cache.clear()
|
||||||
|
|
||||||
if (project.isOpen) {
|
if (project.isOpen) {
|
||||||
val openedScripts = FileEditorManager.getInstance(project).openFiles.filterNot { it.isNonScript() }
|
val openedScripts = FileEditorManager.getInstance(project).openFiles.filterNot { it.isNonScript() }
|
||||||
updateHighlighting(openedScripts)
|
updateHighlighting(openedScripts)
|
||||||
|
|||||||
+1
-1
@@ -124,7 +124,7 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
override fun createCache() = object : ScriptConfigurationMemoryCache(project) {
|
override fun createCache() = object : ScriptConfigurationMemoryCache(project) {
|
||||||
override fun setLoaded(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot) {
|
override fun setLoaded(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot) {
|
||||||
super.setLoaded(file, configurationSnapshot)
|
super.setLoaded(file, configurationSnapshot)
|
||||||
fileAttributeCache.save(file, configurationSnapshot.configuration)
|
fileAttributeCache.save(file, configurationSnapshot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.idea.core.script.configuration.utils.getKtFile
|
|||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||||
|
import java.io.Serializable
|
||||||
import kotlin.script.experimental.api.ScriptDiagnostic
|
import kotlin.script.experimental.api.ScriptDiagnostic
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,7 +56,7 @@ data class ScriptConfigurationSnapshot(
|
|||||||
val configuration: ScriptCompilationConfigurationWrapper?
|
val configuration: ScriptCompilationConfigurationWrapper?
|
||||||
)
|
)
|
||||||
|
|
||||||
interface CachedConfigurationInputs {
|
interface CachedConfigurationInputs: Serializable {
|
||||||
fun isUpToDate(project: Project, file: VirtualFile, ktFile: KtFile? = null): Boolean
|
fun isUpToDate(project: Project, file: VirtualFile, ktFile: KtFile? = null): Boolean
|
||||||
|
|
||||||
object OutOfDate : CachedConfigurationInputs {
|
object OutOfDate : CachedConfigurationInputs {
|
||||||
|
|||||||
+41
-83
@@ -9,19 +9,19 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.loader.ScriptConfigurationLoader
|
import org.jetbrains.kotlin.idea.core.script.configuration.loader.ScriptConfigurationLoader
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.loader.ScriptConfigurationLoadingContext
|
import org.jetbrains.kotlin.idea.core.script.configuration.loader.ScriptConfigurationLoadingContext
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.utils.getKtFile
|
|
||||||
import org.jetbrains.kotlin.idea.core.script.debug
|
import org.jetbrains.kotlin.idea.core.script.debug
|
||||||
import org.jetbrains.kotlin.idea.core.util.*
|
import org.jetbrains.kotlin.idea.core.util.cachedFileAttribute
|
||||||
|
import org.jetbrains.kotlin.idea.core.util.readObject
|
||||||
|
import org.jetbrains.kotlin.idea.core.util.writeObject
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
|
||||||
import org.jetbrains.kotlin.scripting.resolve.KtFileScriptSource
|
import org.jetbrains.kotlin.scripting.resolve.KtFileScriptSource
|
||||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
|
||||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper.FromCompilationConfiguration
|
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper.FromCompilationConfiguration
|
||||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper.FromLegacy
|
import java.io.Serializable
|
||||||
import java.io.*
|
|
||||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
import kotlin.script.experimental.api.ScriptDiagnostic
|
||||||
|
import kotlin.script.experimental.api.dependencies
|
||||||
|
import kotlin.script.experimental.jvm.impl.toClassPathOrEmpty
|
||||||
|
|
||||||
internal class ScriptConfigurationFileAttributeCache(
|
internal class ScriptConfigurationFileAttributeCache(
|
||||||
val project: Project
|
val project: Project
|
||||||
@@ -39,42 +39,37 @@ internal class ScriptConfigurationFileAttributeCache(
|
|||||||
|
|
||||||
val virtualFile = ktFile.originalFile.virtualFile
|
val virtualFile = ktFile.originalFile.virtualFile
|
||||||
val fromFs = load(virtualFile) ?: return false
|
val fromFs = load(virtualFile) ?: return false
|
||||||
val result =
|
|
||||||
|
context.saveNewConfiguration(
|
||||||
|
virtualFile,
|
||||||
ScriptConfigurationSnapshot(
|
ScriptConfigurationSnapshot(
|
||||||
CachedConfigurationInputs.OutOfDate, // todo(KT-34444): save inputs to fs
|
fromFs.inputs,
|
||||||
listOf(), // todo(KT-34444): save reports to fs
|
fromFs.reports,
|
||||||
fromFs
|
FromCompilationConfiguration(KtFileScriptSource(ktFile), fromFs.configuration)
|
||||||
)
|
)
|
||||||
context.saveNewConfiguration(virtualFile, result)
|
)
|
||||||
return true
|
return fromFs.inputs.isUpToDate(ktFile.project, virtualFile, ktFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun load(
|
private fun load(
|
||||||
virtualFile: VirtualFile
|
virtualFile: VirtualFile
|
||||||
): ScriptCompilationConfigurationWrapper? {
|
): ScriptConfigurationSnapshotForFS? {
|
||||||
val ktFile = project.getKtFile(virtualFile) ?: return null
|
val configurationSnapshot = virtualFile.scriptConfigurationSnapshot ?: return null
|
||||||
val scriptSource = KtFileScriptSource(ktFile)
|
debug(virtualFile) { "configuration from fileAttributes = $configurationSnapshot" }
|
||||||
|
|
||||||
val configurationFromAttributes =
|
val configuration = configurationSnapshot.configuration ?: return null
|
||||||
virtualFile.scriptCompilationConfiguration?.let {
|
|
||||||
FromCompilationConfiguration(scriptSource, it)
|
|
||||||
} ?: virtualFile.scriptDependencies?.let {
|
|
||||||
FromLegacy(scriptSource, it, ktFile.findScriptDefinition())
|
|
||||||
} ?: return null
|
|
||||||
|
|
||||||
|
if (!areDependenciesValid(virtualFile, configuration)) {
|
||||||
debug(virtualFile) { "configuration from fileAttributes = $configurationFromAttributes" }
|
|
||||||
|
|
||||||
if (!areDependenciesValid(virtualFile, configurationFromAttributes)) {
|
|
||||||
save(virtualFile, null)
|
save(virtualFile, null)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return configurationFromAttributes
|
return configurationSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun areDependenciesValid(file: VirtualFile, configuration: ScriptCompilationConfigurationWrapper): Boolean {
|
private fun areDependenciesValid(file: VirtualFile, configuration: ScriptCompilationConfiguration): Boolean {
|
||||||
return configuration.dependenciesClassPath.all {
|
val classpath = configuration.get(ScriptCompilationConfiguration.dependencies).toClassPathOrEmpty()
|
||||||
|
return classpath.all {
|
||||||
if (it.exists()) {
|
if (it.exists()) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@@ -83,68 +78,31 @@ internal class ScriptConfigurationFileAttributeCache(
|
|||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save(file: VirtualFile, value: ScriptCompilationConfigurationWrapper?) {
|
fun save(file: VirtualFile, value: ScriptConfigurationSnapshot?) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
file.scriptDependencies = null
|
file.scriptConfigurationSnapshot = null
|
||||||
file.scriptCompilationConfiguration = null
|
|
||||||
} else {
|
} else {
|
||||||
if (value is ScriptCompilationConfigurationWrapper.FromLegacy) {
|
file.scriptConfigurationSnapshot = ScriptConfigurationSnapshotForFS(
|
||||||
file.scriptDependencies = value.legacyDependencies
|
value.inputs,
|
||||||
} else {
|
value.reports,
|
||||||
if (file.scriptDependencies != null) file.scriptDependencies = null
|
value.configuration?.configuration
|
||||||
file.scriptCompilationConfiguration = value.configuration
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var VirtualFile.scriptDependencies: ScriptDependencies? by cachedFileAttribute(
|
private class ScriptConfigurationSnapshotForFS(
|
||||||
name = "kotlin-script-dependencies",
|
val inputs: CachedConfigurationInputs,
|
||||||
version = 3,
|
val reports: List<ScriptDiagnostic>,
|
||||||
read = {
|
val configuration: ScriptCompilationConfiguration?
|
||||||
ScriptDependencies(
|
) : Serializable
|
||||||
classpath = readFileList(),
|
|
||||||
imports = readStringList(),
|
|
||||||
javaHome = readNullable(DataInput::readFile),
|
|
||||||
scripts = readFileList(),
|
|
||||||
sources = readFileList()
|
|
||||||
)
|
|
||||||
},
|
|
||||||
write = {
|
|
||||||
with(it) {
|
|
||||||
writeFileList(classpath)
|
|
||||||
writeStringList(imports)
|
|
||||||
writeNullable(javaHome, DataOutput::writeFile)
|
|
||||||
writeFileList(scripts)
|
|
||||||
writeFileList(sources)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
private var VirtualFile.scriptCompilationConfiguration: ScriptCompilationConfiguration? by cachedFileAttribute(
|
private var VirtualFile.scriptConfigurationSnapshot: ScriptConfigurationSnapshotForFS? by cachedFileAttribute(
|
||||||
name = "kotlin-script-compilation-configuration",
|
name = "kotlin-script-dependencies",
|
||||||
version = 1,
|
version = 4,
|
||||||
read = {
|
read = { readObject<ScriptConfigurationSnapshotForFS>() },
|
||||||
val size = readInt()
|
write = { writeObject<ScriptConfigurationSnapshotForFS>(it) }
|
||||||
val bytes = ByteArray(size)
|
|
||||||
read(bytes, 0, size)
|
|
||||||
val bis = ByteArrayInputStream(bytes)
|
|
||||||
ObjectInputStream(bis).use { ois ->
|
|
||||||
ois.readObject() as ScriptCompilationConfiguration
|
|
||||||
}
|
|
||||||
},
|
|
||||||
write = {
|
|
||||||
val os = ByteArrayOutputStream()
|
|
||||||
ObjectOutputStream(os).use { oos ->
|
|
||||||
oos.writeObject(it)
|
|
||||||
}
|
|
||||||
val bytes = os.toByteArray()
|
|
||||||
writeInt(bytes.size)
|
|
||||||
write(bytes)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -94,3 +94,23 @@ fun <T : Any> DataInput.readNullable(readT: DataInput.() -> T): T? {
|
|||||||
val hasValue = readBoolean()
|
val hasValue = readBoolean()
|
||||||
return if (hasValue) readT() else null
|
return if (hasValue) readT() else null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> DataOutputStream.writeObject(obj: T) {
|
||||||
|
val os = ByteArrayOutputStream()
|
||||||
|
ObjectOutputStream(os).use { oos ->
|
||||||
|
oos.writeObject(obj)
|
||||||
|
}
|
||||||
|
val bytes = os.toByteArray()
|
||||||
|
writeInt(bytes.size)
|
||||||
|
write(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> DataInputStream.readObject(): T {
|
||||||
|
val size = readInt()
|
||||||
|
val bytes = ByteArray(size)
|
||||||
|
read(bytes, 0, size)
|
||||||
|
val bis = ByteArrayInputStream(bytes)
|
||||||
|
return ObjectInputStream(bis).use { ois ->
|
||||||
|
ois.readObject() as T
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -87,6 +87,46 @@ class GradleScriptInputsWatcherTest : AbstractScriptConfigurationLoadingTest() {
|
|||||||
assertConfigurationUpToDate(testFiles.settings)
|
assertConfigurationUpToDate(testFiles.settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testFileAttributes() {
|
||||||
|
assertAndLoadInitialConfiguration(testFiles.buildKts)
|
||||||
|
|
||||||
|
scriptConfigurationManager.clearConfigurationCachesAndRehighlight()
|
||||||
|
|
||||||
|
assertConfigurationUpToDate(testFiles.buildKts)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFileAttributesUpToDate() {
|
||||||
|
assertAndLoadInitialConfiguration(testFiles.buildKts)
|
||||||
|
|
||||||
|
scriptConfigurationManager.clearConfigurationCachesAndRehighlight()
|
||||||
|
|
||||||
|
changeBuildKtsInsideSections()
|
||||||
|
|
||||||
|
assertConfigurationUpdateWasDone(testFiles.buildKts)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFileAttributesUpToDateAfterChangeOutsideSections() {
|
||||||
|
assertAndLoadInitialConfiguration(testFiles.buildKts)
|
||||||
|
|
||||||
|
scriptConfigurationManager.clearConfigurationCachesAndRehighlight()
|
||||||
|
|
||||||
|
changeBuildKtsOutsideSections()
|
||||||
|
|
||||||
|
assertConfigurationUpToDate(testFiles.buildKts)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFileAttributesUpdateAfterChangeOutsideSectionsOfOtherFile() {
|
||||||
|
assertAndLoadInitialConfiguration(testFiles.buildKts)
|
||||||
|
assertAndLoadInitialConfiguration(testFiles.settings)
|
||||||
|
|
||||||
|
scriptConfigurationManager.clearConfigurationCachesAndRehighlight()
|
||||||
|
|
||||||
|
changeSettingsKtsOutsideSections()
|
||||||
|
|
||||||
|
assertConfigurationUpToDate(testFiles.settings)
|
||||||
|
assertConfigurationUpdateWasDone(testFiles.buildKts)
|
||||||
|
}
|
||||||
|
|
||||||
private fun assertConfigurationUpToDate(file: KtFile) {
|
private fun assertConfigurationUpToDate(file: KtFile) {
|
||||||
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file)
|
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file)
|
||||||
assertNoBackgroundTasks()
|
assertNoBackgroundTasks()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ package kotlin.script.experimental.api
|
|||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import java.lang.RuntimeException
|
import java.io.Serializable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The single script diagnostic report
|
* The single script diagnostic report
|
||||||
@@ -25,7 +25,7 @@ data class ScriptDiagnostic(
|
|||||||
val sourcePath: String? = null,
|
val sourcePath: String? = null,
|
||||||
val location: SourceCode.Location? = null,
|
val location: SourceCode.Location? = null,
|
||||||
val exception: Throwable? = null
|
val exception: Throwable? = null
|
||||||
) {
|
) : Serializable {
|
||||||
/**
|
/**
|
||||||
* The diagnostic severity
|
* The diagnostic severity
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -36,21 +36,21 @@ interface SourceCode {
|
|||||||
* @param col source code position column
|
* @param col source code position column
|
||||||
* @param absolutePos absolute source code text position, if available
|
* @param absolutePos absolute source code text position, if available
|
||||||
*/
|
*/
|
||||||
data class Position(val line: Int, val col: Int, val absolutePos: Int? = null)
|
data class Position(val line: Int, val col: Int, val absolutePos: Int? = null) : Serializable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The source code positions range
|
* The source code positions range
|
||||||
* @param start range start position
|
* @param start range start position
|
||||||
* @param end range end position (after the last char)
|
* @param end range end position (after the last char)
|
||||||
*/
|
*/
|
||||||
data class Range(val start: Position, val end: Position)
|
data class Range(val start: Position, val end: Position) : Serializable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The source code location, pointing either at a position or at a range
|
* The source code location, pointing either at a position or at a range
|
||||||
* @param start location start position
|
* @param start location start position
|
||||||
* @param end optional range location end position (after the last char)
|
* @param end optional range location end position (after the last char)
|
||||||
*/
|
*/
|
||||||
data class Location(val start: Position, val end: Position? = null)
|
data class Location(val start: Position, val end: Position? = null) : Serializable
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user