Store kotlin-script-cache-dependencies as project file attribute
To avoid extra root project scan we need to store already processed script cache dependencies ^KT-41640 Fixed
This commit is contained in:
+2
-3
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.components.serviceIfCreated
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.util.Key
|
||||
@@ -107,8 +106,8 @@ interface ScriptConfigurationManager {
|
||||
|
||||
fun getAllScriptsDependenciesClassFilesScope(): GlobalSearchScope
|
||||
fun getAllScriptDependenciesSourcesScope(): GlobalSearchScope
|
||||
fun getAllScriptsDependenciesClassFiles(): List<VirtualFile>
|
||||
fun getAllScriptDependenciesSources(): List<VirtualFile>
|
||||
fun getAllScriptsDependenciesClassFiles(): Collection<VirtualFile>
|
||||
fun getAllScriptDependenciesSources(): Collection<VirtualFile>
|
||||
|
||||
companion object {
|
||||
fun getServiceIfCreated(project: Project): ScriptConfigurationManager? =
|
||||
|
||||
+2
-2
@@ -162,10 +162,10 @@ class CompositeScriptConfigurationManager(val project: Project) : ScriptConfigur
|
||||
override fun getAllScriptDependenciesSourcesScope(): GlobalSearchScope =
|
||||
classpathRoots.allDependenciesSourcesScope
|
||||
|
||||
override fun getAllScriptsDependenciesClassFiles(): List<VirtualFile> =
|
||||
override fun getAllScriptsDependenciesClassFiles(): Collection<VirtualFile> =
|
||||
classpathRoots.allDependenciesClassFiles
|
||||
|
||||
override fun getAllScriptDependenciesSources(): List<VirtualFile> =
|
||||
override fun getAllScriptDependenciesSources(): Collection<VirtualFile> =
|
||||
classpathRoots.allDependenciesSources
|
||||
|
||||
///////////////////
|
||||
|
||||
+86
-10
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.ucache
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
@@ -12,9 +13,14 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.NonClasspathDirectoriesScope.compose
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager.Companion.classpathEntryToVfs
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager.Companion.toVfsRoots
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.ScriptCacheDependencies.Companion.scriptCacheDependencies
|
||||
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.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
import java.lang.ref.Reference
|
||||
import java.lang.ref.SoftReference
|
||||
|
||||
@@ -86,25 +92,25 @@ class ScriptClassRootsCache(
|
||||
val firstScriptSdk: Sdk?
|
||||
get() = sdks.first
|
||||
|
||||
val allDependenciesClassFiles: List<VirtualFile>
|
||||
val allDependenciesClassFiles: Set<VirtualFile>
|
||||
|
||||
val allDependenciesSources: List<VirtualFile>
|
||||
val allDependenciesSources: Set<VirtualFile>
|
||||
|
||||
init {
|
||||
allDependenciesClassFiles = mutableSetOf<VirtualFile>().also { result ->
|
||||
result.addAll(sdks.nonIndexedClassRoots)
|
||||
classes.mapNotNullTo(result) { classpathEntryToVfs(File(it)) }
|
||||
}.toList()
|
||||
}
|
||||
|
||||
allDependenciesSources = mutableSetOf<VirtualFile>().also { result ->
|
||||
result.addAll(sdks.nonIndexedSourceRoots)
|
||||
sources.mapNotNullTo(result) { classpathEntryToVfs(File(it)) }
|
||||
}.toList()
|
||||
}
|
||||
}
|
||||
|
||||
val allDependenciesClassFilesScope = compose(allDependenciesClassFiles)
|
||||
val allDependenciesClassFilesScope = compose(allDependenciesClassFiles.toList())
|
||||
|
||||
val allDependenciesSourcesScope = compose(allDependenciesSources)
|
||||
val allDependenciesSourcesScope = compose(allDependenciesSources.toList())
|
||||
|
||||
fun getScriptConfiguration(file: VirtualFile): ScriptCompilationConfigurationWrapper? =
|
||||
getHeavyScriptInfo(file.path)?.scriptConfiguration
|
||||
@@ -115,9 +121,9 @@ class ScriptClassRootsCache(
|
||||
fun getScriptDependenciesClassFilesScope(file: VirtualFile): GlobalSearchScope =
|
||||
getHeavyScriptInfo(file.path)?.classFilesScope ?: GlobalSearchScope.EMPTY_SCOPE
|
||||
|
||||
fun diff(old: ScriptClassRootsCache?): Updates =
|
||||
fun diff(project: Project, old: ScriptClassRootsCache?): Updates =
|
||||
when (old) {
|
||||
null -> FullUpdate(this)
|
||||
null -> FullUpdate(project, this)
|
||||
this -> NotChanged(this)
|
||||
else -> IncrementalUpdates(
|
||||
this,
|
||||
@@ -174,14 +180,15 @@ class ScriptClassRootsCache(
|
||||
get() = hasNewRoots || updatedScripts.isNotEmpty() || hasOldRoots
|
||||
}
|
||||
|
||||
class FullUpdate(override val cache: ScriptClassRootsCache) : Updates {
|
||||
class FullUpdate(private val project: Project, override val cache: ScriptClassRootsCache) : Updates {
|
||||
override val changed: Boolean get() = true
|
||||
override val hasUpdatedScripts: Boolean get() = true
|
||||
override fun isScriptChanged(scriptPath: String): Boolean = true
|
||||
|
||||
override val hasNewRoots: Boolean
|
||||
get() {
|
||||
return cache.allDependenciesClassFiles.isNotEmpty() || cache.allDependenciesSources.isNotEmpty()
|
||||
val scriptCacheDependencies = project.scriptCacheDependencies()
|
||||
return scriptCacheDependencies?.sameAs(cache) == false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,3 +200,72 @@ class ScriptClassRootsCache(
|
||||
}
|
||||
}
|
||||
|
||||
internal class ScriptCacheDependencies(
|
||||
val classFiles: Set<String>,
|
||||
val sources: Set<String>
|
||||
) : Serializable {
|
||||
constructor(cache: ScriptClassRootsCache) : this(
|
||||
cache.allDependenciesClassFiles.mapTo(HashSet(), VirtualFile::getPath),
|
||||
cache.allDependenciesSources.mapTo(HashSet(), VirtualFile::getPath)
|
||||
)
|
||||
|
||||
fun sameAs(cache: ScriptClassRootsCache): Boolean {
|
||||
if (cache.allDependenciesClassFiles.size != classFiles.size ||
|
||||
cache.allDependenciesSources.size != sources.size
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
return cache.allDependenciesClassFiles.firstOrNull {
|
||||
!classFiles.contains(it.path)
|
||||
} == null && cache.allDependenciesSources.firstOrNull {
|
||||
!sources.contains(it.path)
|
||||
} == null
|
||||
}
|
||||
|
||||
fun save(project: Project) {
|
||||
project.scriptCacheDependenciesFile()?.scriptCacheDependencies = this
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as ScriptCacheDependencies
|
||||
|
||||
return classFiles == other.classFiles && sources == other.sources
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = classFiles.hashCode()
|
||||
result = 31 * result + sources.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun Project.scriptCacheDependenciesFile(): VirtualFile? {
|
||||
var file = this.projectFile ?: return null
|
||||
while (!file.isDirectory || file.name == Project.DIRECTORY_STORE_FOLDER) {
|
||||
file = file.parent
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
fun Project.scriptCacheDependencies(): ScriptCacheDependencies? =
|
||||
try {
|
||||
scriptCacheDependenciesFile()?.scriptCacheDependencies
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private var VirtualFile.scriptCacheDependencies: ScriptCacheDependencies? by cachedFileAttribute(
|
||||
name = "kotlin-script-cache-dependencies",
|
||||
version = 1,
|
||||
read = { readObject() },
|
||||
write = { writeObject(it) }
|
||||
)
|
||||
|
||||
+4
-2
@@ -189,7 +189,9 @@ abstract class ScriptClassRootsUpdater(
|
||||
}
|
||||
}
|
||||
|
||||
lastSeen = updates.cache
|
||||
val scriptClassRootsCache = updates.cache
|
||||
ScriptCacheDependencies(scriptClassRootsCache).save(project)
|
||||
lastSeen = scriptClassRootsCache
|
||||
} finally {
|
||||
synchronized(this) {
|
||||
scheduledUpdate = null
|
||||
@@ -203,7 +205,7 @@ abstract class ScriptClassRootsUpdater(
|
||||
val new = recreateRootsCache()
|
||||
if (cache.compareAndSet(old, new)) {
|
||||
afterUpdate()
|
||||
return new.diff(lastSeen)
|
||||
return new.diff(project, lastSeen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.scripting.gradle
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
@@ -31,41 +30,39 @@ fun getGradleScriptInputsStamp(
|
||||
project: Project,
|
||||
file: VirtualFile,
|
||||
givenKtFile: KtFile? = null,
|
||||
givenTimeStamp: Long = System.currentTimeMillis()
|
||||
givenTimeStamp: Long = file.modificationStamp
|
||||
): GradleKotlinScriptConfigurationInputs? {
|
||||
if (!isGradleKotlinScript(file)) return null
|
||||
|
||||
return runReadAction {
|
||||
val ktFile = givenKtFile ?: PsiManager.getInstance(project).findFile(file) as? KtFile
|
||||
val ktFile = givenKtFile ?: PsiManager.getInstance(project).findFile(file) as? KtFile ?: return@runReadAction null
|
||||
|
||||
if (ktFile != null) {
|
||||
val result = StringBuilder()
|
||||
ktFile.script?.blockExpression
|
||||
?.getChildrenOfType<KtScriptInitializer>()
|
||||
?.forEach {
|
||||
val call = it.children.singleOrNull() as? KtCallExpression
|
||||
val callRef = call?.firstChild?.text ?: return@forEach
|
||||
if (callRef in sections) {
|
||||
result.append(callRef)
|
||||
val lambda = call.lambdaArguments.singleOrNull()
|
||||
lambda?.accept(object : PsiRecursiveElementVisitor(false) {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
super.visitElement(element)
|
||||
when (element) {
|
||||
is PsiWhiteSpace -> if (element.text.contains("\n")) result.append("\n")
|
||||
is PsiComment -> {
|
||||
}
|
||||
is LeafPsiElement -> result.append(element.text)
|
||||
val result = StringBuilder()
|
||||
ktFile.script?.blockExpression
|
||||
?.getChildrenOfType<KtScriptInitializer>()
|
||||
?.forEach {
|
||||
val call = it.children.singleOrNull() as? KtCallExpression
|
||||
val callRef = call?.firstChild?.text ?: return@forEach
|
||||
if (callRef in sections) {
|
||||
result.append(callRef)
|
||||
val lambda = call.lambdaArguments.singleOrNull()
|
||||
lambda?.accept(object : PsiRecursiveElementVisitor(false) {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
super.visitElement(element)
|
||||
when (element) {
|
||||
is PsiWhiteSpace -> if (element.text.contains("\n")) result.append("\n")
|
||||
is PsiComment -> {
|
||||
}
|
||||
is LeafPsiElement -> result.append(element.text)
|
||||
}
|
||||
})
|
||||
result.append("\n")
|
||||
}
|
||||
}
|
||||
})
|
||||
result.append("\n")
|
||||
}
|
||||
}
|
||||
|
||||
val buildRoot = GradleBuildRootsManager.getInstance(project).findScriptBuildRoot(file)?.nearest as? GradleBuildRoot
|
||||
GradleKotlinScriptConfigurationInputs(result.toString(), givenTimeStamp, buildRoot?.pathPrefix)
|
||||
} else null
|
||||
val buildRoot = GradleBuildRootsManager.getInstance(project).findScriptBuildRoot(file)?.nearest as? GradleBuildRoot
|
||||
GradleKotlinScriptConfigurationInputs(result.toString(), givenTimeStamp, buildRoot?.pathPrefix)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user