KotlinDslScriptsModel: save script models right after getting model

Remove redundant DataService
This commit is contained in:
Natalia Selezneva
2020-02-05 12:57:38 +03:00
parent ae522a0375
commit 29de7535a6
5 changed files with 163 additions and 175 deletions
@@ -5,19 +5,6 @@
package org.jetbrains.kotlin.idea.scripting.gradle.importing
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.util.Key
import org.jetbrains.kotlin.idea.util.NotNullableCopyableDataNodeUserDataProperty
var DataNode<out ProjectData>.KOTLIN_DSL_SCRIPT_MODELS: MutableList<KotlinDslScriptModel>
by NotNullableCopyableDataNodeUserDataProperty(
Key.create<MutableList<KotlinDslScriptModel>>(
"GRADLE_KOTLIN_BUILD_SCRIPTS"
),
mutableListOf()
)
data class KotlinDslScriptModel(
val file: String,
val inputsTimeStamp: Long,
@@ -1,160 +0,0 @@
/*
* Copyright 2010-2019 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.importing
import com.intellij.openapi.components.service
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.Key
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.notification.ExternalSystemNotificationManager
import com.intellij.openapi.externalSystem.service.notification.NotificationCategory
import com.intellij.openapi.externalSystem.service.notification.NotificationData
import com.intellij.openapi.externalSystem.service.notification.NotificationSource
import com.intellij.openapi.externalSystem.service.project.IdeModelsProvider
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.pom.Navigatable
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationSnapshot
import org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcher
import org.jetbrains.kotlin.idea.scripting.gradle.getGradleScriptInputsStamp
import org.jetbrains.kotlin.idea.scripting.gradle.saveGradleProjectRootsAfterImport
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import org.jetbrains.kotlin.scripting.resolve.adjustByDefinition
import org.jetbrains.plugins.gradle.settings.GradleExecutionSettings
import org.jetbrains.plugins.gradle.util.GradleConstants
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 KotlinDslScriptModelDataService : AbstractProjectDataService<ProjectData, Void>() {
override fun getTargetDataKey(): Key<ProjectData> = ProjectKeys.PROJECT
override fun onSuccessImport(
imported: MutableCollection<DataNode<ProjectData>>,
projectData: ProjectData?,
project: Project,
modelsProvider: IdeModelsProvider
) {
super.onSuccessImport(imported, projectData, project, modelsProvider)
val projectDataNode = imported.singleOrNull() ?: return
val gradleKotlinBuildScripts = projectDataNode.KOTLIN_DSL_SCRIPT_MODELS
val buildScripts = gradleKotlinBuildScripts.toList()
gradleKotlinBuildScripts.clear()
val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
val projectRoot = projectData?.linkedExternalProjectPath ?: return
val projectSettings = gradleSettings.getLinkedProjectSettings(projectRoot) ?: return
saveGradleProjectRootsAfterImport(projectSettings.modules.takeIf { it.isNotEmpty() } ?: setOf(projectRoot))
val gradleExeSettings = ExternalSystemApiUtil.getExecutionSettings<GradleExecutionSettings>(
project,
projectSettings.externalProjectPath,
GradleConstants.SYSTEM_ID
)
val javaHome = File(gradleExeSettings.javaHome ?: return)
val scriptConfigurations = mutableListOf<Pair<VirtualFile, ScriptConfigurationSnapshot>>()
buildScripts.forEach { buildScript ->
val scriptFile = File(buildScript.file)
val virtualFile = VfsUtil.findFile(scriptFile.toPath(), true)!!
val inputs = getGradleScriptInputsStamp(project, virtualFile, givenTimeStamp = buildScript.inputsTimeStamp)
val definition = virtualFile.findScriptDefinition(project) ?: return@forEach
val configuration =
definition.compilationConfiguration.with {
jvm.jdkHome(javaHome)
defaultImports(buildScript.imports)
dependencies(JvmDependency(buildScript.classPath.map { File(it) }))
ide.dependenciesSources(JvmDependency(buildScript.sourcePath.map { File(it) }))
}.adjustByDefinition(definition)
scriptConfigurations.add(
Pair(
virtualFile,
ScriptConfigurationSnapshot(
inputs ?: CachedConfigurationInputs.OutOfDate,
listOf(),
ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(
VirtualFileScriptSource(virtualFile),
configuration
)
)
)
)
buildScript.messages.forEach {
addBuildScriptDiagnosticMessage(it, virtualFile, project)
}
}
project.service<ScriptConfigurationManager>().saveCompilationConfigurationAfterImport(scriptConfigurations)
project.service<GradleScriptInputsWatcher>().clearState()
}
private fun addBuildScriptDiagnosticMessage(
message: KotlinDslScriptModel.Message,
virtualFile: VirtualFile,
project: Project
) {
val notification = NotificationData(
KotlinIdeaGradleBundle.message("title.kotlin.build.script"),
message.text,
when (message.severity) {
KotlinDslScriptModel.Severity.WARNING -> NotificationCategory.WARNING
KotlinDslScriptModel.Severity.ERROR -> NotificationCategory.ERROR
},
NotificationSource.PROJECT_SYNC
)
notification.navigatable =
LazyNavigatable(
virtualFile,
project,
message.position
)
ExternalSystemNotificationManager.getInstance(project).showNotification(
GradleConstants.SYSTEM_ID,
notification
)
}
class LazyNavigatable internal constructor(
private val virtualFile: VirtualFile,
private val project: Project,
val position: KotlinDslScriptModel.Position?
) : Navigatable {
private val openFileDescriptor: Navigatable by lazy {
if (position != null) OpenFileDescriptor(project, virtualFile, position.line, position.column)
else OpenFileDescriptor(project, virtualFile, -1)
}
override fun navigate(requestFocus: Boolean) {
if (openFileDescriptor.canNavigate()) openFileDescriptor.navigate(requestFocus)
}
override fun canNavigate(): Boolean = virtualFile.exists()
override fun canNavigateToSource(): Boolean = canNavigate()
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.scripting.gradle.importing
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.util.Order
import com.intellij.openapi.util.Pair
import org.gradle.tooling.model.kotlin.dsl.EditorReportSeverity
import org.gradle.tooling.model.kotlin.dsl.KotlinDslModelsParameters.*
@@ -16,6 +17,7 @@ import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExten
internal val LOG = Logger.getInstance(KotlinDslScriptModelResolverCommon::class.java)
@Order(Integer.MIN_VALUE) // to be the first
abstract class KotlinDslScriptModelResolverCommon : AbstractProjectResolverExtension() {
override fun getExtraProjectModelClasses(): Set<Class<out Any>> {
return setOf(KotlinDslScriptsModel::class.java)
@@ -83,7 +85,9 @@ abstract class KotlinDslScriptModelResolverCommon : AbstractProjectResolverExten
"Couldn't get KotlinDslScriptsModel for $projectName:\n${model.message}\n${model.stackTrace}"
)
} else {
ideProject.KOTLIN_DSL_SCRIPT_MODELS.addAll(model.toListOfScriptModels())
val models = model.toListOfScriptModels()
saveScriptModels(resolverCtx, models)
}
}
}
@@ -0,0 +1,157 @@
/*
* 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.importing
import com.intellij.build.SyncViewManager
import com.intellij.openapi.components.service
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemEventDispatcher
import com.intellij.openapi.externalSystem.service.notification.ExternalSystemNotificationManager
import com.intellij.openapi.externalSystem.service.notification.NotificationCategory
import com.intellij.openapi.externalSystem.service.notification.NotificationData
import com.intellij.openapi.externalSystem.service.notification.NotificationSource
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.pom.Navigatable
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationSnapshot
import org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcher
import org.jetbrains.kotlin.idea.scripting.gradle.getGradleScriptInputsStamp
import org.jetbrains.kotlin.idea.scripting.gradle.saveGradleProjectRootsAfterImport
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import org.jetbrains.kotlin.scripting.resolve.adjustByDefinition
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
import org.jetbrains.plugins.gradle.util.GradleConstants
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
fun saveScriptModels(
resolverContext: ProjectResolverContext,
models: List<KotlinDslScriptModel>
) {
val task = resolverContext.externalSystemTaskId
val project = task.findProject() ?: return
val settings = resolverContext.settings ?: return
val scriptConfigurations = mutableListOf<Pair<VirtualFile, ScriptConfigurationSnapshot>>()
val syncViewManager = project.service<SyncViewManager>()
val buildEventDispatcher =
ExternalSystemEventDispatcher(task, syncViewManager)
val javaHome = settings.javaHome?.let { File(it) }
models.forEach { buildScript ->
val scriptFile = File(buildScript.file)
val virtualFile = VfsUtil.findFile(scriptFile.toPath(), true)!!
val inputs = getGradleScriptInputsStamp(
project,
virtualFile,
givenTimeStamp = buildScript.inputsTimeStamp
)
val definition = virtualFile.findScriptDefinition(project) ?: return@forEach
val configuration =
definition.compilationConfiguration.with {
if (javaHome != null) {
jvm.jdkHome(javaHome)
}
defaultImports(buildScript.imports)
dependencies(JvmDependency(buildScript.classPath.map {
File(
it
)
}))
ide.dependenciesSources(JvmDependency(buildScript.sourcePath.map {
File(
it
)
}))
}.adjustByDefinition(definition)
scriptConfigurations.add(
Pair(
virtualFile,
ScriptConfigurationSnapshot(
inputs
?: CachedConfigurationInputs.OutOfDate,
listOf(),
ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(
VirtualFileScriptSource(virtualFile),
configuration,
),
),
),
)
buildScript.messages.forEach {
addBuildScriptDiagnosticMessage(it, virtualFile, project)
}
}
saveGradleProjectRootsAfterImport(
scriptConfigurations.map { it.first.parent.path }.toSet()
)
project.service<ScriptConfigurationManager>().saveCompilationConfigurationAfterImport(scriptConfigurations)
project.service<GradleScriptInputsWatcher>().clearState()
}
private fun addBuildScriptDiagnosticMessage(
message: KotlinDslScriptModel.Message,
virtualFile: VirtualFile,
project: Project
) {
val notification = NotificationData(
KotlinIdeaGradleBundle.message("title.kotlin.build.script"),
message.text,
when (message.severity) {
KotlinDslScriptModel.Severity.WARNING -> NotificationCategory.WARNING
KotlinDslScriptModel.Severity.ERROR -> NotificationCategory.ERROR
},
NotificationSource.PROJECT_SYNC
)
notification.navigatable =
LazyNavigatable(
virtualFile,
project,
message.position
)
ExternalSystemNotificationManager.getInstance(project).showNotification(
GradleConstants.SYSTEM_ID,
notification
)
}
class LazyNavigatable internal constructor(
private val virtualFile: VirtualFile,
private val project: Project,
val position: KotlinDslScriptModel.Position?
) : Navigatable {
private val openFileDescriptor: Navigatable by lazy {
if (position != null) OpenFileDescriptor(project, virtualFile, position.line, position.column)
else OpenFileDescriptor(project, virtualFile, -1)
}
override fun navigate(requestFocus: Boolean) {
if (openFileDescriptor.canNavigate()) openFileDescriptor.navigate(requestFocus)
}
override fun canNavigate(): Boolean = virtualFile.exists()
override fun canNavigateToSource(): Boolean = canNavigate()
}
+1 -1
View File
@@ -27,7 +27,7 @@
<projectTaskRunner implementation="org.jetbrains.kotlin.idea.gradle.execution.KotlinMPPGradleProjectTaskRunner" order="first, before gradle"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectSettingsDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelDataService"/>
<registryKey key="kotlin.mpp.tests.force.gradle"
description="Run multi-platform tests with Gradle runner even if the platform runner is used by default.
This setting currently affects only HMPP projects. You may need to delete existing test configurations for the change to take place."