gradle.kts: improve service initializtion
- prevent analyzing .gradle.kts files until all services are loaded - remove services caches where it is not required - replace cached services with cache only during vfs events batch processing - prevent services loading in actions updating
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
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
|
||||||
@@ -108,6 +109,9 @@ interface ScriptConfigurationManager {
|
|||||||
fun getAllScriptDependenciesSources(): List<VirtualFile>
|
fun getAllScriptDependenciesSources(): List<VirtualFile>
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
fun getServiceIfCreated(project: Project): ScriptConfigurationManager? =
|
||||||
|
ServiceManager.getServiceIfCreated(project, ScriptConfigurationManager::class.java)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getInstance(project: Project): ScriptConfigurationManager =
|
fun getInstance(project: Project): ScriptConfigurationManager =
|
||||||
ServiceManager.getService(project, ScriptConfigurationManager::class.java)
|
ServiceManager.getService(project, ScriptConfigurationManager::class.java)
|
||||||
|
|||||||
+3
-1
@@ -84,7 +84,9 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit
|
|||||||
private val scriptDefinitionsCacheLock = ReentrantLock()
|
private val scriptDefinitionsCacheLock = ReentrantLock()
|
||||||
private val scriptDefinitionsCache = SLRUMap<String, ScriptDefinition>(10, 10)
|
private val scriptDefinitionsCache = SLRUMap<String, ScriptDefinition>(10, 10)
|
||||||
|
|
||||||
val configurations = (ScriptConfigurationManager.getInstance(project) as CompositeScriptConfigurationManager)
|
// cache service as it's getter is on the hot path
|
||||||
|
// it is safe, since both services are in same plugin
|
||||||
|
val configurations = ScriptConfigurationManager.getInstance(project) as CompositeScriptConfigurationManager
|
||||||
|
|
||||||
override fun findDefinition(script: SourceCode): ScriptDefinition? {
|
override fun findDefinition(script: SourceCode): ScriptDefinition? {
|
||||||
val locationId = script.locationId ?: return null
|
val locationId = script.locationId ?: return null
|
||||||
|
|||||||
+8
-2
@@ -27,10 +27,16 @@ class ScriptTrafficLightRendererContributor : TrafficLightRendererContributor {
|
|||||||
TrafficLightRenderer(project, document, file) {
|
TrafficLightRenderer(project, document, file) {
|
||||||
override fun getDaemonCodeAnalyzerStatus(severityRegistrar: SeverityRegistrar): DaemonCodeAnalyzerStatus {
|
override fun getDaemonCodeAnalyzerStatus(severityRegistrar: SeverityRegistrar): DaemonCodeAnalyzerStatus {
|
||||||
val status = super.getDaemonCodeAnalyzerStatus(severityRegistrar)
|
val status = super.getDaemonCodeAnalyzerStatus(severityRegistrar)
|
||||||
if (!ScriptDefinitionsManager.getInstance(file.project).isReady()) {
|
|
||||||
|
val configurations = ScriptConfigurationManager.getServiceIfCreated(project)
|
||||||
|
if (configurations == null) {
|
||||||
|
// services not yet initialized (it should be initialized under the LoadScriptDefinitionsStartupActivity)
|
||||||
|
status.reasonWhySuspended = KotlinIdeaCoreBundle.message("text.loading.kotlin.script.configuration")
|
||||||
|
status.errorAnalyzingFinished = false
|
||||||
|
} else if (!ScriptDefinitionsManager.getInstance(file.project).isReady()) {
|
||||||
status.reasonWhySuspended = KotlinIdeaCoreBundle.message("text.loading.kotlin.script.definitions")
|
status.reasonWhySuspended = KotlinIdeaCoreBundle.message("text.loading.kotlin.script.definitions")
|
||||||
status.errorAnalyzingFinished = false
|
status.errorAnalyzingFinished = false
|
||||||
} else if (ScriptConfigurationManager.getInstance(project).isConfigurationLoadingInProgress(file)) {
|
} else if (configurations.isConfigurationLoadingInProgress(file)) {
|
||||||
status.reasonWhySuspended = KotlinIdeaCoreBundle.message("text.loading.kotlin.script.configuration")
|
status.reasonWhySuspended = KotlinIdeaCoreBundle.message("text.loading.kotlin.script.configuration")
|
||||||
status.errorAnalyzingFinished = false
|
status.errorAnalyzingFinished = false
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -49,7 +49,8 @@ class CompositeScriptConfigurationManager(val project: Project) : ScriptConfigur
|
|||||||
private val classpathRoots: ScriptClassRootsCache
|
private val classpathRoots: ScriptClassRootsCache
|
||||||
get() = updater.classpathRoots
|
get() = updater.classpathRoots
|
||||||
|
|
||||||
private val plugins = ScriptingSupport.EPN.getPoint(project).extensionList
|
private val plugins
|
||||||
|
get() = ScriptingSupport.EPN.getPoint(project).extensionList
|
||||||
|
|
||||||
val default = DefaultScriptingSupport(this)
|
val default = DefaultScriptingSupport(this)
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -83,10 +83,11 @@ internal class ScriptChangesNotifier(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val defaultListener = DefaultScriptChangeListener(project)
|
private val defaultListener = DefaultScriptChangeListener(project)
|
||||||
private val listeners: Collection<ScriptChangeListener> = mutableListOf<ScriptChangeListener>().apply {
|
private val listeners: Collection<ScriptChangeListener>
|
||||||
addAll(LISTENER.getPoint(project).extensionList)
|
get() = mutableListOf<ScriptChangeListener>().apply {
|
||||||
add(defaultListener)
|
addAll(LISTENER.getPoint(project).extensionList)
|
||||||
}
|
add(defaultListener)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getListener(project: Project, file: VirtualFile): ScriptChangeListener? {
|
private fun getListener(project: Project, file: VirtualFile): ScriptChangeListener? {
|
||||||
if (project.isDisposed || areListenersDisabled()) return null
|
if (project.isDisposed || areListenersDisabled()) return null
|
||||||
|
|||||||
+2
-1
@@ -33,9 +33,10 @@ fun addVfsListener(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun apply() {
|
override fun apply() {
|
||||||
|
val fileChangesProcessor = watcher.fileChangesProcessor
|
||||||
changedFiles.forEach {
|
changedFiles.forEach {
|
||||||
LocalFileSystem.getInstance().findFileByPath(it)?.let { f ->
|
LocalFileSystem.getInstance().findFileByPath(it)?.let { f ->
|
||||||
watcher.fileChanged(f.path, f.timeStamp)
|
fileChangesProcessor(f.path, f.timeStamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -17,19 +17,22 @@ fun addVfsListener(
|
|||||||
) {
|
) {
|
||||||
VirtualFileManager.getInstance().addAsyncFileListener(
|
VirtualFileManager.getInstance().addAsyncFileListener(
|
||||||
object : AsyncFileChangeListenerBase() {
|
object : AsyncFileChangeListenerBase() {
|
||||||
|
var fileChangesProcessor = watcher.fileChangesProcessor
|
||||||
|
|
||||||
override fun isRelevant(path: String): Boolean {
|
override fun isRelevant(path: String): Boolean {
|
||||||
return buildRootsManager.maybeAffectedGradleProjectFile(path)
|
return buildRootsManager.maybeAffectedGradleProjectFile(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateFile(file: VirtualFile, event: VFileEvent) {
|
override fun updateFile(file: VirtualFile, event: VFileEvent) {
|
||||||
watcher.fileChanged(event.path, file.timeStamp)
|
fileChangesProcessor(event.path, file.timeStamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// do nothing
|
// do nothing
|
||||||
override fun prepareFileDeletion(file: VirtualFile) {}
|
override fun prepareFileDeletion(file: VirtualFile) {}
|
||||||
override fun apply() {}
|
override fun apply() {}
|
||||||
override fun reset() {}
|
override fun reset() {
|
||||||
|
fileChangesProcessor = watcher.fileChangesProcessor
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watcher.project
|
watcher.project
|
||||||
)
|
)
|
||||||
|
|||||||
+6
-1
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
|
|||||||
import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver
|
import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver
|
||||||
import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRoot
|
import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRoot
|
||||||
import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager
|
import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager
|
||||||
|
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider
|
||||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||||
import org.jetbrains.plugins.gradle.service.project.GradlePartialResolverPolicy
|
import org.jetbrains.plugins.gradle.service.project.GradlePartialResolverPolicy
|
||||||
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
|
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
|
||||||
@@ -98,10 +99,14 @@ class LoadConfigurationAction : AnAction(
|
|||||||
|
|
||||||
private fun getNotificationVisibility(editor: Editor): Boolean {
|
private fun getNotificationVisibility(editor: Editor): Boolean {
|
||||||
if (!scriptConfigurationsNeedToBeUpdatedBalloon) return false
|
if (!scriptConfigurationsNeedToBeUpdatedBalloon) return false
|
||||||
|
|
||||||
if (DiffUtil.isDiffEditor(editor)) return false
|
if (DiffUtil.isDiffEditor(editor)) return false
|
||||||
|
|
||||||
val project = editor.project ?: return false
|
val project = editor.project ?: return false
|
||||||
|
|
||||||
|
// prevent services initializtion
|
||||||
|
// (all services actually initialized under the ScriptDefinitionProvider during startup activity)
|
||||||
|
if (ScriptDefinitionProvider.getServiceIfCreated(project) == null) return false
|
||||||
|
|
||||||
val file = getKotlinScriptFile(editor) ?: return false
|
val file = getKotlinScriptFile(editor) ?: return false
|
||||||
|
|
||||||
if (autoReloadScriptConfigurations(project, file)) {
|
if (autoReloadScriptConfigurations(project, file)) {
|
||||||
|
|||||||
+13
-2
@@ -14,15 +14,26 @@ import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager
|
|||||||
class GradleScriptListener(project: Project) : ScriptChangeListener(project) {
|
class GradleScriptListener(project: Project) : ScriptChangeListener(project) {
|
||||||
// todo(gradle6): remove
|
// todo(gradle6): remove
|
||||||
private val legacy = GradleLegacyScriptListener(project)
|
private val legacy = GradleLegacyScriptListener(project)
|
||||||
private val buildRootsManager = GradleBuildRootsManager.getInstance(project)
|
|
||||||
|
private val buildRootsManager
|
||||||
|
get() = GradleBuildRootsManager.getInstance(project)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// listen changes using VFS events, including gradle-configuration related files
|
// listen changes using VFS events, including gradle-configuration related files
|
||||||
addVfsListener(this, buildRootsManager)
|
addVfsListener(this, buildRootsManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cache buildRootsManager service for hot path under vfs changes listener
|
||||||
|
val fileChangesProcessor: (filePath: String, ts: Long) -> Unit
|
||||||
|
get() {
|
||||||
|
val buildRootsManager = buildRootsManager
|
||||||
|
return { filePath, ts ->
|
||||||
|
buildRootsManager.fileChanged(filePath, ts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun fileChanged(filePath: String, ts: Long) =
|
fun fileChanged(filePath: String, ts: Long) =
|
||||||
buildRootsManager.fileChanged(filePath, ts)
|
fileChangesProcessor(filePath, ts)
|
||||||
|
|
||||||
override fun isApplicable(vFile: VirtualFile) =
|
override fun isApplicable(vFile: VirtualFile) =
|
||||||
// todo(gradle6): replace with `isCustomScriptingSupport(vFile)`
|
// todo(gradle6): replace with `isCustomScriptingSupport(vFile)`
|
||||||
|
|||||||
+2
-1
@@ -27,7 +27,8 @@ import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
|||||||
* TODO(gradle6): remove
|
* TODO(gradle6): remove
|
||||||
*/
|
*/
|
||||||
class GradleLegacyScriptConfigurationLoader(project: Project) : DefaultScriptConfigurationLoader(project) {
|
class GradleLegacyScriptConfigurationLoader(project: Project) : DefaultScriptConfigurationLoader(project) {
|
||||||
private val buildRootsManager = GradleBuildRootsManager.getInstance(project)
|
private val buildRootsManager
|
||||||
|
get() = GradleBuildRootsManager.getInstance(project)
|
||||||
|
|
||||||
override fun interceptBackgroundLoading(file: VirtualFile, isFirstLoad: Boolean, doLoad: () -> Unit): Boolean {
|
override fun interceptBackgroundLoading(file: VirtualFile, isFirstLoad: Boolean, doLoad: () -> Unit): Boolean {
|
||||||
if (!isGradleKotlinScript(file)) return false
|
if (!isGradleKotlinScript(file)) return false
|
||||||
|
|||||||
+2
-1
@@ -14,7 +14,8 @@ import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager
|
|||||||
// called from GradleScriptListener
|
// called from GradleScriptListener
|
||||||
// todo(gradle6): remove
|
// todo(gradle6): remove
|
||||||
class GradleLegacyScriptListener(project: Project) : ScriptChangeListener(project) {
|
class GradleLegacyScriptListener(project: Project) : ScriptChangeListener(project) {
|
||||||
private val buildRootsManager = GradleBuildRootsManager.getInstance(project)
|
private val buildRootsManager
|
||||||
|
get() = GradleBuildRootsManager.getInstance(project)
|
||||||
|
|
||||||
override fun isApplicable(vFile: VirtualFile) =
|
override fun isApplicable(vFile: VirtualFile) =
|
||||||
isGradleKotlinScript(vFile)
|
isGradleKotlinScript(vFile)
|
||||||
|
|||||||
+1
-2
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
|||||||
import org.jetbrains.kotlin.idea.core.script.configuration.CompositeScriptConfigurationManager
|
import org.jetbrains.kotlin.idea.core.script.configuration.CompositeScriptConfigurationManager
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.DefaultScriptingSupport
|
import org.jetbrains.kotlin.idea.core.script.configuration.DefaultScriptingSupport
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.ScriptingSupport
|
import org.jetbrains.kotlin.idea.core.script.configuration.ScriptingSupport
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.ScriptingSupport.Companion.EPN
|
|
||||||
import org.jetbrains.kotlin.idea.core.script.ucache.ScriptClassRootsBuilder
|
import org.jetbrains.kotlin.idea.core.script.ucache.ScriptClassRootsBuilder
|
||||||
import org.jetbrains.kotlin.idea.core.util.EDT
|
import org.jetbrains.kotlin.idea.core.util.EDT
|
||||||
import org.jetbrains.kotlin.idea.scripting.gradle.*
|
import org.jetbrains.kotlin.idea.scripting.gradle.*
|
||||||
@@ -456,6 +455,6 @@ class GradleBuildRootsManager(val project: Project) : GradleBuildRootsLocator(),
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getInstance(project: Project): GradleBuildRootsManager =
|
fun getInstance(project: Project): GradleBuildRootsManager =
|
||||||
EPN.getPoint(project).extensionList.firstIsInstance()
|
ScriptingSupport.EPN.findExtensionOrFail(GradleBuildRootsManager::class.java, project)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
@@ -26,6 +26,9 @@ interface ScriptDefinitionProvider {
|
|||||||
companion object {
|
companion object {
|
||||||
fun getInstance(project: Project): ScriptDefinitionProvider? =
|
fun getInstance(project: Project): ScriptDefinitionProvider? =
|
||||||
ServiceManager.getService(project, ScriptDefinitionProvider::class.java)
|
ServiceManager.getService(project, ScriptDefinitionProvider::class.java)
|
||||||
|
|
||||||
|
fun getServiceIfCreated(project: Project): ScriptDefinitionProvider? =
|
||||||
|
ServiceManager.getServiceIfCreated(project, ScriptDefinitionProvider::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user