gradle.kts: solve the linked gradle builds hell
This commit is contained in:
+1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.core.script.configuration.utils
|
|||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.application.TransactionGuard
|
import com.intellij.openapi.application.TransactionGuard
|
||||||
|
import com.intellij.openapi.progress.ProcessCanceledException
|
||||||
import com.intellij.openapi.progress.ProgressIndicator
|
import com.intellij.openapi.progress.ProgressIndicator
|
||||||
import com.intellij.openapi.progress.ProgressManager
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
import com.intellij.openapi.progress.util.BackgroundTaskUtil
|
import com.intellij.openapi.progress.util.BackgroundTaskUtil
|
||||||
|
|||||||
@@ -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<GradleScriptDefinitionsContributor>()
|
|
||||||
.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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -38,7 +38,6 @@ private const val kotlinDslNotificationGroupId = "Gradle Kotlin DSL Scripts"
|
|||||||
private var Project.notificationPanel: ScriptConfigurationChangedNotification?
|
private var Project.notificationPanel: ScriptConfigurationChangedNotification?
|
||||||
by UserDataProperty<Project, ScriptConfigurationChangedNotification>(Key.create("load.script.configuration.panel"))
|
by UserDataProperty<Project, ScriptConfigurationChangedNotification>(Key.create("load.script.configuration.panel"))
|
||||||
|
|
||||||
|
|
||||||
fun showNotificationForProjectImport(project: Project) {
|
fun showNotificationForProjectImport(project: Project) {
|
||||||
val existingPanel = project.notificationPanel
|
val existingPanel = project.notificationPanel
|
||||||
if (existingPanel != null) {
|
if (existingPanel != null) {
|
||||||
|
|||||||
+5
-7
@@ -21,19 +21,17 @@ import com.intellij.testFramework.LightVirtualFileBase
|
|||||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||||
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
||||||
import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver
|
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.GradlePartialResolverPolicy
|
||||||
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverExtension
|
|
||||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||||
import java.util.function.Predicate
|
|
||||||
|
|
||||||
fun runPartialGradleImport(project: Project) {
|
fun runPartialGradleImport(project: Project) {
|
||||||
getGradleProjectSettings(project).forEach {
|
getGradleProjectSettings(project).forEach { gradleProjectSettings ->
|
||||||
ExternalSystemUtil.refreshProject(
|
ExternalSystemUtil.refreshProject(
|
||||||
it.externalProjectPath,
|
gradleProjectSettings.externalProjectPath,
|
||||||
ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
|
ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
|
||||||
.projectResolverPolicy(
|
.projectResolverPolicy(
|
||||||
GradlePartialResolverPolicy(Predicate<GradleProjectResolverExtension?> { it is KotlinDslScriptModelResolver })
|
GradlePartialResolverPolicy { it is KotlinDslScriptModelResolver }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -81,6 +79,6 @@ class LoadConfigurationAction : AnAction(
|
|||||||
if (virtualFile is LightVirtualFileBase) return false
|
if (virtualFile is LightVirtualFileBase) return false
|
||||||
if (virtualFile == null || !virtualFile.isValid) return false
|
if (virtualFile == null || !virtualFile.isValid) return false
|
||||||
|
|
||||||
return GradleScriptingSupportProvider.getInstance(project).isConfigurationOutOfDate(virtualFile)
|
return GradleBuildRootsManager.getInstance(project).isConfigurationOutOfDate(virtualFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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?)
|
|
||||||
+18
-2
@@ -11,6 +11,7 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.util.EnvironmentUtil
|
import com.intellij.util.EnvironmentUtil
|
||||||
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
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.ScriptDefinitionSourceAsContributor
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
|
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
|
||||||
import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplates
|
import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplates
|
||||||
@@ -40,6 +41,21 @@ import kotlin.script.experimental.location.ScriptExpectedLocation
|
|||||||
import kotlin.script.templates.standard.ScriptTemplateWithArgs
|
import kotlin.script.templates.standard.ScriptTemplateWithArgs
|
||||||
|
|
||||||
class GradleScriptDefinitionsContributor(private val project: Project) : ScriptDefinitionSourceAsContributor {
|
class GradleScriptDefinitionsContributor(private val project: Project) : ScriptDefinitionSourceAsContributor {
|
||||||
|
companion object {
|
||||||
|
fun getDefinitions(project: Project) =
|
||||||
|
ScriptDefinitionContributor.EP_NAME.getExtensions(project)
|
||||||
|
.filterIsInstance<GradleScriptDefinitionsContributor>()
|
||||||
|
.single().definitions.toList()
|
||||||
|
|
||||||
|
fun getDefinitionsTemplateClasspath(project: Project): MutableSet<String> =
|
||||||
|
mutableSetOf<String>().also { result ->
|
||||||
|
getDefinitions(project).forEach { definition ->
|
||||||
|
definition.asLegacyOrNull<KotlinScriptDefinitionFromAnnotatedTemplate>()
|
||||||
|
?.templateClasspath
|
||||||
|
?.mapNotNullTo(result) { it.path }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val id: String = "Gradle Kotlin DSL"
|
override val id: String = "Gradle Kotlin DSL"
|
||||||
private val failedToLoad = AtomicBoolean(false)
|
private val failedToLoad = AtomicBoolean(false)
|
||||||
@@ -128,8 +144,8 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD
|
|||||||
private fun kotlinStdlibAndCompiler(gradleLibDir: File): List<File> {
|
private fun kotlinStdlibAndCompiler(gradleLibDir: File): List<File> {
|
||||||
// additionally need compiler jar to load gradle resolver
|
// additionally need compiler jar to load gradle resolver
|
||||||
return gradleLibDir.listFiles { file ->
|
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()
|
.firstOrNull()?.let(::listOf).orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-8
@@ -9,6 +9,7 @@ import com.intellij.openapi.components.service
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener
|
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) {
|
class GradleScriptListener(project: Project) : ScriptChangeListener(project) {
|
||||||
init {
|
init {
|
||||||
@@ -16,16 +17,20 @@ class GradleScriptListener(project: Project) : ScriptChangeListener(project) {
|
|||||||
project.service<GradleScriptInputsWatcher>().startWatching()
|
project.service<GradleScriptInputsWatcher>().startWatching()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isApplicable(vFile: VirtualFile): Boolean {
|
override fun isApplicable(vFile: VirtualFile) = GradleBuildRootsManager.getInstance(project).isApplicable(vFile)
|
||||||
return GradleScriptingSupportProvider.getInstance(project).isApplicable(vFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun editorActivated(vFile: VirtualFile) {
|
override fun editorActivated(vFile: VirtualFile) = checkUpToDate(vFile)
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-263
@@ -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<GradleProjectSettings>) {
|
|
||||||
settings.forEach {
|
|
||||||
loadLinkedRoot(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onProjectsUnlinked(linkedProjectPaths: MutableSet<String>) {
|
|
||||||
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<GradleExecutionSettings>(
|
|
||||||
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<String>? {
|
|
||||||
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<KotlinScriptDefinitionFromAnnotatedTemplate>()
|
|
||||||
?.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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+7
-3
@@ -17,6 +17,8 @@ import com.intellij.ui.EditorNotifications
|
|||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
||||||
import org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptConfigurationLoaderForOutOfProjectScripts
|
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.settings.GradleProjectSettings
|
||||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||||
|
|
||||||
@@ -28,8 +30,10 @@ class MissingGradleScriptConfigurationNotificationProvider(private val project:
|
|||||||
if (!isGradleKotlinScript(file)) return null
|
if (!isGradleKotlinScript(file)) return null
|
||||||
if (file.fileType != KotlinFileType.INSTANCE) return null
|
if (file.fileType != KotlinFileType.INSTANCE) return null
|
||||||
|
|
||||||
return when (GradleScriptingSupportProvider.getInstance(project).findScriptBuildRoot(file)) {
|
val scriptUnderRoot = GradleBuildRootsManager.getInstance(project).findScriptBuildRoot(file)
|
||||||
is GradleBuildRoot.Unlinked -> EditorNotificationPanel().apply {
|
val root = scriptUnderRoot?.root
|
||||||
|
return when {
|
||||||
|
root is GradleBuildRoot.Unlinked -> EditorNotificationPanel().apply {
|
||||||
text(KotlinIdeaGradleBundle.message("text.the.associated.gradle.project.isn.t.imported"))
|
text(KotlinIdeaGradleBundle.message("text.the.associated.gradle.project.isn.t.imported"))
|
||||||
|
|
||||||
val linkProjectText = KotlinIdeaGradleBundle.message("action.label.text.load.script.configuration")
|
val linkProjectText = KotlinIdeaGradleBundle.message("action.label.text.load.script.configuration")
|
||||||
@@ -55,7 +59,7 @@ class MissingGradleScriptConfigurationNotificationProvider(private val project:
|
|||||||
linkProjectText
|
linkProjectText
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is GradleBuildRoot.Linked -> EditorNotificationPanel().apply {
|
root is GradleBuildRoot.New && !root.importing -> EditorNotificationPanel().apply {
|
||||||
text(getMissingConfigurationNotificationText())
|
text(getMissingConfigurationNotificationText())
|
||||||
createActionLabel(getMissingConfigurationActionText()) {
|
createActionLabel(getMissingConfigurationActionText()) {
|
||||||
runPartialGradleImport(project)
|
runPartialGradleImport(project)
|
||||||
|
|||||||
+6
-2
@@ -16,7 +16,7 @@ import org.gradle.tooling.model.kotlin.dsl.KotlinDslScriptsModel
|
|||||||
import org.jetbrains.kotlin.gradle.BrokenKotlinDslScriptsModel
|
import org.jetbrains.kotlin.gradle.BrokenKotlinDslScriptsModel
|
||||||
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
||||||
import org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcher
|
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.idea.scripting.gradle.getGradleScriptInputsStamp
|
||||||
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
||||||
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||||
@@ -103,6 +103,7 @@ private fun KotlinDslScriptsModel.toListOfScriptModels(project: Project): List<K
|
|||||||
}
|
}
|
||||||
|
|
||||||
class KotlinDslGradleBuildSync(val workingDir: String, val taskId: ExternalSystemTaskId) {
|
class KotlinDslGradleBuildSync(val workingDir: String, val taskId: ExternalSystemTaskId) {
|
||||||
|
val projectRoots = mutableSetOf<String>()
|
||||||
val models = mutableListOf<KotlinDslScriptModel>()
|
val models = mutableListOf<KotlinDslScriptModel>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +118,10 @@ fun saveScriptModels(project: Project, build: KotlinDslGradleBuildSync) {
|
|||||||
build.models.map { FileUtil.toSystemIndependentName(File(it.file).parent) }.toSet()
|
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<GradleScriptInputsWatcher>().clearState()
|
project.service<GradleScriptInputsWatcher>().clearState()
|
||||||
}
|
}
|
||||||
+2
-2
@@ -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.ExternalSystemTaskNotificationListenerAdapter
|
||||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType
|
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType
|
||||||
import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
|
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() {
|
class KotlinDslSyncListener : ExternalSystemTaskNotificationListenerAdapter() {
|
||||||
override fun onStart(id: ExternalSystemTaskId, workingDir: String?) {
|
override fun onStart(id: ExternalSystemTaskId, workingDir: String?) {
|
||||||
@@ -19,7 +19,7 @@ class KotlinDslSyncListener : ExternalSystemTaskNotificationListenerAdapter() {
|
|||||||
if (workingDir == null) return
|
if (workingDir == null) return
|
||||||
val project = id.findProject() ?: return
|
val project = id.findProject() ?: return
|
||||||
|
|
||||||
GradleScriptingSupportProvider.getInstance(project).markImportingInProgress(workingDir)
|
GradleBuildRootsManager.getInstance(project).markImportingInProgress(workingDir)
|
||||||
project.kotlinGradleDslSync[id] = KotlinDslGradleBuildSync(workingDir, id)
|
project.kotlinGradleDslSync[id] = KotlinDslGradleBuildSync(workingDir, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+98
@@ -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<String> 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<String>
|
||||||
|
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>
|
||||||
|
): ScriptDefinition? {
|
||||||
|
val file = LocalFileSystem.getInstance().findFileByPath(script.file) ?: return null
|
||||||
|
val scriptSource = VirtualFileScriptSource(file)
|
||||||
|
return definitions.firstOrNull { it.isScript(scriptSource) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-4
@@ -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.
|
* 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
|
import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel
|
||||||
|
|
||||||
data class GradleImportedBuildRootData(
|
data class GradleBuildRootData(
|
||||||
val templateClasspath: List<String>,
|
val projectRoots: Collection<String>,
|
||||||
val models: List<KotlinDslScriptModel>
|
val templateClasspath: Collection<String>,
|
||||||
|
val models: Collection<KotlinDslScriptModel>
|
||||||
)
|
)
|
||||||
+12
-8
@@ -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.
|
* 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.VirtualFile
|
||||||
import com.intellij.openapi.vfs.newvfs.FileAttribute
|
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.readString
|
||||||
import org.jetbrains.kotlin.idea.core.util.writeNullable
|
import org.jetbrains.kotlin.idea.core.util.writeNullable
|
||||||
import org.jetbrains.kotlin.idea.core.util.writeString
|
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 org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel
|
||||||
import java.io.DataInput
|
import java.io.DataInput
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
import java.io.DataOutput
|
import java.io.DataOutput
|
||||||
|
|
||||||
internal object KotlinDslScriptModels {
|
internal object GradleBuildRootDataSerializer {
|
||||||
private val attribute = FileAttribute("kotlin-dsl-script-models", 3, false)
|
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 {
|
return attribute.readAttribute(buildRoot)?.use {
|
||||||
it.readNullable {
|
it.readNullable {
|
||||||
readKotlinDslScriptModels(it)
|
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 {
|
attribute.writeAttribute(buildRoot).use {
|
||||||
it.writeNullable(data) {
|
it.writeNullable(data) {
|
||||||
writeKotlinDslScriptModels(this, it)
|
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)
|
val strings = StringsPool.writer(output)
|
||||||
|
strings.addStrings(data.projectRoots)
|
||||||
strings.addStrings(data.templateClasspath)
|
strings.addStrings(data.templateClasspath)
|
||||||
data.models.forEach {
|
data.models.forEach {
|
||||||
strings.addString(it.file)
|
strings.addString(it.file)
|
||||||
@@ -50,6 +52,7 @@ internal fun writeKotlinDslScriptModels(output: DataOutput, data: GradleImported
|
|||||||
strings.addStrings(it.imports)
|
strings.addStrings(it.imports)
|
||||||
}
|
}
|
||||||
strings.writeHeader()
|
strings.writeHeader()
|
||||||
|
strings.writeStringIds(data.projectRoots)
|
||||||
strings.writeStringIds(data.templateClasspath)
|
strings.writeStringIds(data.templateClasspath)
|
||||||
output.writeList(data.models) {
|
output.writeList(data.models) {
|
||||||
strings.writeStringId(it.file)
|
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 strings = StringsPool.reader(input)
|
||||||
|
|
||||||
|
val projectRoots = strings.readStrings()
|
||||||
val templateClasspath = strings.readStrings()
|
val templateClasspath = strings.readStrings()
|
||||||
|
|
||||||
val models = input.readList {
|
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 {
|
private object StringsPool {
|
||||||
+58
@@ -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<GradleBuildRootIndex>()
|
||||||
|
|
||||||
|
private val byWorkingDir = HashMap<String, GradleBuildRoot.Linked>()
|
||||||
|
val byProjectDir = HashMap<String, GradleBuildRoot.Linked>()
|
||||||
|
|
||||||
|
val values: Collection<GradleBuildRoot>
|
||||||
|
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<String, GradleBuildRoot.Linked>? = 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
+280
@@ -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<GradleProjectSettings>) {
|
||||||
|
settings.forEach {
|
||||||
|
loadLinkedRoot(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProjectsUnlinked(linkedProjectPaths: MutableSet<String>) {
|
||||||
|
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<GradleExecutionSettings>(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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+66
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,12 +19,9 @@ import org.jetbrains.kotlin.psi.KtCallExpression
|
|||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.KtScriptInitializer
|
import org.jetbrains.kotlin.psi.KtScriptInitializer
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
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.GradleProjectSettings
|
||||||
import org.jetbrains.plugins.gradle.settings.GradleSettings
|
import org.jetbrains.plugins.gradle.settings.GradleSettings
|
||||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import kotlin.collections.HashMap
|
|
||||||
|
|
||||||
private val sections = arrayListOf("buildscript", "plugins", "initscript", "pluginManagement")
|
private val sections = arrayListOf("buildscript", "plugins", "initscript", "pluginManagement")
|
||||||
|
|
||||||
@@ -96,57 +93,5 @@ fun useScriptConfigurationFromImportOnly(): Boolean {
|
|||||||
return Registry.`is`("kotlin.gradle.scripts.useIdeaProjectImport", false)
|
return Registry.`is`("kotlin.gradle.scripts.useIdeaProjectImport", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGradleVersion(project: Project, settings: GradleProjectSettings): String {
|
fun getGradleProjectSettings(project: Project): Collection<GradleProjectSettings> =
|
||||||
val localVersion = GradleLocalSettings.getInstance(project).getGradleVersion(settings.externalProjectPath)
|
(ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID) as GradleSettings).linkedProjectsSettings
|
||||||
if (localVersion != null) return localVersion
|
|
||||||
|
|
||||||
return settings.resolveGradleVersion().version
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getGradleProjectSettings(project: Project): Collection<GradleProjectSettings> {
|
|
||||||
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<String, GradleBuildRoot>()
|
|
||||||
private val scripts = HashMap<String, GradleBuildRoot>()
|
|
||||||
val values: Collection<GradleBuildRoot>
|
|
||||||
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<String, GradleBuildRoot>? = 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-3
@@ -10,6 +10,7 @@ import junit.framework.AssertionFailedError
|
|||||||
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||||
import org.jetbrains.kotlin.idea.core.script.applySuggestedScriptConfiguration
|
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.DefaultScriptConfigurationLoader
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.loader.ScriptConfigurationLoadingContext
|
import org.jetbrains.kotlin.idea.core.script.configuration.loader.ScriptConfigurationLoadingContext
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.utils.areSimilar
|
import org.jetbrains.kotlin.idea.core.script.configuration.utils.areSimilar
|
||||||
@@ -37,7 +38,7 @@ class GradleKtsImportTest : GradleImportingTestCase() {
|
|||||||
fun data(): Collection<Array<Any?>> = listOf(arrayOf<Any?>("6.0.1"))
|
fun data(): Collection<Array<Any?>> = listOf(arrayOf<Any?>("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)
|
val projectDir get() = File(GradleSettings.getInstance(myProject).linkedProjectsSettings.first().externalProjectPath)
|
||||||
|
|
||||||
override fun testDataDirName(): String {
|
override fun testDataDirName(): String {
|
||||||
@@ -98,8 +99,8 @@ class GradleKtsImportTest : GradleImportingTestCase() {
|
|||||||
|
|
||||||
// reload configuration and check this it is not changed
|
// reload configuration and check this it is not changed
|
||||||
scripts.forEach {
|
scripts.forEach {
|
||||||
val reloadedConfiguration = scriptConfigurationManager.forceReloadConfiguration(
|
val reloadedConfiguration = scriptConfigurationManager.default.forceReloadConfiguration(
|
||||||
it.virtualFile,
|
it.psiFile,
|
||||||
object : DefaultScriptConfigurationLoader(it.psiFile.project) {
|
object : DefaultScriptConfigurationLoader(it.psiFile.project) {
|
||||||
override fun shouldRunInBackground(scriptDefinition: ScriptDefinition) = false
|
override fun shouldRunInBackground(scriptDefinition: ScriptDefinition) = false
|
||||||
override fun loadDependencies(
|
override fun loadDependencies(
|
||||||
|
|||||||
+6
-2
@@ -6,6 +6,9 @@
|
|||||||
package org.jetbrains.kotlin.idea.scripting.gradle
|
package org.jetbrains.kotlin.idea.scripting.gradle
|
||||||
|
|
||||||
import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel
|
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 org.junit.Test
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
@@ -13,11 +16,12 @@ import java.io.DataInputStream
|
|||||||
import java.io.DataOutputStream
|
import java.io.DataOutputStream
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class KotlinDslScriptModelsTest {
|
class GradleBuildRootDataSerializerTest {
|
||||||
@Test
|
@Test
|
||||||
fun write() {
|
fun write() {
|
||||||
val data = GradleImportedBuildRootData(
|
val data = GradleBuildRootData(
|
||||||
listOf("a", "b", "c"),
|
listOf("a", "b", "c"),
|
||||||
|
listOf("a"),
|
||||||
listOf(
|
listOf(
|
||||||
KotlinDslScriptModel(
|
KotlinDslScriptModel(
|
||||||
"a",
|
"a",
|
||||||
+2
-2
@@ -233,13 +233,13 @@ open class GradleScriptInputsWatcherTest : AbstractScriptConfigurationLoadingTes
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun assertConfigurationUpToDate(file: KtFile) {
|
private fun assertConfigurationUpToDate(file: KtFile) {
|
||||||
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file)
|
scriptConfigurationManager.default.ensureUpToDatedConfigurationSuggested(file)
|
||||||
assertNoBackgroundTasks()
|
assertNoBackgroundTasks()
|
||||||
assertNoLoading()
|
assertNoLoading()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertConfigurationUpdateWasDone(file: KtFile) {
|
private fun assertConfigurationUpdateWasDone(file: KtFile) {
|
||||||
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file)
|
scriptConfigurationManager.default.ensureUpToDatedConfigurationSuggested(file)
|
||||||
assertAndDoAllBackgroundTasks()
|
assertAndDoAllBackgroundTasks()
|
||||||
assertSingleLoading()
|
assertSingleLoading()
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -43,7 +43,7 @@ class GradleScriptOutOfProjectTest : AbstractScriptConfigurationLoadingTest() {
|
|||||||
fun testManualLoadingForUpToDate() {
|
fun testManualLoadingForUpToDate() {
|
||||||
assertConfigurationShouldBeLoadedManually()
|
assertConfigurationShouldBeLoadedManually()
|
||||||
|
|
||||||
scriptConfigurationManager.forceReloadConfiguration(myFile.virtualFile, loaderForOutOfProjectScripts)
|
scriptConfigurationManager.default.forceReloadConfiguration(myFile as KtFile, loaderForOutOfProjectScripts)
|
||||||
|
|
||||||
assertConfigurationWasLoaded()
|
assertConfigurationWasLoaded()
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ class GradleScriptOutOfProjectTest : AbstractScriptConfigurationLoadingTest() {
|
|||||||
assertNoBackgroundTasks()
|
assertNoBackgroundTasks()
|
||||||
assertNoLoading()
|
assertNoLoading()
|
||||||
|
|
||||||
scriptConfigurationManager.forceReloadConfiguration(myFile.virtualFile, loaderForOutOfProjectScripts)
|
scriptConfigurationManager.default.forceReloadConfiguration(myFile as KtFile, loaderForOutOfProjectScripts)
|
||||||
|
|
||||||
assertConfigurationWasLoaded()
|
assertConfigurationWasLoaded()
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ class GradleScriptOutOfProjectTest : AbstractScriptConfigurationLoadingTest() {
|
|||||||
fun testFileAttributesForManualLoading() {
|
fun testFileAttributesForManualLoading() {
|
||||||
assertConfigurationShouldBeLoadedManually()
|
assertConfigurationShouldBeLoadedManually()
|
||||||
|
|
||||||
scriptConfigurationManager.forceReloadConfiguration(myFile.virtualFile, loaderForOutOfProjectScripts)
|
scriptConfigurationManager.default.forceReloadConfiguration(myFile as KtFile, loaderForOutOfProjectScripts)
|
||||||
|
|
||||||
assertConfigurationWasLoaded()
|
assertConfigurationWasLoaded()
|
||||||
|
|
||||||
@@ -76,12 +76,12 @@ class GradleScriptOutOfProjectTest : AbstractScriptConfigurationLoadingTest() {
|
|||||||
fun testNoNotificationAfterForReload() {
|
fun testNoNotificationAfterForReload() {
|
||||||
assertConfigurationShouldBeLoadedManually()
|
assertConfigurationShouldBeLoadedManually()
|
||||||
|
|
||||||
scriptConfigurationManager.forceReloadConfiguration(myFile.virtualFile, loaderForOutOfProjectScripts)
|
scriptConfigurationManager.default.forceReloadConfiguration(myFile as KtFile, loaderForOutOfProjectScripts)
|
||||||
assertConfigurationWasLoaded()
|
assertConfigurationWasLoaded()
|
||||||
|
|
||||||
makeChangesInsideSections()
|
makeChangesInsideSections()
|
||||||
|
|
||||||
scriptConfigurationManager.forceReloadConfiguration(myFile.virtualFile, loaderForOutOfProjectScripts)
|
scriptConfigurationManager.default.forceReloadConfiguration(myFile as KtFile, loaderForOutOfProjectScripts)
|
||||||
assertConfigurationWasLoaded()
|
assertConfigurationWasLoaded()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<Int>()
|
|
||||||
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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,7 +17,8 @@
|
|||||||
<listener order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptListener"/>
|
<listener order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptListener"/>
|
||||||
|
|
||||||
<loader order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptConfigurationLoader"/>
|
<loader order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptConfigurationLoader"/>
|
||||||
<scriptingSupportProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptingSupportProvider"/>
|
|
||||||
|
<scriptingSupportProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||||
|
|||||||
@@ -14,10 +14,11 @@
|
|||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.kotlin.scripting.idea">
|
<extensions defaultExtensionNs="org.jetbrains.kotlin.scripting.idea">
|
||||||
<listener order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptListener"/>
|
<listener order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptListener"/>
|
||||||
<loader order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptConfigurationLoader"/>
|
<listener order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptListener"/>
|
||||||
<scriptingSupportProvider
|
|
||||||
implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptingSupportProvider"
|
<loader order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptConfigurationLoader"/>
|
||||||
/>
|
|
||||||
|
<scriptingSupportProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||||
|
|||||||
+4
-3
@@ -13,6 +13,7 @@ import com.intellij.openapi.vfs.VirtualFile
|
|||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import org.jetbrains.kotlin.idea.core.script.*
|
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.DefaultScriptConfigurationManagerExtensions
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.loader.FileContentsDependentConfigurationLoader
|
import org.jetbrains.kotlin.idea.core.script.configuration.loader.FileContentsDependentConfigurationLoader
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.testingBackgroundExecutor
|
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
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
|
||||||
abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurationTest() {
|
abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurationTest() {
|
||||||
lateinit var scriptConfigurationManager: ScriptConfigurationManager
|
lateinit var scriptConfigurationManager: CompositeScriptConfigurationManager
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var occurredLoadings = 0
|
private var occurredLoadings = 0
|
||||||
@@ -41,7 +42,7 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
|
|||||||
testScriptConfigurationNotification = true
|
testScriptConfigurationNotification = true
|
||||||
ApplicationManager.getApplication().isScriptChangesNotifierDisabled = false
|
ApplicationManager.getApplication().isScriptChangesNotifierDisabled = false
|
||||||
|
|
||||||
scriptConfigurationManager = ServiceManager.getService(project, ScriptConfigurationManager::class.java)
|
scriptConfigurationManager = ServiceManager.getService(project, ScriptConfigurationManager::class.java) as CompositeScriptConfigurationManager
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tearDown() {
|
override fun tearDown() {
|
||||||
@@ -103,7 +104,7 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
|
|||||||
protected fun makeChanges(contents: String, file: KtFile = myFile as KtFile) {
|
protected fun makeChanges(contents: String, file: KtFile = myFile as KtFile) {
|
||||||
changeContents(contents)
|
changeContents(contents)
|
||||||
|
|
||||||
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file)
|
scriptConfigurationManager.default.ensureUpToDatedConfigurationSuggested(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun changeContents(contents: String, file: PsiFile = myFile) {
|
protected fun changeContents(contents: String, file: PsiFile = myFile) {
|
||||||
|
|||||||
@@ -163,10 +163,10 @@ class ScriptConfigurationLoadingTest : AbstractScriptConfigurationLoadingTest()
|
|||||||
|
|
||||||
fun testLoadingForUsagesSearch() {
|
fun testLoadingForUsagesSearch() {
|
||||||
assertAndLoadInitialConfiguration()
|
assertAndLoadInitialConfiguration()
|
||||||
assertTrue(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(myFile as KtFile)))
|
assertTrue(scriptConfigurationManager.default.ensureConfigurationUpToDate(listOf(myFile as KtFile)))
|
||||||
|
|
||||||
changeContents("A")
|
changeContents("A")
|
||||||
assertFalse(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(myFile as KtFile)))
|
assertFalse(scriptConfigurationManager.default.ensureConfigurationUpToDate(listOf(myFile as KtFile)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testReportsOnAutoApply() {
|
fun testReportsOnAutoApply() {
|
||||||
|
|||||||
Reference in New Issue
Block a user