diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt index 311bcd91f14..d60b378e291 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt @@ -46,9 +46,6 @@ class ScriptDefinitionsManager(private val project: Project): ScriptDefinitionPr private var definitionsByContributor = mutableMapOf>() private var definitions: List = emptyList() - var hasFailedDefinitions = false - private set - fun reloadDefinitionsBy(contributor: ScriptDefinitionContributor) = lock.write { val notLoadedYet = definitions.isEmpty() if (notLoadedYet) return @@ -57,8 +54,6 @@ class ScriptDefinitionsManager(private val project: Project): ScriptDefinitionPr definitionsByContributor[contributor] = contributor.safeGetDefinitions() - hasFailedDefinitions = getContributors().any { it.isError() } - updateDefinitions() } @@ -72,6 +67,13 @@ class ScriptDefinitionsManager(private val project: Project): ScriptDefinitionPr return definitionsByContributor[contributor] ?: emptyList() } + fun getContributorForDefinition(scriptDefinition: KotlinScriptDefinition): ScriptDefinitionContributor { + for ((contributor, definitions) in definitionsByContributor) { + if (definitions.contains(scriptDefinition)) return contributor + } + throw error("Unknown definition: ${scriptDefinition.name}") + } + private fun currentDefinitions(): List { val hasDefinitions = definitions.isNotEmpty() when { @@ -105,8 +107,6 @@ class ScriptDefinitionsManager(private val project: Project): ScriptDefinitionPr definitionsByContributor[contributor] = definitions } - hasFailedDefinitions = getContributors().any { it.isError() } - updateDefinitions() } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt index aa8100419fb..c14910f2a88 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt @@ -41,7 +41,6 @@ import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor import org.jetbrains.kotlin.idea.core.util.EDT import org.jetbrains.kotlin.idea.core.util.cancelOnDisposal -import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.psi.NotNullableUserDataProperty import org.jetbrains.kotlin.script.* @@ -127,10 +126,6 @@ class ScriptDependenciesUpdater( } private fun performUpdate(file: VirtualFile) { - if (ScriptDefinitionsManager.getInstance(project).hasFailedDefinitions && !ProjectRootsUtil.isProjectSourceFile(project, file)) { - return - } - val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) ?: return when (scriptDef.dependencyResolver) { is AsyncDependenciesResolver, is LegacyResolverWrapper -> { @@ -212,7 +207,7 @@ class ScriptDependenciesUpdater( } ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports) val resultingDependencies = (result.dependencies ?: ScriptDependencies.Empty).adjustByDefinition(scriptDef) - if (saveNewDependencies(resultingDependencies, file)) { + if (saveNewDependencies(resultingDependencies, file, scriptDef)) { notifyRootsChanged() } } @@ -221,15 +216,16 @@ class ScriptDependenciesUpdater( fun updateSync(file: VirtualFile, scriptDef: KotlinScriptDefinition): Boolean { val newDeps = contentLoader.loadContentsAndResolveDependencies(scriptDef, file) ?: ScriptDependencies.Empty - return saveNewDependencies(newDeps, file) + return saveNewDependencies(newDeps, file, scriptDef) } private fun saveNewDependencies( new: ScriptDependencies, - file: VirtualFile + file: VirtualFile, + scriptDef: KotlinScriptDefinition ): Boolean { val rootsChanged = cache.hasNotCachedRoots(new) - if (cache.save(file, new)) { + if (cache.save(file, new) && !ScriptDefinitionsManager.getInstance(project).getContributorForDefinition(scriptDef).isError()) { file.scriptDependencies = new } return rootsChanged diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/core/script/GradleScriptTemplateProvider.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/core/script/GradleScriptTemplateProvider.kt index 4f8419625d9..94db40db940 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/core/script/GradleScriptTemplateProvider.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/core/script/GradleScriptTemplateProvider.kt @@ -22,12 +22,16 @@ 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 com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil +import com.intellij.openapi.fileTypes.LanguageFileType import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import org.gradle.tooling.ProjectConnection +import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID import org.jetbrains.kotlin.lexer.KotlinLexer import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtScript import org.jetbrains.kotlin.script.KotlinScriptDefinition import org.jetbrains.plugins.gradle.config.GradleSettingsListenerAdapter import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper @@ -39,9 +43,14 @@ import org.jetbrains.plugins.gradle.util.GradleConstants import java.io.File import java.util.* import java.util.concurrent.atomic.AtomicBoolean +import kotlin.reflect.KClass import kotlin.script.dependencies.Environment +import kotlin.script.dependencies.ScriptContents +import kotlin.script.experimental.dependencies.DependenciesResolver +import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult import kotlin.script.experimental.dependencies.ScriptDependencies - +import kotlin.script.experimental.dependencies.ScriptReport +import kotlin.script.templates.standard.ScriptTemplateWithArgs class GradleScriptDefinitionsContributor(private val project: Project) : ScriptDefinitionContributor { @@ -109,7 +118,12 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD return kotlinDslTemplates } - return tryToLoadOldBuildScriptDefinition() + val default = tryToLoadOldBuildScriptDefinition() + if (default.isNotEmpty()) { + return default + } + + return listOf(ErrorGradleScriptDefinition()) } private fun tryToLoadOldBuildScriptDefinition(): List { @@ -137,7 +151,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD } catch (t: Throwable) { // TODO: review exception handling failedToLoad.set(true) - emptyList() + listOf(ErrorGradleScriptDefinition(t.message)) } @@ -168,10 +182,10 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD } val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID) - if (gradleSettings.getLinkedProjectsSettings().isEmpty()) return emptyList() + if (gradleSettings.getLinkedProjectsSettings().isEmpty()) error("Project '${project.name}' isn't linked with Gradle") - val projectSettings = - gradleSettings.getLinkedProjectsSettings().filterIsInstance().firstOrNull() ?: return emptyList() + val projectSettings = gradleSettings.getLinkedProjectsSettings().filterIsInstance().firstOrNull() + ?: error("Project '${project.name}' isn't linked with Gradle") val gradleExeSettings = ExternalSystemApiUtil.getExecutionSettings( project, @@ -207,6 +221,30 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD ScriptDefinitionsManager.getInstance(project).reloadDefinitionsBy(this) } + private class ErrorGradleScriptDefinition(message: String? = null) : KotlinScriptDefinition(ScriptTemplateWithArgs::class) { + override val name: String = "Default Kotlin Gradle Script" + override val fileType: LanguageFileType = KotlinFileType.INSTANCE + override val annotationsForSamWithReceivers: List = emptyList() + override val acceptedAnnotations: List> = emptyList() + + override val dependencyResolver: DependenciesResolver = ErrorScriptDependenciesResolver(message) + + override fun getScriptName(script: KtScript) = + Name.identifier(script.containingKtFile.name.removeSuffix(GradleConstants.KOTLIN_DSL_SCRIPT_EXTENSION)) + + override fun isScript(fileName: String): Boolean = + fileName.endsWith(GradleConstants.KOTLIN_DSL_SCRIPT_EXTENSION) + } + + private class ErrorScriptDependenciesResolver(private val message: String? = null) : DependenciesResolver { + override fun resolve(scriptContents: ScriptContents, environment: Environment): ResolveResult { + return ResolveResult.Failure( + ScriptReport( + message ?: "Failed to load script definitions by ${GradleScriptDefinitionsContributor::class.java.name}" + ) + ) + } + } } class ReloadGradleTemplatesOnSync : ExternalSystemTaskNotificationListenerAdapter() {