diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/utils/ScriptClassRootsUpdater.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/utils/ScriptClassRootsUpdater.kt index f1a9093feec..6e8d4c7d2ec 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/utils/ScriptClassRootsUpdater.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/utils/ScriptClassRootsUpdater.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.core.script.configuration.utils import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.TransactionGuard +import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.util.BackgroundTaskUtil diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleBuildRoot.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleBuildRoot.kt deleted file mode 100644 index 3a6c8a8d7cc..00000000000 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleBuildRoot.kt +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2010-2020 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. - */ - -package org.jetbrains.kotlin.idea.scripting.gradle - -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.LocalFileSystem -import com.intellij.openapi.vfs.VfsUtil -import com.intellij.openapi.vfs.VirtualFile -import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor -import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsCache -import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel -import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition -import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper -import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource -import org.jetbrains.kotlin.scripting.resolve.adjustByDefinition -import java.io.File -import kotlin.script.experimental.api.* -import kotlin.script.experimental.jvm.JvmDependency -import kotlin.script.experimental.jvm.jdkHome -import kotlin.script.experimental.jvm.jvm - -sealed class GradleBuildRoot { - abstract val pathPrefix: String - - /** - * Add Gradle Project - * for other scripts too - * - * definitely not precompiled scripts (it is detected as in sources roots) - * may be also included scripts not returned by gradle: todo proper notification - */ - class Unlinked(override val pathPrefix: String) : GradleBuildRoot() - - abstract class Linked : GradleBuildRoot() { - @Volatile - var importing = false - } - - /** - * Notification: please update to Gradle 6.0 - * default loader, cases: - * - not loaded: todo: Notification: Load configration to get code insights - * - loaded, not up-to-date: Notifaction: Reload configuraiton - * - loaded, up-to-date: Nothing - */ - class Legacy(override val pathPrefix: String) : Linked() - - /** - * not imported: - * Notification: Import Gradle project to get code insights - * during import: - * - todo: disable action on importing. don't miss failed import - * - pause analyzing, todo: change status text to: importing gradle project - * - * todo: - * detect precompiled scripts (in sources roots) - */ - class New(override val pathPrefix: String) : Linked() - - // precompiled scripts not detected by gradle - - class Imported( - val project: Project, - val dir: VirtualFile, - val context: GradleKtsContext, - val data: GradleImportedBuildRootData - ) : Linked() { - override val pathPrefix: String = dir.path - - fun collectConfigurations(builder: ScriptClassRootsCache.Builder) { - val javaHome = context.javaHome - javaHome?.let { builder.addSdk(it) } - - val definitions = ScriptDefinitionContributor.EP_NAME.getExtensions(project) - .filterIsInstance() - .single().definitions.toList() - - builder.classes.addAll(data.templateClasspath) - data.models.forEach { script -> - val vFile = LocalFileSystem.getInstance().findFileByPath(script.file) - val def = if (vFile != null) { - val src = VirtualFileScriptSource(vFile) - definitions.firstOrNull { it.isScript(src) } - } else null - - builder.scripts[script.file] = ScriptInfo(this, def, script) - - builder.classes.addAll(script.classPath) - builder.sources.addAll(script.sourcePath) - } - } - - class ScriptInfo( - val buildRoot: Imported, - scriptDefinition: ScriptDefinition?, - val model: KotlinDslScriptModel - ) : ScriptClassRootsCache.LightScriptInfo(scriptDefinition) { - - override fun buildConfiguration(): ScriptCompilationConfigurationWrapper? { - val javaHome = buildRoot.context.javaHome - - val scriptFile = File(model.file) - val virtualFile = VfsUtil.findFile(scriptFile.toPath(), true)!! - - if (definition == null) return null - - return ScriptCompilationConfigurationWrapper.FromCompilationConfiguration( - VirtualFileScriptSource(virtualFile), - definition.compilationConfiguration.with { - if (javaHome != null) { - jvm.jdkHome(javaHome) - } - defaultImports(model.imports) - dependencies(JvmDependency(model.classPath.map { File(it) })) - ide.dependenciesSources(JvmDependency(model.sourcePath.map { File(it) })) - }.adjustByDefinition(definition) - ) - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as ScriptInfo - - if (buildRoot.pathPrefix != other.buildRoot.pathPrefix) return false - if (model != other.model) return false - if (definition != other.definition) return false - - return true - } - - override fun hashCode(): Int { - var result = buildRoot.pathPrefix.hashCode() - result = 31 * result + model.hashCode() - result = 31 * result + definition.hashCode() - return result - } - } - } -} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt index 25dab3b34c9..06e8967c07a 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt @@ -38,7 +38,6 @@ private const val kotlinDslNotificationGroupId = "Gradle Kotlin DSL Scripts" private var Project.notificationPanel: ScriptConfigurationChangedNotification? by UserDataProperty(Key.create("load.script.configuration.panel")) - fun showNotificationForProjectImport(project: Project) { val existingPanel = project.notificationPanel if (existingPanel != null) { diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.201 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.201 index abe27c57ab4..368c521591a 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.201 +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.201 @@ -21,19 +21,17 @@ import com.intellij.testFramework.LightVirtualFileBase import org.jetbrains.kotlin.idea.KotlinIcons import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver -import org.jetbrains.kotlin.psi.UserDataProperty +import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager import org.jetbrains.plugins.gradle.service.project.GradlePartialResolverPolicy -import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverExtension import org.jetbrains.plugins.gradle.util.GradleConstants -import java.util.function.Predicate fun runPartialGradleImport(project: Project) { - getGradleProjectSettings(project).forEach { + getGradleProjectSettings(project).forEach { gradleProjectSettings -> ExternalSystemUtil.refreshProject( - it.externalProjectPath, + gradleProjectSettings.externalProjectPath, ImportSpecBuilder(project, GradleConstants.SYSTEM_ID) .projectResolverPolicy( - GradlePartialResolverPolicy(Predicate { it is KotlinDslScriptModelResolver }) + GradlePartialResolverPolicy { it is KotlinDslScriptModelResolver } ) ) } @@ -81,6 +79,6 @@ class LoadConfigurationAction : AnAction( if (virtualFile is LightVirtualFileBase) return false if (virtualFile == null || !virtualFile.isValid) return false - return GradleScriptingSupportProvider.getInstance(project).isConfigurationOutOfDate(virtualFile) + return GradleBuildRootsManager.getInstance(project).isConfigurationOutOfDate(virtualFile) } } \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKtsContext.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKtsContext.kt deleted file mode 100644 index e9a143defd5..00000000000 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKtsContext.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2010-2020 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. - */ - -package org.jetbrains.kotlin.idea.scripting.gradle - -import java.io.File - -class GradleKtsContext(val javaHome: File?) \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptDefinitionsProvider.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptDefinitionsProvider.kt index f606109975d..de935af6ad8 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptDefinitionsProvider.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptDefinitionsProvider.kt @@ -11,6 +11,7 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.project.Project import com.intellij.util.EnvironmentUtil import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle +import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionSourceAsContributor import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplates @@ -40,6 +41,21 @@ import kotlin.script.experimental.location.ScriptExpectedLocation import kotlin.script.templates.standard.ScriptTemplateWithArgs class GradleScriptDefinitionsContributor(private val project: Project) : ScriptDefinitionSourceAsContributor { + companion object { + fun getDefinitions(project: Project) = + ScriptDefinitionContributor.EP_NAME.getExtensions(project) + .filterIsInstance() + .single().definitions.toList() + + fun getDefinitionsTemplateClasspath(project: Project): MutableSet = + mutableSetOf().also { result -> + getDefinitions(project).forEach { definition -> + definition.asLegacyOrNull() + ?.templateClasspath + ?.mapNotNullTo(result) { it.path } + } + } + } override val id: String = "Gradle Kotlin DSL" private val failedToLoad = AtomicBoolean(false) @@ -128,8 +144,8 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD private fun kotlinStdlibAndCompiler(gradleLibDir: File): List { // additionally need compiler jar to load gradle resolver return gradleLibDir.listFiles { file -> - file.name.startsWith("kotlin-compiler-embeddable") || file.name.startsWith("kotlin-stdlib") - } + file.name.startsWith("kotlin-compiler-embeddable") || file.name.startsWith("kotlin-stdlib") + } .firstOrNull()?.let(::listOf).orEmpty() } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt index 76cd963f621..a05feef1cd1 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener +import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager class GradleScriptListener(project: Project) : ScriptChangeListener(project) { init { @@ -16,16 +17,20 @@ class GradleScriptListener(project: Project) : ScriptChangeListener(project) { project.service().startWatching() } - override fun isApplicable(vFile: VirtualFile): Boolean { - return GradleScriptingSupportProvider.getInstance(project).isApplicable(vFile) - } + override fun isApplicable(vFile: VirtualFile) = GradleBuildRootsManager.getInstance(project).isApplicable(vFile) - override fun editorActivated(vFile: VirtualFile) { - // do nothing - } + override fun editorActivated(vFile: VirtualFile) = checkUpToDate(vFile) - override fun documentChanged(vFile: VirtualFile) { + override fun documentChanged(vFile: VirtualFile) = checkUpToDate(vFile) - GradleScriptingSupportProvider.getInstance(project).getScriptInfo(vFile)?.model?.inputs + fun checkUpToDate(vFile: VirtualFile) { + val upToDate = GradleBuildRootsManager.getInstance(project) + .getScriptInfo(vFile)?.model?.inputs?.isUpToDate(project, vFile) ?: return + + if (upToDate) { + hideNotificationForProjectImport(project) + } else { + showNotificationForProjectImport(project) + } } } \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptingSupportProvider.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptingSupportProvider.kt deleted file mode 100644 index e42da493aa6..00000000000 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptingSupportProvider.kt +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2010-2020 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. - */ - -package org.jetbrains.kotlin.idea.scripting.gradle - -import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.VfsUtil -import com.intellij.openapi.vfs.VirtualFile -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.ScriptingSupport -import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsCache -import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslGradleBuildSync -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition -import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance -import org.jetbrains.plugins.gradle.config.GradleSettingsListenerAdapter -import org.jetbrains.plugins.gradle.settings.* -import org.jetbrains.plugins.gradle.util.GradleConstants -import java.io.File -import java.nio.file.Paths - -/** - * Manages [roots] gradle build roots: - * - populated after Gradle project sync, by calling [update] - * - stored in FS and loaded in [init] - */ -class GradleScriptingSupportProvider(val project: Project) : ScriptingSupport.Provider() { - val manager: CompositeScriptConfigurationManager - get() = ScriptConfigurationManager.getInstance(project) as CompositeScriptConfigurationManager - - private val updater - get() = manager.updater - - val roots = RootsIndex() - - //////////// - /// ScriptingSupport.Provider implementation: - - override fun updateScriptDefinitions() { - // nothing related to script definition and project roots are cached - } - - override fun isApplicable(file: VirtualFile): Boolean { - val buildRoot = findScriptBuildRoot(file) ?: return false - if (buildRoot is GradleBuildRoot.Legacy) return false - return true - } - - override fun isConfigurationLoadingInProgress(file: KtFile): Boolean { - return when (val root = findScriptBuildRoot(file.originalFile.virtualFile)) { - is GradleBuildRoot.Linked -> root.importing - else -> false - } - } - - override fun collectConfigurations(builder: ScriptClassRootsCache.Builder) { - roots.values.forEach { root -> - if (root is GradleBuildRoot.Imported) { - root.collectConfigurations(builder) - } - } - } - - ////////////////// - - private val VirtualFile.localPath - get() = path - - fun getScriptInfo(file: VirtualFile): GradleBuildRoot.Imported.ScriptInfo? = - manager.getLightScriptInfo(file.localPath) as? GradleBuildRoot.Imported.ScriptInfo - - fun findScriptBuildRoot(file: VirtualFile): GradleBuildRoot? { - if (!isGradleKotlinScript(file)) return null - - val path = file.localPath - val found = roots.findNearestRoot(path) - if (found != null) return found - - return findNewScriptBuildRoot(path) - } - - private fun findNewScriptBuildRoot(scriptPath: String): GradleBuildRoot { - val newRoot = updater.update { - loadScriptBuildRoot(scriptPath) - } - roots[newRoot.pathPrefix] = newRoot - return newRoot - } - - private fun updateBuildRoot(rootPath: String) { - val settings = getGradleProjectSettings(rootPath) ?: return - val newRoot = loadLinkedRoot(settings) - roots[newRoot.pathPrefix] = newRoot - if (newRoot is GradleBuildRoot.Imported) { - updater.ensureUpdateScheduled() - } - } - - private fun loadScriptBuildRoot(scriptPath: String): GradleBuildRoot { - val settings = findNearestGradleProjectSettings(scriptPath) ?: return detectUnlinkedGradleBuildRoot(scriptPath) - return loadLinkedRoot(settings) - } - - private fun loadLinkedRoot(settings: GradleProjectSettings) = - tryLoadFromFsCache(settings) ?: createOtherLinkedRoot(settings) - - private fun createOtherLinkedRoot(settings: GradleProjectSettings): GradleBuildRoot.Linked { - val supported = kotlinDslScriptsModelImportSupported(settings.resolveGradleVersion().version) - return when { - supported -> GradleBuildRoot.New(settings.externalProjectPath) - else -> GradleBuildRoot.Legacy(settings.externalProjectPath) - } - } - - private fun getGradleProjectSettings(workingDir: String): GradleProjectSettings? { - return (ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID) as GradleSettings) - .getLinkedProjectSettings(workingDir) - } - - private fun findNearestGradleProjectSettings(localPath: String): GradleProjectSettings? { - return getGradleProjectSettings(project) - .filter { localPath.startsWith(it.externalProjectPath) } - .maxBy { it.externalProjectPath.length } - } - - private fun detectUnlinkedGradleBuildRoot(file: String): GradleBuildRoot.Unlinked = - GradleBuildRoot.Unlinked(file) - - init { - getGradleProjectSettings(project).forEach { - roots[it.externalProjectPath] = loadLinkedRoot(it) - } - - // subscribe to gradle build unlink - val listener = object : GradleSettingsListenerAdapter() { - override fun onProjectsLinked(settings: MutableCollection) { - settings.forEach { - loadLinkedRoot(it) - } - } - - override fun onProjectsUnlinked(linkedProjectPaths: MutableSet) { - linkedProjectPaths.forEach { - val buildRoot = VfsUtil.findFile(Paths.get(it), false) - if (buildRoot != null) { - if (roots.remove(buildRoot.localPath) != null) { - KotlinDslScriptModels.remove(buildRoot) - } - } - } - } - - override fun onGradleHomeChange(oldPath: String?, newPath: String?, linkedProjectPath: String) { - updateBuildRoot(linkedProjectPath) - manager.updater.ensureUpdateScheduled() - } - - override fun onGradleDistributionTypeChange(currentValue: DistributionType?, linkedProjectPath: String) { - updateBuildRoot(linkedProjectPath) - manager.updater.ensureUpdateScheduled() - } - } - - project.messageBus.connect(project).subscribe(GradleSettingsListener.TOPIC, listener) - } - - private fun tryLoadFromFsCache(settings: GradleProjectSettings) = - tryCreateImportedRoot(settings.externalProjectPath) { - KotlinDslScriptModels.read(it) - } - - fun markImportingInProgress(workingDir: String) { - val linked = roots.getBuildRoot(workingDir) as? GradleBuildRoot.Linked - if (linked != null) { - linked.importing = true - } else { - val settings = getGradleProjectSettings(workingDir) - if (settings != null) { - val root = createOtherLinkedRoot(settings) - root.importing = true - roots[workingDir] = root - } - } - } - - fun update(build: KotlinDslGradleBuildSync) { - val settings = getGradleProjectSettings(build.workingDir) ?: return - - (roots.getBuildRoot(build.workingDir) as? GradleBuildRoot.Linked)?.importing = false - - if (!kotlinDslScriptsModelImportSupported(settings.resolveGradleVersion().version)) { - roots[build.workingDir] = GradleBuildRoot.Legacy(build.workingDir) - return - } - - // fast path for linked gradle builds without .gradle.kts support - if (build.models.isEmpty()) { - val root = roots.findNearestRoot(build.workingDir) ?: return - if (root is GradleBuildRoot.Imported && root.data.models.isEmpty()) return - } - - val templateClasspath = findTemplateClasspath(build) ?: return - val data = GradleImportedBuildRootData(templateClasspath, build.models) - val newSupport = tryCreateImportedRoot(build.workingDir) { data } ?: return - KotlinDslScriptModels.write(newSupport.dir, data) - roots[build.workingDir] = newSupport - manager.updater.ensureUpdateScheduled() - } - - private fun tryCreateImportedRoot( - externalProjectPath: String, - dataProvider: (buildRoot: VirtualFile) -> GradleImportedBuildRootData? - ): GradleBuildRoot.Imported? { - val gradleExeSettings = - ExternalSystemApiUtil.getExecutionSettings( - project, - externalProjectPath, - GradleConstants.SYSTEM_ID - ) - - val buildRoot = VfsUtil.findFile(Paths.get(externalProjectPath), true) ?: return null - val data = dataProvider(buildRoot) ?: return null - - val newSupport = GradleBuildRoot.Imported( - project, - buildRoot, - GradleKtsContext(gradleExeSettings.javaHome?.let { File(it) }), - data - ) - - val oldSupport = roots.findNearestRoot(externalProjectPath) - if (oldSupport != null) { - hideNotificationForProjectImport(project) - } - - return newSupport - } - - private fun findTemplateClasspath(build: KotlinDslGradleBuildSync): List? { - val anyScript = VfsUtil.findFile(Paths.get(build.models.first().file), true)!! - // todo: find definition according to build.workingDir - val definition = anyScript.findScriptDefinition(project) ?: return null - return definition.asLegacyOrNull() - ?.templateClasspath?.map { it.path } - } - - // used in 201 - @Suppress("UNUSED") - fun isConfigurationOutOfDate(file: VirtualFile): Boolean { - val script = getScriptInfo(file) ?: return false - return script.model.inputs.isUpToDate(project, file) - } - - companion object { - fun getInstance(project: Project): GradleScriptingSupportProvider = - EPN.getPoint(project).extensionList.firstIsInstance() - } -} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/MissingGradleScriptConfigurationNotificationProvider.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/MissingGradleScriptConfigurationNotificationProvider.kt index 453728d3e6f..9919dffa76f 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/MissingGradleScriptConfigurationNotificationProvider.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/MissingGradleScriptConfigurationNotificationProvider.kt @@ -17,6 +17,8 @@ import com.intellij.ui.EditorNotifications import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle import org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptConfigurationLoaderForOutOfProjectScripts +import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRoot +import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager import org.jetbrains.plugins.gradle.settings.GradleProjectSettings import org.jetbrains.plugins.gradle.util.GradleConstants @@ -28,8 +30,10 @@ class MissingGradleScriptConfigurationNotificationProvider(private val project: if (!isGradleKotlinScript(file)) return null if (file.fileType != KotlinFileType.INSTANCE) return null - return when (GradleScriptingSupportProvider.getInstance(project).findScriptBuildRoot(file)) { - is GradleBuildRoot.Unlinked -> EditorNotificationPanel().apply { + val scriptUnderRoot = GradleBuildRootsManager.getInstance(project).findScriptBuildRoot(file) + val root = scriptUnderRoot?.root + return when { + root is GradleBuildRoot.Unlinked -> EditorNotificationPanel().apply { text(KotlinIdeaGradleBundle.message("text.the.associated.gradle.project.isn.t.imported")) val linkProjectText = KotlinIdeaGradleBundle.message("action.label.text.load.script.configuration") @@ -55,7 +59,7 @@ class MissingGradleScriptConfigurationNotificationProvider(private val project: linkProjectText ) } - is GradleBuildRoot.Linked -> EditorNotificationPanel().apply { + root is GradleBuildRoot.New && !root.importing -> EditorNotificationPanel().apply { text(getMissingConfigurationNotificationText()) createActionLabel(getMissingConfigurationActionText()) { runPartialGradleImport(project) diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScrtiptModelProcessor.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScrtiptModelProcessor.kt index 0e78d56a80f..4fde374b376 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScrtiptModelProcessor.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslScrtiptModelProcessor.kt @@ -16,7 +16,7 @@ import org.gradle.tooling.model.kotlin.dsl.KotlinDslScriptsModel import org.jetbrains.kotlin.gradle.BrokenKotlinDslScriptsModel import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle import org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcher -import org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptingSupportProvider +import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager import org.jetbrains.kotlin.idea.scripting.gradle.getGradleScriptInputsStamp import org.jetbrains.kotlin.psi.NotNullableUserDataProperty import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext @@ -103,6 +103,7 @@ private fun KotlinDslScriptsModel.toListOfScriptModels(project: Project): List() val models = mutableListOf() } @@ -117,7 +118,10 @@ fun saveScriptModels(project: Project, build: KotlinDslGradleBuildSync) { build.models.map { FileUtil.toSystemIndependentName(File(it.file).parent) }.toSet() ) - GradleScriptingSupportProvider.getInstance(project).update(build) + // todo: use real info about projects + build.projectRoots.addAll(build.models.map { FileUtil.toSystemIndependentName(File(it.file).parent) }) + + GradleBuildRootsManager.getInstance(project).update(build) project.service().clearState() } \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslSyncListener.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslSyncListener.kt index 3906b04c01a..c02a1125c46 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslSyncListener.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/importing/KotlinDslSyncListener.kt @@ -9,7 +9,7 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID -import org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptingSupportProvider +import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager class KotlinDslSyncListener : ExternalSystemTaskNotificationListenerAdapter() { override fun onStart(id: ExternalSystemTaskId, workingDir: String?) { @@ -19,7 +19,7 @@ class KotlinDslSyncListener : ExternalSystemTaskNotificationListenerAdapter() { if (workingDir == null) return val project = id.findProject() ?: return - GradleScriptingSupportProvider.getInstance(project).markImportingInProgress(workingDir) + GradleBuildRootsManager.getInstance(project).markImportingInProgress(workingDir) project.kotlinGradleDslSync[id] = KotlinDslGradleBuildSync(workingDir, id) } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRoot.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRoot.kt new file mode 100644 index 00000000000..226c6d0db56 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRoot.kt @@ -0,0 +1,98 @@ +/* + * Copyright 2010-2020 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. + */ + +package org.jetbrains.kotlin.idea.scripting.gradle.roots + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsCache +import org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptDefinitionsContributor +import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition +import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource +import java.io.File + +/** + * See [GradleBuildRootsManager] + */ +sealed class GradleBuildRoot { + /** + * Add Gradle Project + * for other scripts too + * + * precompiled script + * may be also included scripts not returned by gradle: todo proper notification + */ + class Unlinked() : GradleBuildRoot() + + abstract class Linked : GradleBuildRoot() { + @Volatile + var importing = false + + abstract val pathPrefix: String + + open val projectRoots: Collection get() = listOf() + } + + /** + * Notification: please update to Gradle 6.0 + * default loader, cases: + * - not loaded: Notification: Load configration to get code insights + * - loaded, not up-to-date: Notifaction: Reload configuraiton + * - loaded, up-to-date: Nothing + */ + class Legacy(override val pathPrefix: String) : Linked() + + /** + * not imported: + * Notification: Import Gradle project to get code insights + * during import: + * - disable action on importing. todo: don't miss failed import + * - pause analyzing, todo: change status text to: importing gradle project + */ + class New(override val pathPrefix: String) : Linked() + + // precompiled scripts not detected by gradle + + class Imported( + val project: Project, + val dir: VirtualFile, + val javaHome: File?, + val data: GradleBuildRootData + ) : Linked() { + override val pathPrefix: String = dir.path + + override val projectRoots: Collection + get() = data.projectRoots + + fun collectConfigurations(builder: ScriptClassRootsCache.Builder) { + if (javaHome != null) { + builder.addSdk(javaHome) + } + + val definitions = GradleScriptDefinitionsContributor.getDefinitions(project) + + builder.classes.addAll(data.templateClasspath) + data.models.forEach { script -> + val definition = selectScriptDefinition(script, definitions) + + builder.scripts[script.file] = GradleScriptInfo(this, definition, script) + + builder.classes.addAll(script.classPath) + builder.sources.addAll(script.sourcePath) + } + } + + private fun selectScriptDefinition( + script: KotlinDslScriptModel, + definitions: List + ): ScriptDefinition? { + val file = LocalFileSystem.getInstance().findFileByPath(script.file) ?: return null + val scriptSource = VirtualFileScriptSource(file) + return definitions.firstOrNull { it.isScript(scriptSource) } + } + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/Configuration.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootData.kt similarity index 56% rename from idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/Configuration.kt rename to idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootData.kt index 9a0513839f6..2075893163b 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/Configuration.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootData.kt @@ -3,11 +3,12 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package org.jetbrains.kotlin.idea.scripting.gradle +package org.jetbrains.kotlin.idea.scripting.gradle.roots import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel -data class GradleImportedBuildRootData( - val templateClasspath: List, - val models: List +data class GradleBuildRootData( + val projectRoots: Collection, + val templateClasspath: Collection, + val models: Collection ) \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/serizliation.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootDataSerializer.kt similarity index 87% rename from idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/serizliation.kt rename to idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootDataSerializer.kt index 9787b8b52b3..f18c0ea60db 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/serizliation.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootDataSerializer.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package org.jetbrains.kotlin.idea.scripting.gradle +package org.jetbrains.kotlin.idea.scripting.gradle.roots import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.FileAttribute @@ -11,15 +11,16 @@ import org.jetbrains.kotlin.idea.core.util.readNullable import org.jetbrains.kotlin.idea.core.util.readString import org.jetbrains.kotlin.idea.core.util.writeNullable import org.jetbrains.kotlin.idea.core.util.writeString +import org.jetbrains.kotlin.idea.scripting.gradle.GradleKotlinScriptConfigurationInputs import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel import java.io.DataInput import java.io.DataInputStream import java.io.DataOutput -internal object KotlinDslScriptModels { - private val attribute = FileAttribute("kotlin-dsl-script-models", 3, false) +internal object GradleBuildRootDataSerializer { + private val attribute = FileAttribute("kotlin-dsl-script-models", 4, false) - fun read(buildRoot: VirtualFile): GradleImportedBuildRootData? { + fun read(buildRoot: VirtualFile): GradleBuildRootData? { return attribute.readAttribute(buildRoot)?.use { it.readNullable { readKotlinDslScriptModels(it) @@ -27,7 +28,7 @@ internal object KotlinDslScriptModels { } } - fun write(buildRoot: VirtualFile, data: GradleImportedBuildRootData?) { + fun write(buildRoot: VirtualFile, data: GradleBuildRootData?) { attribute.writeAttribute(buildRoot).use { it.writeNullable(data) { writeKotlinDslScriptModels(this, it) @@ -40,8 +41,9 @@ internal object KotlinDslScriptModels { } } -internal fun writeKotlinDslScriptModels(output: DataOutput, data: GradleImportedBuildRootData) { +internal fun writeKotlinDslScriptModels(output: DataOutput, data: GradleBuildRootData) { val strings = StringsPool.writer(output) + strings.addStrings(data.projectRoots) strings.addStrings(data.templateClasspath) data.models.forEach { strings.addString(it.file) @@ -50,6 +52,7 @@ internal fun writeKotlinDslScriptModels(output: DataOutput, data: GradleImported strings.addStrings(it.imports) } strings.writeHeader() + strings.writeStringIds(data.projectRoots) strings.writeStringIds(data.templateClasspath) output.writeList(data.models) { strings.writeStringId(it.file) @@ -61,9 +64,10 @@ internal fun writeKotlinDslScriptModels(output: DataOutput, data: GradleImported } } -internal fun readKotlinDslScriptModels(input: DataInputStream): GradleImportedBuildRootData { +internal fun readKotlinDslScriptModels(input: DataInputStream): GradleBuildRootData { val strings = StringsPool.reader(input) + val projectRoots = strings.readStrings() val templateClasspath = strings.readStrings() val models = input.readList { @@ -77,7 +81,7 @@ internal fun readKotlinDslScriptModels(input: DataInputStream): GradleImportedBu ) } - return GradleImportedBuildRootData(templateClasspath, models) + return GradleBuildRootData(projectRoots, templateClasspath, models) } private object StringsPool { diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootIndex.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootIndex.kt new file mode 100644 index 00000000000..4927b2a7a22 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootIndex.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2020 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. + */ + +package org.jetbrains.kotlin.idea.scripting.gradle.roots + +import com.intellij.openapi.diagnostic.logger + +class GradleBuildRootIndex { + private val log = logger() + + private val byWorkingDir = HashMap() + val byProjectDir = HashMap() + + val values: Collection + get() = byWorkingDir.values + + @Synchronized + fun rebuildProjectRoots() { + byProjectDir.clear() + byWorkingDir.values.forEach { buildRoot -> + buildRoot.projectRoots.forEach { + byProjectDir[it] = buildRoot + } + } + } + + @Synchronized + fun getBuildRoot(dir: String) = byWorkingDir[dir] + + @Synchronized + fun findNearestRoot(path: String): GradleBuildRoot.Linked? { + var max: Pair? = null + byWorkingDir.entries.forEach { + if (path.startsWith(it.key) && (max == null || it.key.length > max!!.first.length)) { + max = it.key to it.value + } + } + return max?.second + } + + @Synchronized + fun getBuildByProjectDir(projectDir: String) = byProjectDir[projectDir] + + @Synchronized + operator fun set(prefix: String, value: GradleBuildRoot.Linked) { + val old = byWorkingDir.put(prefix, value) + rebuildProjectRoots() + log.info("$prefix: $old -> $value") + } + + @Synchronized + fun remove(prefix: String) = byWorkingDir.remove(prefix)?.also { + rebuildProjectRoots() + log.info("$prefix: removed") + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt new file mode 100644 index 00000000000..28c50a2e580 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt @@ -0,0 +1,280 @@ +/* + * Copyright 2010-2020 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. + */ + +package org.jetbrains.kotlin.idea.scripting.gradle.roots + +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +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.ScriptingSupport +import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsCache +import org.jetbrains.kotlin.idea.scripting.gradle.* +import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslGradleBuildSync +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance +import org.jetbrains.plugins.gradle.config.GradleSettingsListenerAdapter +import org.jetbrains.plugins.gradle.settings.* +import org.jetbrains.plugins.gradle.util.GradleConstants +import java.io.File +import java.nio.file.Paths + +/** + * [GradleBuildRoot] is a linked gradle build (don't confuse with gradle project and included build). + * Each [GradleBuildRoot] may have it's own Gradle version, java home and other settings. + * + * This manager allows to find related Gradle build by the Gradle Kotlin script file path. + * Each imported build have info about all of it's Kotlin Build Scripts. + * It is populated by calling [update], stored in FS and will be loaded from FS on next project opening + * + * [CompositeScriptConfigurationManager] may ask about known scripts by calling [collectConfigurations]. + * + * It also used to show related notification and floating actions depending on root kind, state and script state itself. + * + * Roots may be: + * - [GradleBuildRoot.Unlinked] - The script not related to any Gradle build that is linked to IntelliJ Project, + * or we cannot known what is it + * - [GradleBuildRoot.Linked] - Linked project, that may be itself: + * - [GradleBuildRoot.Legacy] - Gradle build with old Gradle version (<6.0) + * - [GradleBuildRoot.New] - not yet imported + * - [GradleBuildRoot.Imported] - imported + */ +class GradleBuildRootsManager(val project: Project) : ScriptingSupport.Provider() { + val manager: CompositeScriptConfigurationManager + get() = ScriptConfigurationManager.getInstance(project) as CompositeScriptConfigurationManager + + private val updater + get() = manager.updater + + val roots = GradleBuildRootIndex() + + //////////// + /// ScriptingSupport.Provider implementation: + + override fun updateScriptDefinitions() { + // nothing related to script definition and project roots are cached + } + + override fun isApplicable(file: VirtualFile): Boolean { + val scriptUnderRoot = findScriptBuildRoot(file) ?: return false + if (scriptUnderRoot.root is GradleBuildRoot.Legacy) return false + return true + } + + override fun isConfigurationLoadingInProgress(file: KtFile): Boolean { + return when (val root = findScriptBuildRoot(file.originalFile.virtualFile)?.root) { + is GradleBuildRoot.Linked -> root.importing + else -> false + } + } + + // used in 201 + @Suppress("UNUSED") + fun isConfigurationOutOfDate(file: VirtualFile): Boolean { + val script = getScriptInfo(file) ?: return false + return !script.model.inputs.isUpToDate(project, file) + } + + override fun collectConfigurations(builder: ScriptClassRootsCache.Builder) { + roots.values.forEach { root -> + if (root is GradleBuildRoot.Imported) { + root.collectConfigurations(builder) + } + } + } + + ////////////////// + + private val VirtualFile.localPath + get() = path + + fun getScriptInfo(file: VirtualFile): GradleScriptInfo? = + manager.getLightScriptInfo(file.localPath) as? GradleScriptInfo + + class ScriptUnderRoot( + val root: GradleBuildRoot?, + val script: GradleScriptInfo? = null + ) + + fun findScriptBuildRoot(gradleKtsFile: VirtualFile): ScriptUnderRoot? { + if (!isGradleKotlinScript(gradleKtsFile)) return null + + val filePath = gradleKtsFile.path + val scriptInfo = getScriptInfo(gradleKtsFile) + val imported = scriptInfo?.buildRoot + if (imported != null) return ScriptUnderRoot(imported, scriptInfo) + + if (gradleKtsFile.name == "build.gradle.kts" || + gradleKtsFile.name == "settings.gradle.kts" || + gradleKtsFile.name == "init.gradle.kts" + ) { + // build|settings|init.gradle.kts scripts should be located near gradle project root only + val gradleBuild = roots.getBuildByProjectDir(gradleKtsFile.parent.localPath) + if (gradleBuild != null) return ScriptUnderRoot(gradleBuild) + } + + // other scripts: "included", "precompiled" scripts, scripts in unlinked projects, + // or just random files with ".gradle.kts" ending + + // try find nearest linked legacy gradle project settings first + val found = roots.findNearestRoot(filePath) + if (found is GradleBuildRoot.Legacy) return ScriptUnderRoot(found) + + return ScriptUnderRoot(GradleBuildRoot.Unlinked()) + } + + + fun markImportingInProgress(workingDir: String, inProgress: Boolean = true) { + actualizeBuildRoot(workingDir)?.importing = inProgress + } + + fun update(build: KotlinDslGradleBuildSync) { + // fast path for linked gradle builds without .gradle.kts support + if (build.models.isEmpty()) { + val root = roots.getBuildRoot(build.workingDir) ?: return + if (root is GradleBuildRoot.Imported && root.data.models.isEmpty()) return + } + + val old = actualizeBuildRoot(build.workingDir) ?: return + old.importing = false + + if (old is GradleBuildRoot.Legacy) return + + val templateClasspath = GradleScriptDefinitionsContributor.getDefinitionsTemplateClasspath(project) + val data = GradleBuildRootData(build.projectRoots, templateClasspath, build.models) + val newSupport = tryCreateImportedRoot(build.workingDir) { data } ?: return + GradleBuildRootDataSerializer.write(newSupport.dir, data) + roots[build.workingDir] = newSupport + manager.updater.ensureUpdateScheduled() + } + + init { + getGradleProjectSettings(project).forEach { + roots[it.externalProjectPath] = loadLinkedRoot(it) + } + + // subscribe to linked gradle project modification + val listener = object : GradleSettingsListenerAdapter() { + override fun onProjectsLinked(settings: MutableCollection) { + settings.forEach { + loadLinkedRoot(it) + } + } + + override fun onProjectsUnlinked(linkedProjectPaths: MutableSet) { + linkedProjectPaths.forEach { + val buildRoot = VfsUtil.findFile(Paths.get(it), false) + if (buildRoot != null) { + if (roots.remove(buildRoot.localPath) != null) { + GradleBuildRootDataSerializer.remove(buildRoot) + } + } + } + } + + override fun onGradleHomeChange(oldPath: String?, newPath: String?, linkedProjectPath: String) { + updateBuildRoot(linkedProjectPath) + manager.updater.ensureUpdateScheduled() + } + + override fun onGradleDistributionTypeChange(currentValue: DistributionType?, linkedProjectPath: String) { + updateBuildRoot(linkedProjectPath) + manager.updater.ensureUpdateScheduled() + } + } + + project.messageBus.connect(project).subscribe(GradleSettingsListener.TOPIC, listener) + } + + private fun getGradleProjectSettings(workingDir: String): GradleProjectSettings? { + return (ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID) as GradleSettings) + .getLinkedProjectSettings(workingDir) + } + + /** + * Check that root under [workingDir] in sync with it's [GradleProjectSettings]. + * Actually this should be true, but we may miss some change events. + * For that cases we are rechecking this on each Gradle Project sync (importing/reimporting) + */ + private fun actualizeBuildRoot(workingDir: String): GradleBuildRoot.Linked? { + val actualSettings = getGradleProjectSettings(workingDir) + val buildRoot = roots.getBuildRoot(workingDir) + + return when { + buildRoot != null -> when { + !buildRoot.checkActual(actualSettings) -> updateBuildRoot(workingDir) + else -> buildRoot + } + actualSettings != null -> loadLinkedRoot(actualSettings) + else -> null + } + } + + private fun GradleBuildRoot.Linked.checkActual(actualSettings: GradleProjectSettings?): Boolean { + if (actualSettings == null) return false + + val knownAsSupported = this !is GradleBuildRoot.Legacy + val shouldBeSupported = kotlinDslScriptsModelImportSupported(actualSettings.resolveGradleVersion().version) + return knownAsSupported == shouldBeSupported + } + + private fun updateBuildRoot(rootPath: String): GradleBuildRoot.Linked? { + val settings = getGradleProjectSettings(rootPath) + if (settings == null) { + val removed = roots.remove(rootPath) + if (removed is GradleBuildRoot.Imported) { + updater.ensureUpdateScheduled() + } + return null + } else { + val newRoot = loadLinkedRoot(settings) + roots[newRoot.pathPrefix] = newRoot + updater.ensureUpdateScheduled() + return newRoot + } + } + + private fun loadLinkedRoot(settings: GradleProjectSettings) = + tryLoadFromFsCache(settings) ?: createOtherLinkedRoot(settings) + + private fun tryLoadFromFsCache(settings: GradleProjectSettings) = + tryCreateImportedRoot(settings.externalProjectPath) { + GradleBuildRootDataSerializer.read(it) + } + + private fun createOtherLinkedRoot(settings: GradleProjectSettings): GradleBuildRoot.Linked { + val supported = kotlinDslScriptsModelImportSupported(settings.resolveGradleVersion().version) + return when { + supported -> GradleBuildRoot.New(settings.externalProjectPath) + else -> GradleBuildRoot.Legacy(settings.externalProjectPath) + } + } + + private fun tryCreateImportedRoot( + externalProjectPath: String, + dataProvider: (buildRoot: VirtualFile) -> GradleBuildRootData? + ): GradleBuildRoot.Imported? { + val buildRoot = VfsUtil.findFile(Paths.get(externalProjectPath), true) ?: return null + val data = dataProvider(buildRoot) ?: return null + val javaHome = ExternalSystemApiUtil + .getExecutionSettings(project, externalProjectPath, GradleConstants.SYSTEM_ID) + .javaHome?.let { File(it) } + + val newSupport = GradleBuildRoot.Imported(project, buildRoot, javaHome, data) + val oldSupport = roots.getBuildRoot(externalProjectPath) + if (oldSupport != null) { + hideNotificationForProjectImport(project) + } + + return newSupport + } + + companion object { + fun getInstance(project: Project): GradleBuildRootsManager = + EPN.getPoint(project).extensionList.firstIsInstance() + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleScriptInfo.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleScriptInfo.kt new file mode 100644 index 00000000000..7e20f3baeab --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleScriptInfo.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2010-2020 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. + */ + +package org.jetbrains.kotlin.idea.scripting.gradle.roots + +import com.intellij.openapi.vfs.VfsUtil +import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsCache +import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper +import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource +import org.jetbrains.kotlin.scripting.resolve.adjustByDefinition +import java.io.File +import kotlin.script.experimental.api.* +import kotlin.script.experimental.jvm.JvmDependency +import kotlin.script.experimental.jvm.jdkHome +import kotlin.script.experimental.jvm.jvm + +class GradleScriptInfo( + val buildRoot: GradleBuildRoot.Imported, + scriptDefinition: ScriptDefinition?, + val model: KotlinDslScriptModel +) : ScriptClassRootsCache.LightScriptInfo(scriptDefinition) { + override fun buildConfiguration(): ScriptCompilationConfigurationWrapper? { + val javaHome = buildRoot.javaHome + + val scriptFile = File(model.file) + val virtualFile = VfsUtil.findFile(scriptFile.toPath(), true)!! + + if (definition == null) return null + + return ScriptCompilationConfigurationWrapper.FromCompilationConfiguration( + VirtualFileScriptSource(virtualFile), + definition.compilationConfiguration.with { + if (javaHome != null) { + jvm.jdkHome(javaHome) + } + defaultImports(model.imports) + dependencies(JvmDependency(model.classPath.map { File(it) })) + ide.dependenciesSources(JvmDependency(model.sourcePath.map { File(it) })) + }.adjustByDefinition(definition) + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as GradleScriptInfo + + if (buildRoot.pathPrefix != other.buildRoot.pathPrefix) return false + if (model != other.model) return false + if (definition != other.definition) return false + + return true + } + + override fun hashCode(): Int { + var result = buildRoot.pathPrefix.hashCode() + result = 31 * result + model.hashCode() + result = 31 * result + definition.hashCode() + return result + } +} diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt index dbd54aaf14b..dfe78ffc003 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt @@ -19,12 +19,9 @@ import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtScriptInitializer import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType -import org.jetbrains.plugins.gradle.settings.GradleLocalSettings import org.jetbrains.plugins.gradle.settings.GradleProjectSettings import org.jetbrains.plugins.gradle.settings.GradleSettings import org.jetbrains.plugins.gradle.util.GradleConstants -import org.slf4j.LoggerFactory -import kotlin.collections.HashMap private val sections = arrayListOf("buildscript", "plugins", "initscript", "pluginManagement") @@ -96,57 +93,5 @@ fun useScriptConfigurationFromImportOnly(): Boolean { return Registry.`is`("kotlin.gradle.scripts.useIdeaProjectImport", false) } -fun getGradleVersion(project: Project, settings: GradleProjectSettings): String { - val localVersion = GradleLocalSettings.getInstance(project).getGradleVersion(settings.externalProjectPath) - if (localVersion != null) return localVersion - - return settings.resolveGradleVersion().version -} - -fun getGradleProjectSettings(project: Project): Collection { - val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID) as GradleSettings - return gradleSettings.getLinkedProjectsSettings() -} - -class RootsIndex { - private val log = LoggerFactory.getLogger(RootsIndex::class.java) - - private val buildRoots = HashMap() - private val scripts = HashMap() - val values: Collection - get() = buildRoots.values - - @Synchronized - fun rebuildProjectRoots() { -// values.forEach { -// it. -// } - } - - @Synchronized - fun getBuildRoot(dir: String) = buildRoots[dir] - - @Synchronized - fun findNearestRoot(path: String): GradleBuildRoot? { - var max: Pair? = null - buildRoots.entries.forEach { - if (path.startsWith(it.key) && (max == null || it.key.length > max!!.first.length)) { - max = it.key to it.value - } - } - return max?.second - } - - @Synchronized - operator fun set(prefix: String, value: GradleBuildRoot) { - val old = buildRoots.put(prefix, value) - rebuildProjectRoots() - log.info("{}: {} -> {}", prefix, old, value) - } - - @Synchronized - fun remove(prefix: String) = buildRoots.remove(prefix)?.also { - rebuildProjectRoots() - log.info("{}: removed", prefix) - } -} \ No newline at end of file +fun getGradleProjectSettings(project: Project): Collection = + (ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID) as GradleSettings).linkedProjectsSettings \ No newline at end of file diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleKtsImportTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleKtsImportTest.kt index 39c4cc6454c..11ac5e99cf5 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleKtsImportTest.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleKtsImportTest.kt @@ -10,6 +10,7 @@ import junit.framework.AssertionFailedError import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager import org.jetbrains.kotlin.idea.core.script.applySuggestedScriptConfiguration +import org.jetbrains.kotlin.idea.core.script.configuration.CompositeScriptConfigurationManager import org.jetbrains.kotlin.idea.core.script.configuration.loader.DefaultScriptConfigurationLoader import org.jetbrains.kotlin.idea.core.script.configuration.loader.ScriptConfigurationLoadingContext import org.jetbrains.kotlin.idea.core.script.configuration.utils.areSimilar @@ -37,7 +38,7 @@ class GradleKtsImportTest : GradleImportingTestCase() { fun data(): Collection> = listOf(arrayOf("6.0.1")) } - val scriptConfigurationManager get() = ScriptConfigurationManager.getInstance(myProject) + val scriptConfigurationManager get() = ScriptConfigurationManager.getInstance(myProject) as CompositeScriptConfigurationManager val projectDir get() = File(GradleSettings.getInstance(myProject).linkedProjectsSettings.first().externalProjectPath) override fun testDataDirName(): String { @@ -98,8 +99,8 @@ class GradleKtsImportTest : GradleImportingTestCase() { // reload configuration and check this it is not changed scripts.forEach { - val reloadedConfiguration = scriptConfigurationManager.forceReloadConfiguration( - it.virtualFile, + val reloadedConfiguration = scriptConfigurationManager.default.forceReloadConfiguration( + it.psiFile, object : DefaultScriptConfigurationLoader(it.psiFile.project) { override fun shouldRunInBackground(scriptDefinition: ScriptDefinition) = false override fun loadDependencies( diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/KotlinDslScriptModelsTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleBuildRootDataSerializerTest.kt similarity index 81% rename from idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/KotlinDslScriptModelsTest.kt rename to idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleBuildRootDataSerializerTest.kt index d7e7ee0154e..6a397fd54c7 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/KotlinDslScriptModelsTest.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleBuildRootDataSerializerTest.kt @@ -6,6 +6,9 @@ package org.jetbrains.kotlin.idea.scripting.gradle import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel +import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootData +import org.jetbrains.kotlin.idea.scripting.gradle.roots.readKotlinDslScriptModels +import org.jetbrains.kotlin.idea.scripting.gradle.roots.writeKotlinDslScriptModels import org.junit.Test import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream @@ -13,11 +16,12 @@ import java.io.DataInputStream import java.io.DataOutputStream import kotlin.test.assertEquals -class KotlinDslScriptModelsTest { +class GradleBuildRootDataSerializerTest { @Test fun write() { - val data = GradleImportedBuildRootData( + val data = GradleBuildRootData( listOf("a", "b", "c"), + listOf("a"), listOf( KotlinDslScriptModel( "a", diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcherTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcherTest.kt index 73e69d9efb3..2beaa7efcc0 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcherTest.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcherTest.kt @@ -233,13 +233,13 @@ open class GradleScriptInputsWatcherTest : AbstractScriptConfigurationLoadingTes } private fun assertConfigurationUpToDate(file: KtFile) { - scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file) + scriptConfigurationManager.default.ensureUpToDatedConfigurationSuggested(file) assertNoBackgroundTasks() assertNoLoading() } private fun assertConfigurationUpdateWasDone(file: KtFile) { - scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file) + scriptConfigurationManager.default.ensureUpToDatedConfigurationSuggested(file) assertAndDoAllBackgroundTasks() assertSingleLoading() } diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptOutOfProjectTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptOutOfProjectTest.kt index 4159e2a880b..4a208dbb9d2 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptOutOfProjectTest.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptOutOfProjectTest.kt @@ -43,7 +43,7 @@ class GradleScriptOutOfProjectTest : AbstractScriptConfigurationLoadingTest() { fun testManualLoadingForUpToDate() { assertConfigurationShouldBeLoadedManually() - scriptConfigurationManager.forceReloadConfiguration(myFile.virtualFile, loaderForOutOfProjectScripts) + scriptConfigurationManager.default.forceReloadConfiguration(myFile as KtFile, loaderForOutOfProjectScripts) assertConfigurationWasLoaded() } @@ -56,7 +56,7 @@ class GradleScriptOutOfProjectTest : AbstractScriptConfigurationLoadingTest() { assertNoBackgroundTasks() assertNoLoading() - scriptConfigurationManager.forceReloadConfiguration(myFile.virtualFile, loaderForOutOfProjectScripts) + scriptConfigurationManager.default.forceReloadConfiguration(myFile as KtFile, loaderForOutOfProjectScripts) assertConfigurationWasLoaded() } @@ -64,7 +64,7 @@ class GradleScriptOutOfProjectTest : AbstractScriptConfigurationLoadingTest() { fun testFileAttributesForManualLoading() { assertConfigurationShouldBeLoadedManually() - scriptConfigurationManager.forceReloadConfiguration(myFile.virtualFile, loaderForOutOfProjectScripts) + scriptConfigurationManager.default.forceReloadConfiguration(myFile as KtFile, loaderForOutOfProjectScripts) assertConfigurationWasLoaded() @@ -76,12 +76,12 @@ class GradleScriptOutOfProjectTest : AbstractScriptConfigurationLoadingTest() { fun testNoNotificationAfterForReload() { assertConfigurationShouldBeLoadedManually() - scriptConfigurationManager.forceReloadConfiguration(myFile.virtualFile, loaderForOutOfProjectScripts) + scriptConfigurationManager.default.forceReloadConfiguration(myFile as KtFile, loaderForOutOfProjectScripts) assertConfigurationWasLoaded() makeChangesInsideSections() - scriptConfigurationManager.forceReloadConfiguration(myFile.virtualFile, loaderForOutOfProjectScripts) + scriptConfigurationManager.default.forceReloadConfiguration(myFile as KtFile, loaderForOutOfProjectScripts) assertConfigurationWasLoaded() } diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/RootsIndexTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/RootsIndexTest.kt deleted file mode 100644 index 47be40910df..00000000000 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/RootsIndexTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010-2020 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. - */ - -package org.jetbrains.kotlin.idea.scripting.gradle - -import org.junit.Test -import kotlin.test.assertEquals -import kotlin.test.assertFails - -class RootsIndexTest { - @Test - fun findRoot() { - val roots = RootsIndex() - roots["a/b/c"] = 1 - assertFails { roots["a/b/c/d"] = 2 } - roots["a/c"] = 3 - roots["d"] = 4 - - assertEquals(1, roots.findNearestRoot("a/b/c/x")) - assertEquals(1, roots.findNearestRoot("a/b/c")) - assertEquals(3, roots.findNearestRoot("a/c/x")) - assertEquals(3, roots.findNearestRoot("a/c")) - assertEquals(4, roots.findNearestRoot("d")) - assertEquals(4, roots.findNearestRoot("d/x")) - assertEquals(null, roots.findNearestRoot("e")) - assertEquals(null, roots.findNearestRoot("e/f")) - - roots["d"] = 5 - assertEquals(5, roots.findNearestRoot("d")) - } -} \ No newline at end of file diff --git a/idea/resources/META-INF/gradle.xml b/idea/resources/META-INF/gradle.xml index f7bfdd46818..80350d2b6f8 100644 --- a/idea/resources/META-INF/gradle.xml +++ b/idea/resources/META-INF/gradle.xml @@ -17,7 +17,8 @@ - + + diff --git a/idea/resources/META-INF/gradle.xml.201 b/idea/resources/META-INF/gradle.xml.201 index 6884acab4b9..ecb667b861e 100644 --- a/idea/resources/META-INF/gradle.xml.201 +++ b/idea/resources/META-INF/gradle.xml.201 @@ -14,10 +14,11 @@ - - + + + + + diff --git a/idea/tests/org/jetbrains/kotlin/idea/script/AbstractScriptConfigurationLoadingTest.kt b/idea/tests/org/jetbrains/kotlin/idea/script/AbstractScriptConfigurationLoadingTest.kt index e6bb2b4bc56..da27468a763 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/script/AbstractScriptConfigurationLoadingTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/script/AbstractScriptConfigurationLoadingTest.kt @@ -13,6 +13,7 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiFile import org.jetbrains.kotlin.idea.core.script.* +import org.jetbrains.kotlin.idea.core.script.configuration.CompositeScriptConfigurationManager import org.jetbrains.kotlin.idea.core.script.configuration.DefaultScriptConfigurationManagerExtensions import org.jetbrains.kotlin.idea.core.script.configuration.loader.FileContentsDependentConfigurationLoader import org.jetbrains.kotlin.idea.core.script.configuration.testingBackgroundExecutor @@ -21,7 +22,7 @@ import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.psi.KtFile abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurationTest() { - lateinit var scriptConfigurationManager: ScriptConfigurationManager + lateinit var scriptConfigurationManager: CompositeScriptConfigurationManager companion object { private var occurredLoadings = 0 @@ -41,7 +42,7 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat testScriptConfigurationNotification = true ApplicationManager.getApplication().isScriptChangesNotifierDisabled = false - scriptConfigurationManager = ServiceManager.getService(project, ScriptConfigurationManager::class.java) + scriptConfigurationManager = ServiceManager.getService(project, ScriptConfigurationManager::class.java) as CompositeScriptConfigurationManager } override fun tearDown() { @@ -103,7 +104,7 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat protected fun makeChanges(contents: String, file: KtFile = myFile as KtFile) { changeContents(contents) - scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file) + scriptConfigurationManager.default.ensureUpToDatedConfigurationSuggested(file) } protected fun changeContents(contents: String, file: PsiFile = myFile) { diff --git a/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationLoadingTest.kt b/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationLoadingTest.kt index 6aa62a30550..f4ee66413b9 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationLoadingTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationLoadingTest.kt @@ -163,10 +163,10 @@ class ScriptConfigurationLoadingTest : AbstractScriptConfigurationLoadingTest() fun testLoadingForUsagesSearch() { assertAndLoadInitialConfiguration() - assertTrue(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(myFile as KtFile))) + assertTrue(scriptConfigurationManager.default.ensureConfigurationUpToDate(listOf(myFile as KtFile))) changeContents("A") - assertFalse(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(myFile as KtFile))) + assertFalse(scriptConfigurationManager.default.ensureConfigurationUpToDate(listOf(myFile as KtFile))) } fun testReportsOnAutoApply() {