Refactor script definitions and resolving/refining infrastructure:
- implement wrappers to wrap old and new API providers and resolvers - make old API deprecated (with error where possible) - drop old internal classes related to the old API - refactor usages accordingly - fix and add missing features to the scripting API where necessary
This commit is contained in:
+1
-1
@@ -43,7 +43,7 @@ class JvmCliScriptEvaluationExtension : ScriptEvaluationExtension {
|
||||
val scriptFile = File(sourcePath)
|
||||
if (scriptFile.isDirectory || !scriptDefinitionProvider.isScript(scriptFile.name)) {
|
||||
val extensionHint =
|
||||
if (configuration.get(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS) == listOf(StandardScriptDefinition)) " (.kts)"
|
||||
if (configuration.get(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS)?.let { it.size == 1 && it.first().isDefault } == true) " (.kts)"
|
||||
else ""
|
||||
messageCollector.report(ERROR, "Specify path to the script file$extensionHint as the first argument")
|
||||
return COMPILATION_ERROR
|
||||
|
||||
+26
-32
@@ -18,13 +18,14 @@ import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
|
||||
import org.jetbrains.kotlin.scripting.configuration.configureScriptDefinitions
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsFromClasspathDiscoverySource
|
||||
import org.jetbrains.kotlin.scripting.definitions.StandardScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.reporter
|
||||
import org.jetbrains.kotlin.scripting.definitions.*
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
|
||||
class ScriptingCompilerConfigurationExtension(val project: MockProject) : CompilerConfigurationExtension {
|
||||
class ScriptingCompilerConfigurationExtension(
|
||||
val project: MockProject,
|
||||
val baseHostConfiguration: ScriptingHostConfiguration
|
||||
) : CompilerConfigurationExtension {
|
||||
|
||||
override fun updateConfiguration(configuration: CompilerConfiguration) {
|
||||
|
||||
@@ -39,7 +40,11 @@ class ScriptingCompilerConfigurationExtension(val project: MockProject) : Compil
|
||||
projectRoot
|
||||
)
|
||||
}
|
||||
val scriptResolverEnv = configuration.getMap(ScriptingConfigurationKeys.LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION)
|
||||
val hostConfiguration = ScriptingHostConfiguration(baseHostConfiguration) {
|
||||
getEnvironment {
|
||||
configuration.getMap(ScriptingConfigurationKeys.LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION)
|
||||
}
|
||||
}
|
||||
|
||||
val explicitScriptDefinitions = configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS_CLASSES)
|
||||
|
||||
@@ -49,16 +54,16 @@ class ScriptingCompilerConfigurationExtension(val project: MockProject) : Compil
|
||||
configuration,
|
||||
this::class.java.classLoader,
|
||||
messageCollector,
|
||||
scriptResolverEnv
|
||||
hostConfiguration
|
||||
)
|
||||
}
|
||||
// If not disabled explicitly, we should always support at least the standard script definition
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
|
||||
!configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS).contains(StandardScriptDefinition)
|
||||
configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS).none { it.isDefault }
|
||||
) {
|
||||
configuration.add(
|
||||
ScriptingConfigurationKeys.SCRIPT_DEFINITIONS,
|
||||
StandardScriptDefinition
|
||||
ScriptDefinition.getDefault(hostConfiguration)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -66,37 +71,26 @@ class ScriptingCompilerConfigurationExtension(val project: MockProject) : Compil
|
||||
ScriptingConfigurationKeys.SCRIPT_DEFINITIONS_SOURCES,
|
||||
ScriptDefinitionsFromClasspathDiscoverySource(
|
||||
configuration.jvmClasspathRoots,
|
||||
configuration.get(ScriptingConfigurationKeys.LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION) ?: emptyMap(),
|
||||
hostConfiguration,
|
||||
messageCollector.reporter
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// If not disabled explicitly, we should always support at least the standard script definition
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
|
||||
StandardScriptDefinition !in configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS)
|
||||
) {
|
||||
configuration.add(
|
||||
ScriptingConfigurationKeys.SCRIPT_DEFINITIONS,
|
||||
StandardScriptDefinition
|
||||
)
|
||||
}
|
||||
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider
|
||||
if (scriptDefinitionProvider != null) {
|
||||
scriptDefinitionProvider.setScriptDefinitionsSources(configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS_SOURCES))
|
||||
scriptDefinitionProvider.setScriptDefinitions(configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS))
|
||||
|
||||
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider
|
||||
if (scriptDefinitionProvider != null) {
|
||||
scriptDefinitionProvider.setScriptDefinitionsSources(configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS_SOURCES))
|
||||
scriptDefinitionProvider.setScriptDefinitions(configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS))
|
||||
// Register new file extensions
|
||||
val fileTypeRegistry = FileTypeRegistry.getInstance() as CoreFileTypeRegistry
|
||||
|
||||
// Register new file extensions
|
||||
val fileTypeRegistry = FileTypeRegistry.getInstance() as CoreFileTypeRegistry
|
||||
|
||||
scriptDefinitionProvider.getKnownFilenameExtensions().filter {
|
||||
fileTypeRegistry.getFileTypeByExtension(it) != KotlinFileType.INSTANCE
|
||||
}.forEach {
|
||||
fileTypeRegistry.registerFileType(KotlinFileType.INSTANCE, it)
|
||||
scriptDefinitionProvider.getKnownFilenameExtensions().filter {
|
||||
fileTypeRegistry.getFileTypeByExtension(it) != KotlinFileType.INSTANCE
|
||||
}.forEach {
|
||||
fileTypeRegistry.registerFileType(KotlinFileType.INSTANCE, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-14
@@ -5,33 +5,29 @@
|
||||
|
||||
package org.jetbrains.kotlin.scripting.compiler.plugin.definitions
|
||||
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.LazyScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsSource
|
||||
import org.jetbrains.kotlin.scripting.definitions.StandardScriptDefinition
|
||||
import kotlin.concurrent.write
|
||||
|
||||
open class CliScriptDefinitionProvider : LazyScriptDefinitionProvider() {
|
||||
private val definitionsFromSources: MutableList<Sequence<KotlinScriptDefinition>> = arrayListOf()
|
||||
private val definitions: MutableList<KotlinScriptDefinition> = arrayListOf()
|
||||
private var hasStandardDefinition = true
|
||||
private val definitionsFromSources: MutableList<Sequence<ScriptDefinition>> = arrayListOf()
|
||||
private val definitions: MutableList<ScriptDefinition> = arrayListOf()
|
||||
private var defaultDefinition: ScriptDefinition? = null
|
||||
|
||||
override val currentDefinitions: Sequence<KotlinScriptDefinition>
|
||||
override val currentDefinitions: Sequence<ScriptDefinition>
|
||||
get() {
|
||||
val base = definitions.asSequence() + definitionsFromSources.asSequence().flatMap { it }
|
||||
return if (hasStandardDefinition) base + getDefaultScriptDefinition() else base
|
||||
return base + getDefaultDefinition()
|
||||
}
|
||||
|
||||
override fun getDefaultScriptDefinition(): KotlinScriptDefinition {
|
||||
return StandardScriptDefinition
|
||||
}
|
||||
|
||||
fun setScriptDefinitions(newDefinitions: List<KotlinScriptDefinition>) {
|
||||
fun setScriptDefinitions(newDefinitions: List<ScriptDefinition>) {
|
||||
lock.write {
|
||||
definitions.clear()
|
||||
val (withoutStdDef, stdDef) = newDefinitions.partition { it != getDefaultScriptDefinition() }
|
||||
val (withoutStdDef, stdDef) = newDefinitions.partition { !it.isDefault }
|
||||
definitions.addAll(withoutStdDef)
|
||||
hasStandardDefinition = stdDef.isNotEmpty()
|
||||
// TODO: consider reporting an error when several default definitions are supplied
|
||||
defaultDefinition = stdDef.firstOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,4 +39,6 @@ open class CliScriptDefinitionProvider : LazyScriptDefinitionProvider() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDefaultDefinition(): ScriptDefinition = defaultDefinition ?: super.getDefaultDefinition()
|
||||
}
|
||||
|
||||
+17
-16
@@ -11,44 +11,45 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptContentLoader
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
|
||||
import org.jetbrains.kotlin.scripting.resolve.adjustByDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
|
||||
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
|
||||
import java.io.File
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||
import kotlin.script.experimental.jvm.compat.mapToLegacyReports
|
||||
|
||||
class CliScriptDependenciesProvider(private val project: Project) : ScriptDependenciesProvider {
|
||||
private val cacheLock = ReentrantReadWriteLock()
|
||||
private val cache = hashMapOf<String, ScriptDependencies?>()
|
||||
private val scriptContentLoader = ScriptContentLoader(project)
|
||||
private val cache = hashMapOf<String, ScriptCompilationConfigurationResult?>()
|
||||
|
||||
override fun getScriptDependencies(file: VirtualFile): ScriptDependencies? = cacheLock.read {
|
||||
calculateExternalDependencies(file)
|
||||
override fun getScriptConfigurationResult(file: VirtualFile): ScriptCompilationConfigurationResult? = cacheLock.read {
|
||||
calculateRefinedConfiguration(file)
|
||||
}
|
||||
|
||||
private fun calculateExternalDependencies(file: VirtualFile): ScriptDependencies? {
|
||||
private fun calculateRefinedConfiguration(file: VirtualFile): ScriptCompilationConfigurationResult? {
|
||||
val path = file.path
|
||||
val cached = cache[path]
|
||||
return if (cached != null) cached
|
||||
else {
|
||||
val scriptDef = file.findScriptDefinition(project)
|
||||
if (scriptDef != null) {
|
||||
val result = scriptContentLoader.loadContentsAndResolveDependencies(scriptDef, file)
|
||||
val result = refineScriptCompilationConfiguration(VirtualFileScriptSource(file), scriptDef, project)
|
||||
|
||||
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports)
|
||||
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports.mapToLegacyReports())
|
||||
|
||||
val deps = result.dependencies?.adjustByDefinition(scriptDef)
|
||||
|
||||
if (deps != null) {
|
||||
log.info("[kts] new cached deps for $path: ${deps.classpath.joinToString(File.pathSeparator)}")
|
||||
if (result is ResultWithDiagnostics.Success) {
|
||||
log.info("[kts] new cached deps for $path: ${result.value.dependenciesClassPath.joinToString(File.pathSeparator)}")
|
||||
} else {
|
||||
log.info("[kts] new cached errors for $path:\n ${result.reports.joinToString("\n ") { it.message + if (it.exception == null) "" else ": ${it.exception}" }}")
|
||||
}
|
||||
cacheLock.write {
|
||||
cache.put(path, deps)
|
||||
cache.put(path, result)
|
||||
}
|
||||
deps
|
||||
result
|
||||
} else null
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptReportSink
|
||||
import org.jetbrains.kotlin.scripting.configuration.makeHostConfiguration
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.scripting.extensions.*
|
||||
@@ -39,8 +40,9 @@ private fun <T> ProjectExtensionDescriptor<T>.registerExtensionIfRequired(projec
|
||||
class ScriptingCompilerConfigurationComponentRegistrar : ComponentRegistrar {
|
||||
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
||||
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
val hostConfiguration = makeHostConfiguration(project, configuration)
|
||||
withClassloadingProblemsReporting(messageCollector) {
|
||||
CompilerConfigurationExtension.registerExtension(project, ScriptingCompilerConfigurationExtension(project))
|
||||
CompilerConfigurationExtension.registerExtension(project, ScriptingCompilerConfigurationExtension(project, hostConfiguration))
|
||||
CollectAdditionalSourcesExtension.registerExtension(project, ScriptingCollectAdditionalSourcesExtension(project))
|
||||
ScriptEvaluationExtension.registerExtensionIfRequired(project, JvmCliScriptEvaluationExtension())
|
||||
ShellExtension.registerExtensionIfRequired(project, JvmCliReplShellExtension())
|
||||
|
||||
+11
-4
@@ -7,11 +7,13 @@ package org.jetbrains.kotlin.scripting.compiler.plugin
|
||||
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsSource
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
import kotlin.script.templates.standard.ScriptTemplateWithArgs
|
||||
|
||||
class ScriptProviderTest : KtUsefulTestCase() {
|
||||
@@ -64,11 +66,16 @@ class ScriptProviderTest : KtUsefulTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
private open class FakeScriptDefinition(val suffix: String = ".kts") : KotlinScriptDefinition(ScriptTemplateWithArgs::class) {
|
||||
private open class FakeScriptDefinition(val suffix: String = ".kts") :
|
||||
ScriptDefinition.FromLegacy(defaultJvmScriptingHostConfiguration, KotlinScriptDefinition(ScriptTemplateWithArgs::class))
|
||||
{
|
||||
val matchCounter = AtomicInteger()
|
||||
override fun isScript(fileName: String): Boolean = fileName.endsWith(suffix).also {
|
||||
if (it) matchCounter.incrementAndGet()
|
||||
}
|
||||
|
||||
override val isDefault: Boolean
|
||||
get() = suffix == ".kts"
|
||||
}
|
||||
|
||||
private class TestScriptDefinitionSource(val counter: AtomicInteger, val defGens: Iterable<() -> FakeScriptDefinition>) :
|
||||
@@ -80,7 +87,7 @@ private class TestScriptDefinitionSource(val counter: AtomicInteger, val defGens
|
||||
)
|
||||
} })
|
||||
|
||||
override val definitions: Sequence<KotlinScriptDefinition> = sequence {
|
||||
override val definitions: Sequence<ScriptDefinition> = sequence {
|
||||
for (gen in defGens) {
|
||||
counter.incrementAndGet()
|
||||
yield(gen())
|
||||
@@ -88,6 +95,6 @@ private class TestScriptDefinitionSource(val counter: AtomicInteger, val defGens
|
||||
}
|
||||
}
|
||||
|
||||
private class TestCliScriptDefinitionProvider(private val standardDef: KotlinScriptDefinition) : CliScriptDefinitionProvider() {
|
||||
override fun getDefaultScriptDefinition(): KotlinScriptDefinition = standardDef
|
||||
private class TestCliScriptDefinitionProvider(private val standardDef: ScriptDefinition) : CliScriptDefinitionProvider() {
|
||||
override fun getDefaultScriptDefinition(): KotlinScriptDefinition = standardDef.legacyDefinition
|
||||
}
|
||||
+4
-3
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.utils.KotlinPaths
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
|
||||
class ScriptingCompilerPluginTest : TestCaseWithTmpdir() {
|
||||
|
||||
@@ -116,7 +117,7 @@ class ScriptingCompilerPluginTest : TestCaseWithTmpdir() {
|
||||
|
||||
loadScriptTemplatesFromClasspath(
|
||||
listOf("TestScriptWithReceivers", "TestScriptWithSimpleEnvVars"),
|
||||
listOf(defsOut), emptyList(), this::class.java.classLoader, emptyMap(), messageCollector.reporter
|
||||
listOf(defsOut), emptyList(), this::class.java.classLoader, defaultJvmScriptingHostConfiguration, messageCollector.reporter
|
||||
).toList()
|
||||
|
||||
for (def in defClasses) {
|
||||
@@ -141,7 +142,7 @@ class ScriptingCompilerPluginTest : TestCaseWithTmpdir() {
|
||||
discoverScriptTemplatesInClasspath(
|
||||
listOf(defsOut),
|
||||
this::class.java.classLoader,
|
||||
emptyMap(),
|
||||
defaultJvmScriptingHostConfiguration,
|
||||
messageCollector.reporter
|
||||
)
|
||||
|
||||
@@ -212,7 +213,7 @@ class ScriptingCompilerPluginTest : TestCaseWithTmpdir() {
|
||||
discoverScriptTemplatesInClasspath(
|
||||
listOf(defsOut),
|
||||
this::class.java.classLoader,
|
||||
emptyMap(),
|
||||
defaultJvmScriptingHostConfiguration,
|
||||
messageCollector.reporter
|
||||
).toList()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user