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
|
package org.jetbrains.kotlin.idea.core.script
|
||||||
|
|
||||||
import com.intellij.openapi.components.ServiceManager
|
import com.intellij.openapi.components.ServiceManager
|
||||||
import com.intellij.openapi.components.serviceIfCreated
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.projectRoots.Sdk
|
import com.intellij.openapi.projectRoots.Sdk
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
@@ -107,8 +106,8 @@ interface ScriptConfigurationManager {
|
|||||||
|
|
||||||
fun getAllScriptsDependenciesClassFilesScope(): GlobalSearchScope
|
fun getAllScriptsDependenciesClassFilesScope(): GlobalSearchScope
|
||||||
fun getAllScriptDependenciesSourcesScope(): GlobalSearchScope
|
fun getAllScriptDependenciesSourcesScope(): GlobalSearchScope
|
||||||
fun getAllScriptsDependenciesClassFiles(): List<VirtualFile>
|
fun getAllScriptsDependenciesClassFiles(): Collection<VirtualFile>
|
||||||
fun getAllScriptDependenciesSources(): List<VirtualFile>
|
fun getAllScriptDependenciesSources(): Collection<VirtualFile>
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getServiceIfCreated(project: Project): ScriptConfigurationManager? =
|
fun getServiceIfCreated(project: Project): ScriptConfigurationManager? =
|
||||||
|
|||||||
+2
-2
@@ -162,10 +162,10 @@ class CompositeScriptConfigurationManager(val project: Project) : ScriptConfigur
|
|||||||
override fun getAllScriptDependenciesSourcesScope(): GlobalSearchScope =
|
override fun getAllScriptDependenciesSourcesScope(): GlobalSearchScope =
|
||||||
classpathRoots.allDependenciesSourcesScope
|
classpathRoots.allDependenciesSourcesScope
|
||||||
|
|
||||||
override fun getAllScriptsDependenciesClassFiles(): List<VirtualFile> =
|
override fun getAllScriptsDependenciesClassFiles(): Collection<VirtualFile> =
|
||||||
classpathRoots.allDependenciesClassFiles
|
classpathRoots.allDependenciesClassFiles
|
||||||
|
|
||||||
override fun getAllScriptDependenciesSources(): List<VirtualFile> =
|
override fun getAllScriptDependenciesSources(): Collection<VirtualFile> =
|
||||||
classpathRoots.allDependenciesSources
|
classpathRoots.allDependenciesSources
|
||||||
|
|
||||||
///////////////////
|
///////////////////
|
||||||
|
|||||||
+86
-10
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.core.script.ucache
|
package org.jetbrains.kotlin.idea.core.script.ucache
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.projectRoots.Sdk
|
import com.intellij.openapi.projectRoots.Sdk
|
||||||
import com.intellij.openapi.roots.OrderRootType
|
import com.intellij.openapi.roots.OrderRootType
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
@@ -12,9 +13,14 @@ import com.intellij.psi.search.GlobalSearchScope
|
|||||||
import com.intellij.psi.search.NonClasspathDirectoriesScope.compose
|
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.classpathEntryToVfs
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager.Companion.toVfsRoots
|
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.definitions.ScriptDefinition
|
||||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.Serializable
|
||||||
import java.lang.ref.Reference
|
import java.lang.ref.Reference
|
||||||
import java.lang.ref.SoftReference
|
import java.lang.ref.SoftReference
|
||||||
|
|
||||||
@@ -86,25 +92,25 @@ class ScriptClassRootsCache(
|
|||||||
val firstScriptSdk: Sdk?
|
val firstScriptSdk: Sdk?
|
||||||
get() = sdks.first
|
get() = sdks.first
|
||||||
|
|
||||||
val allDependenciesClassFiles: List<VirtualFile>
|
val allDependenciesClassFiles: Set<VirtualFile>
|
||||||
|
|
||||||
val allDependenciesSources: List<VirtualFile>
|
val allDependenciesSources: Set<VirtualFile>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
allDependenciesClassFiles = mutableSetOf<VirtualFile>().also { result ->
|
allDependenciesClassFiles = mutableSetOf<VirtualFile>().also { result ->
|
||||||
result.addAll(sdks.nonIndexedClassRoots)
|
result.addAll(sdks.nonIndexedClassRoots)
|
||||||
classes.mapNotNullTo(result) { classpathEntryToVfs(File(it)) }
|
classes.mapNotNullTo(result) { classpathEntryToVfs(File(it)) }
|
||||||
}.toList()
|
}
|
||||||
|
|
||||||
allDependenciesSources = mutableSetOf<VirtualFile>().also { result ->
|
allDependenciesSources = mutableSetOf<VirtualFile>().also { result ->
|
||||||
result.addAll(sdks.nonIndexedSourceRoots)
|
result.addAll(sdks.nonIndexedSourceRoots)
|
||||||
sources.mapNotNullTo(result) { classpathEntryToVfs(File(it)) }
|
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? =
|
fun getScriptConfiguration(file: VirtualFile): ScriptCompilationConfigurationWrapper? =
|
||||||
getHeavyScriptInfo(file.path)?.scriptConfiguration
|
getHeavyScriptInfo(file.path)?.scriptConfiguration
|
||||||
@@ -115,9 +121,9 @@ class ScriptClassRootsCache(
|
|||||||
fun getScriptDependenciesClassFilesScope(file: VirtualFile): GlobalSearchScope =
|
fun getScriptDependenciesClassFilesScope(file: VirtualFile): GlobalSearchScope =
|
||||||
getHeavyScriptInfo(file.path)?.classFilesScope ?: GlobalSearchScope.EMPTY_SCOPE
|
getHeavyScriptInfo(file.path)?.classFilesScope ?: GlobalSearchScope.EMPTY_SCOPE
|
||||||
|
|
||||||
fun diff(old: ScriptClassRootsCache?): Updates =
|
fun diff(project: Project, old: ScriptClassRootsCache?): Updates =
|
||||||
when (old) {
|
when (old) {
|
||||||
null -> FullUpdate(this)
|
null -> FullUpdate(project, this)
|
||||||
this -> NotChanged(this)
|
this -> NotChanged(this)
|
||||||
else -> IncrementalUpdates(
|
else -> IncrementalUpdates(
|
||||||
this,
|
this,
|
||||||
@@ -174,14 +180,15 @@ class ScriptClassRootsCache(
|
|||||||
get() = hasNewRoots || updatedScripts.isNotEmpty() || hasOldRoots
|
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 changed: Boolean get() = true
|
||||||
override val hasUpdatedScripts: Boolean get() = true
|
override val hasUpdatedScripts: Boolean get() = true
|
||||||
override fun isScriptChanged(scriptPath: String): Boolean = true
|
override fun isScriptChanged(scriptPath: String): Boolean = true
|
||||||
|
|
||||||
override val hasNewRoots: Boolean
|
override val hasNewRoots: Boolean
|
||||||
get() {
|
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 {
|
} finally {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
scheduledUpdate = null
|
scheduledUpdate = null
|
||||||
@@ -203,7 +205,7 @@ abstract class ScriptClassRootsUpdater(
|
|||||||
val new = recreateRootsCache()
|
val new = recreateRootsCache()
|
||||||
if (cache.compareAndSet(old, new)) {
|
if (cache.compareAndSet(old, new)) {
|
||||||
afterUpdate()
|
afterUpdate()
|
||||||
return new.diff(lastSeen)
|
return new.diff(project, lastSeen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.scripting.gradle
|
package org.jetbrains.kotlin.idea.scripting.gradle
|
||||||
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
|
||||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
@@ -31,41 +30,39 @@ fun getGradleScriptInputsStamp(
|
|||||||
project: Project,
|
project: Project,
|
||||||
file: VirtualFile,
|
file: VirtualFile,
|
||||||
givenKtFile: KtFile? = null,
|
givenKtFile: KtFile? = null,
|
||||||
givenTimeStamp: Long = System.currentTimeMillis()
|
givenTimeStamp: Long = file.modificationStamp
|
||||||
): GradleKotlinScriptConfigurationInputs? {
|
): GradleKotlinScriptConfigurationInputs? {
|
||||||
if (!isGradleKotlinScript(file)) return null
|
if (!isGradleKotlinScript(file)) return null
|
||||||
|
|
||||||
return runReadAction {
|
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()
|
||||||
val result = StringBuilder()
|
ktFile.script?.blockExpression
|
||||||
ktFile.script?.blockExpression
|
?.getChildrenOfType<KtScriptInitializer>()
|
||||||
?.getChildrenOfType<KtScriptInitializer>()
|
?.forEach {
|
||||||
?.forEach {
|
val call = it.children.singleOrNull() as? KtCallExpression
|
||||||
val call = it.children.singleOrNull() as? KtCallExpression
|
val callRef = call?.firstChild?.text ?: return@forEach
|
||||||
val callRef = call?.firstChild?.text ?: return@forEach
|
if (callRef in sections) {
|
||||||
if (callRef in sections) {
|
result.append(callRef)
|
||||||
result.append(callRef)
|
val lambda = call.lambdaArguments.singleOrNull()
|
||||||
val lambda = call.lambdaArguments.singleOrNull()
|
lambda?.accept(object : PsiRecursiveElementVisitor(false) {
|
||||||
lambda?.accept(object : PsiRecursiveElementVisitor(false) {
|
override fun visitElement(element: PsiElement) {
|
||||||
override fun visitElement(element: PsiElement) {
|
super.visitElement(element)
|
||||||
super.visitElement(element)
|
when (element) {
|
||||||
when (element) {
|
is PsiWhiteSpace -> if (element.text.contains("\n")) result.append("\n")
|
||||||
is PsiWhiteSpace -> if (element.text.contains("\n")) result.append("\n")
|
is PsiComment -> {
|
||||||
is PsiComment -> {
|
|
||||||
}
|
|
||||||
is LeafPsiElement -> result.append(element.text)
|
|
||||||
}
|
}
|
||||||
|
is LeafPsiElement -> result.append(element.text)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
result.append("\n")
|
})
|
||||||
}
|
result.append("\n")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val buildRoot = GradleBuildRootsManager.getInstance(project).findScriptBuildRoot(file)?.nearest as? GradleBuildRoot
|
val buildRoot = GradleBuildRootsManager.getInstance(project).findScriptBuildRoot(file)?.nearest as? GradleBuildRoot
|
||||||
GradleKotlinScriptConfigurationInputs(result.toString(), givenTimeStamp, buildRoot?.pathPrefix)
|
GradleKotlinScriptConfigurationInputs(result.toString(), givenTimeStamp, buildRoot?.pathPrefix)
|
||||||
} else null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user