Refactor configs loading, Add config script definitions reloading on config files changes

This commit is contained in:
Ilya Chernikov
2016-06-01 12:25:53 +02:00
parent 310e8014a8
commit dfc96d216b
3 changed files with 47 additions and 24 deletions
@@ -40,23 +40,21 @@ import java.util.*
val SCRIPT_CONFIG_FILE_EXTENSION = ".ktscfg.xml" val SCRIPT_CONFIG_FILE_EXTENSION = ".ktscfg.xml"
fun loadScriptDefinitionsFromDirectoryWithConfigs(dir: File, kotlinEnvVars: Map<String, List<String>>? = null): List<KotlinConfigurableScriptDefinition> = fun isScriptDefinitionConfigFile(it: File) = it.isFile && it.name.endsWith(SCRIPT_CONFIG_FILE_EXTENSION, ignoreCase = true)
dir.walk().filter { it.isFile && it.name.endsWith(SCRIPT_CONFIG_FILE_EXTENSION, ignoreCase = true) }.toList()
.flatMap { loadScriptDefinitionsFromConfig(it, kotlinEnvVars) }
fun loadScriptDefinitionsFromConfig(configFile: File, kotlinEnvVars: Map<String, List<String>>? = null): List<KotlinConfigurableScriptDefinition> = fun loadScriptConfigsFromProjectRoot(projectRoot: File): List<KotlinScriptConfig> =
projectRoot.walk().filter ( ::isScriptDefinitionConfigFile ).toList()
.flatMap { loadScriptConfigs(it) }
fun loadScriptConfigs(configFile: File): List<KotlinScriptConfig> =
JDOMUtil.loadDocument(configFile).rootElement.children.mapNotNull { JDOMUtil.loadDocument(configFile).rootElement.children.mapNotNull {
XmlSerializer.deserialize(it, KotlinScriptConfig::class.java)?.let { XmlSerializer.deserialize(it, KotlinScriptConfig::class.java)
KotlinConfigurableScriptDefinition(it, kotlinEnvVars)
}
} }
@Suppress("unused") // Used externally @Suppress("unused") // Used externally
fun loadScriptDefinitionsFromConfig(configStream: InputStream, kotlinEnvVars: Map<String, List<String>>? = null): List<KotlinConfigurableScriptDefinition> = fun loadScriptConfigs(configStream: InputStream): List<KotlinScriptConfig> =
JDOMUtil.loadDocument(configStream).rootElement.children.mapNotNull { JDOMUtil.loadDocument(configStream).rootElement.children.mapNotNull {
XmlSerializer.deserialize(it, KotlinScriptConfig::class.java)?.let { XmlSerializer.deserialize(it, KotlinScriptConfig::class.java)
KotlinConfigurableScriptDefinition(it, kotlinEnvVars)
}
} }
@Suppress("unused") @Suppress("unused")
@@ -135,3 +133,4 @@ class KotlinConfigurableScriptDefinition(val config: KotlinScriptConfig, val env
} }
} }
} }
@@ -19,25 +19,34 @@ package org.jetbrains.kotlin.script
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
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 java.util.* import kotlin.concurrent.read
import kotlin.concurrent.write
class KotlinScriptDefinitionProvider { class KotlinScriptDefinitionProvider {
private val definitions: MutableList<KotlinScriptDefinition> = arrayListOf(StandardScriptDefinition) private val definitions: MutableList<KotlinScriptDefinition> = arrayListOf(StandardScriptDefinition)
private val definitionsLock = java.util.concurrent.locks.ReentrantReadWriteLock()
var scriptDefinitions: List<KotlinScriptDefinition> var scriptDefinitions: List<KotlinScriptDefinition>
get() = definitions get() = definitionsLock.read { definitions } // TODO: remove as unsafe with locking, replace with particular data extractors
set(definitions: List<KotlinScriptDefinition>) { set(definitions: List<KotlinScriptDefinition>) {
this.definitions.clear() definitionsLock.write {
this.definitions.addAll(definitions) this.definitions.clear()
this.definitions.addAll(definitions)
}
} }
fun findScriptDefinition(file: VirtualFile?): KotlinScriptDefinition? = file?.let { file -> definitions.firstOrNull { it.isScript(file) } } fun findScriptDefinition(file: VirtualFile?): KotlinScriptDefinition? = definitionsLock.read {
file?.let { file -> definitions.firstOrNull { it.isScript(file) } }
}
fun isScript(file: VirtualFile?): Boolean = findScriptDefinition(file) != null fun isScript(file: VirtualFile?): Boolean = findScriptDefinition(file) != null
fun addScriptDefinition(scriptDefinition: KotlinScriptDefinition) { fun addScriptDefinition(scriptDefinition: KotlinScriptDefinition) {
definitions.add(0, scriptDefinition) definitionsLock.write {
definitions.add(0, scriptDefinition)
}
} }
fun removeScriptDefinition(scriptDefinition: KotlinScriptDefinition) { fun removeScriptDefinition(scriptDefinition: KotlinScriptDefinition) {
@@ -18,15 +18,17 @@ package org.jetbrains.kotlin.idea.script
import com.intellij.openapi.components.AbstractProjectComponent import com.intellij.openapi.components.AbstractProjectComponent
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider import com.intellij.openapi.vfs.VirtualFileManager
import org.jetbrains.kotlin.script.StandardScriptDefinition import com.intellij.openapi.vfs.newvfs.BulkFileListener
import org.jetbrains.kotlin.script.loadScriptDefinitionsFromDirectoryWithConfigs import com.intellij.openapi.vfs.newvfs.events.VFileEvent
import org.jetbrains.kotlin.script.*
import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.PathUtil
import java.io.File import java.io.File
class KotlinScriptConfigurationManager(project: Project, scriptDefinitionProvider: KotlinScriptDefinitionProvider) : AbstractProjectComponent(project) { @Suppress("unused") // project component
class KotlinScriptConfigurationManager(private val project: Project, private val scriptDefinitionProvider: KotlinScriptDefinitionProvider) : AbstractProjectComponent(project) {
val kotlinEnvVars: Map<String, List<String>> by lazy { private val kotlinEnvVars: Map<String, List<String>> by lazy {
val paths = PathUtil.getKotlinPathsForIdeaPlugin() val paths = PathUtil.getKotlinPathsForIdeaPlugin()
mapOf("kotlin-runtime" to listOf(paths.runtimePath.canonicalPath), mapOf("kotlin-runtime" to listOf(paths.runtimePath.canonicalPath),
"project-root" to listOf(project.basePath ?: "."), "project-root" to listOf(project.basePath ?: "."),
@@ -34,9 +36,22 @@ class KotlinScriptConfigurationManager(project: Project, scriptDefinitionProvide
} }
init { init {
loadScriptDefinitionsFromDirectoryWithConfigs(File(project.basePath ?: "."), kotlinEnvVars).let { reloadScriptDefinitions()
val conn = project.messageBus.connect()
conn.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener.Adapter() {
override fun after(events: List<VFileEvent>) {
events.firstOrNull { it is VFileEvent && isScriptDefinitionConfigFile(File(it.path)) }?.let {
reloadScriptDefinitions()
}
}
})
}
private fun reloadScriptDefinitions() {
loadScriptConfigsFromProjectRoot(File(project.basePath ?: ".")).let {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
scriptDefinitionProvider.scriptDefinitions = it + StandardScriptDefinition scriptDefinitionProvider.scriptDefinitions =
it.map { KotlinConfigurableScriptDefinition(it, kotlinEnvVars) } + StandardScriptDefinition
} }
} }
} }