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()
|
||||
clearClassRootsCaches()
|
||||
|
||||
cache.clear()
|
||||
|
||||
if (project.isOpen) {
|
||||
val openedScripts = FileEditorManager.getInstance(project).openFiles.filterNot { it.isNonScript() }
|
||||
updateHighlighting(openedScripts)
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
||||
override fun createCache() = object : ScriptConfigurationMemoryCache(project) {
|
||||
override fun setLoaded(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot) {
|
||||
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.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
import java.io.Serializable
|
||||
import kotlin.script.experimental.api.ScriptDiagnostic
|
||||
|
||||
/**
|
||||
@@ -55,7 +56,7 @@ data class ScriptConfigurationSnapshot(
|
||||
val configuration: ScriptCompilationConfigurationWrapper?
|
||||
)
|
||||
|
||||
interface CachedConfigurationInputs {
|
||||
interface CachedConfigurationInputs: Serializable {
|
||||
fun isUpToDate(project: Project, file: VirtualFile, ktFile: KtFile? = null): Boolean
|
||||
|
||||
object OutOfDate : CachedConfigurationInputs {
|
||||
|
||||
+41
-83
@@ -9,19 +9,19 @@ import com.intellij.openapi.project.Project
|
||||
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.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.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.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||
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.FromLegacy
|
||||
import java.io.*
|
||||
import java.io.Serializable
|
||||
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(
|
||||
val project: Project
|
||||
@@ -39,42 +39,37 @@ internal class ScriptConfigurationFileAttributeCache(
|
||||
|
||||
val virtualFile = ktFile.originalFile.virtualFile
|
||||
val fromFs = load(virtualFile) ?: return false
|
||||
val result =
|
||||
|
||||
context.saveNewConfiguration(
|
||||
virtualFile,
|
||||
ScriptConfigurationSnapshot(
|
||||
CachedConfigurationInputs.OutOfDate, // todo(KT-34444): save inputs to fs
|
||||
listOf(), // todo(KT-34444): save reports to fs
|
||||
fromFs
|
||||
fromFs.inputs,
|
||||
fromFs.reports,
|
||||
FromCompilationConfiguration(KtFileScriptSource(ktFile), fromFs.configuration)
|
||||
)
|
||||
context.saveNewConfiguration(virtualFile, result)
|
||||
return true
|
||||
)
|
||||
return fromFs.inputs.isUpToDate(ktFile.project, virtualFile, ktFile)
|
||||
}
|
||||
|
||||
private fun load(
|
||||
virtualFile: VirtualFile
|
||||
): ScriptCompilationConfigurationWrapper? {
|
||||
val ktFile = project.getKtFile(virtualFile) ?: return null
|
||||
val scriptSource = KtFileScriptSource(ktFile)
|
||||
): ScriptConfigurationSnapshotForFS? {
|
||||
val configurationSnapshot = virtualFile.scriptConfigurationSnapshot ?: return null
|
||||
debug(virtualFile) { "configuration from fileAttributes = $configurationSnapshot" }
|
||||
|
||||
val configurationFromAttributes =
|
||||
virtualFile.scriptCompilationConfiguration?.let {
|
||||
FromCompilationConfiguration(scriptSource, it)
|
||||
} ?: virtualFile.scriptDependencies?.let {
|
||||
FromLegacy(scriptSource, it, ktFile.findScriptDefinition())
|
||||
} ?: return null
|
||||
val configuration = configurationSnapshot.configuration ?: return null
|
||||
|
||||
|
||||
debug(virtualFile) { "configuration from fileAttributes = $configurationFromAttributes" }
|
||||
|
||||
if (!areDependenciesValid(virtualFile, configurationFromAttributes)) {
|
||||
if (!areDependenciesValid(virtualFile, configuration)) {
|
||||
save(virtualFile, null)
|
||||
return null
|
||||
}
|
||||
|
||||
return configurationFromAttributes
|
||||
return configurationSnapshot
|
||||
}
|
||||
|
||||
private fun areDependenciesValid(file: VirtualFile, configuration: ScriptCompilationConfigurationWrapper): Boolean {
|
||||
return configuration.dependenciesClassPath.all {
|
||||
private fun areDependenciesValid(file: VirtualFile, configuration: ScriptCompilationConfiguration): Boolean {
|
||||
val classpath = configuration.get(ScriptCompilationConfiguration.dependencies).toClassPathOrEmpty()
|
||||
return classpath.all {
|
||||
if (it.exists()) {
|
||||
true
|
||||
} else {
|
||||
@@ -83,68 +78,31 @@ internal class ScriptConfigurationFileAttributeCache(
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun save(file: VirtualFile, value: ScriptCompilationConfigurationWrapper?) {
|
||||
fun save(file: VirtualFile, value: ScriptConfigurationSnapshot?) {
|
||||
if (value == null) {
|
||||
file.scriptDependencies = null
|
||||
file.scriptCompilationConfiguration = null
|
||||
file.scriptConfigurationSnapshot = null
|
||||
} else {
|
||||
if (value is ScriptCompilationConfigurationWrapper.FromLegacy) {
|
||||
file.scriptDependencies = value.legacyDependencies
|
||||
} else {
|
||||
if (file.scriptDependencies != null) file.scriptDependencies = null
|
||||
file.scriptCompilationConfiguration = value.configuration
|
||||
}
|
||||
file.scriptConfigurationSnapshot = ScriptConfigurationSnapshotForFS(
|
||||
value.inputs,
|
||||
value.reports,
|
||||
value.configuration?.configuration
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private var VirtualFile.scriptDependencies: ScriptDependencies? by cachedFileAttribute(
|
||||
name = "kotlin-script-dependencies",
|
||||
version = 3,
|
||||
read = {
|
||||
ScriptDependencies(
|
||||
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 class ScriptConfigurationSnapshotForFS(
|
||||
val inputs: CachedConfigurationInputs,
|
||||
val reports: List<ScriptDiagnostic>,
|
||||
val configuration: ScriptCompilationConfiguration?
|
||||
) : Serializable
|
||||
|
||||
private var VirtualFile.scriptCompilationConfiguration: ScriptCompilationConfiguration? by cachedFileAttribute(
|
||||
name = "kotlin-script-compilation-configuration",
|
||||
version = 1,
|
||||
read = {
|
||||
val size = readInt()
|
||||
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)
|
||||
}
|
||||
private var VirtualFile.scriptConfigurationSnapshot: ScriptConfigurationSnapshotForFS? by cachedFileAttribute(
|
||||
name = "kotlin-script-dependencies",
|
||||
version = 4,
|
||||
read = { readObject<ScriptConfigurationSnapshotForFS>() },
|
||||
write = { writeObject<ScriptConfigurationSnapshotForFS>(it) }
|
||||
)
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -93,4 +93,24 @@ fun <T : Any> DataOutput.writeNullable(nullable: T?, writeT: DataOutput.(T) -> U
|
||||
fun <T : Any> DataInput.readNullable(readT: DataInput.() -> T): T? {
|
||||
val hasValue = readBoolean()
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file)
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,7 @@ package kotlin.script.experimental.api
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import java.lang.RuntimeException
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* The single script diagnostic report
|
||||
@@ -25,7 +25,7 @@ data class ScriptDiagnostic(
|
||||
val sourcePath: String? = null,
|
||||
val location: SourceCode.Location? = null,
|
||||
val exception: Throwable? = null
|
||||
) {
|
||||
) : Serializable {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -36,21 +36,21 @@ interface SourceCode {
|
||||
* @param col source code position column
|
||||
* @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
|
||||
* @param start range start position
|
||||
* @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
|
||||
* @param start location start position
|
||||
* @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