Process script templates everywhere properly:
- add options to disable scripting plugin and standard script definition - move standard definition adding logic into appropriate place - fix logic of scripting plugin loading - add standard script definition on the environment creation to ensure compatibility with all usages - fix testdata - some minor fixes
This commit is contained in:
+3
@@ -234,6 +234,9 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value = "-Xdisable-default-scripting-plugin", description = "Do not enable scripting plugin by default")
|
||||
var disableDefaultScriptingPlugin: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(value = "-Xdisable-standard-script", description = "Disable standard kotlin script support")
|
||||
var disableStandardScript: Boolean by FreezableVar(false)
|
||||
|
||||
// Paths to output directories for friend modules.
|
||||
var friendPaths: Array<String>? by FreezableVar(null)
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.cli.jvm
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.openapi.Disposable
|
||||
import org.jetbrains.kotlin.cli.common.CLICompiler
|
||||
import org.jetbrains.kotlin.cli.common.CLICompiler.getLibraryFromHome
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.CLITool
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
@@ -68,6 +69,10 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
if (it != OK) return it
|
||||
}
|
||||
|
||||
if (arguments.disableStandardScript) {
|
||||
configuration.put(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION, true)
|
||||
}
|
||||
|
||||
val pluginLoadResult = loadPlugins(paths, arguments, configuration)
|
||||
if (pluginLoadResult != ExitCode.OK) return pluginLoadResult
|
||||
|
||||
@@ -223,35 +228,40 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
private fun loadPlugins(paths: KotlinPaths?, arguments: K2JVMCompilerArguments, configuration: CompilerConfiguration): ExitCode {
|
||||
val pluginClasspaths = arguments.pluginClasspaths?.toMutableList() ?: ArrayList()
|
||||
val pluginOptions = arguments.pluginOptions?.toMutableList() ?: ArrayList()
|
||||
val isEmbeddable =
|
||||
try {
|
||||
this::class.java.classLoader.loadClass("com.intellij.mock.MockProject") == null
|
||||
} catch (_: ClassNotFoundException) {
|
||||
true
|
||||
} catch (_: NoClassDefFoundError) {
|
||||
true
|
||||
}
|
||||
|
||||
if (!isEmbeddable &&
|
||||
pluginClasspaths.none { File(it).name == PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR } &&
|
||||
!arguments.disableDefaultScriptingPlugin
|
||||
) {
|
||||
// if scripting plugin is not enabled explicitly (probably from another path) try to enable it implicitly
|
||||
val libPath = paths?.libPath ?: File(".")
|
||||
val pluginJar = File(libPath, PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR)
|
||||
val scriptingJar = File(libPath, PathUtil.KOTLIN_SCRIPTING_COMMON_JAR)
|
||||
val scriptingJvmJar = File(libPath, PathUtil.KOTLIN_SCRIPTING_JVM_JAR)
|
||||
if (pluginJar.exists() && scriptingJar.exists() && scriptingJvmJar.exists()) {
|
||||
pluginClasspaths.addAll(listOf(pluginJar.canonicalPath, scriptingJar.canonicalPath, scriptingJvmJar.canonicalPath))
|
||||
if (arguments.scriptTemplates?.isNotEmpty() == true) {
|
||||
pluginOptions.add("-P")
|
||||
pluginOptions.add("plugin:kotlin.scripting:script-templates=${arguments.scriptTemplates!!.joinToString(",")}")
|
||||
}
|
||||
if (arguments.scriptResolverEnvironment?.isNotEmpty() == true) {
|
||||
pluginOptions.add("-P")
|
||||
pluginOptions.add("plugin:kotlin.scripting:script-resolver-environment=${arguments.scriptResolverEnvironment!!.joinToString(",")}")
|
||||
if (!arguments.disableDefaultScriptingPlugin) {
|
||||
val explicitOrLoadedScriptingPlugin =
|
||||
pluginClasspaths.any { File(it).name == PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR } ||
|
||||
try {
|
||||
PluginCliParser::class.java.classLoader.loadClass("org.jetbrains.kotlin.extensions.ScriptingCompilerConfigurationExtension")
|
||||
true
|
||||
} catch (_: Throwable) {
|
||||
false
|
||||
}
|
||||
// if scripting plugin is not enabled explicitly (probably from another path) and not in the classpath already,
|
||||
// try to find and enable it implicitly
|
||||
if (!explicitOrLoadedScriptingPlugin) {
|
||||
val libPath = paths?.libPath?.takeIf { it.exists() } ?: File(".")
|
||||
with(PathUtil) {
|
||||
val jars = arrayOf(KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMMON_JAR, KOTLIN_SCRIPTING_JVM_JAR)
|
||||
.mapNotNull { File(libPath, it).takeIf { it.exists() }?.canonicalPath }
|
||||
if (jars.size == 3) {
|
||||
pluginClasspaths.addAll(jars)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (arguments.scriptTemplates?.isNotEmpty() == true) {
|
||||
pluginOptions.add("plugin:kotlin.scripting:script-templates=${arguments.scriptTemplates!!.joinToString(",")}")
|
||||
}
|
||||
if (arguments.scriptResolverEnvironment?.isNotEmpty() == true) {
|
||||
pluginOptions.add(
|
||||
"plugin:kotlin.scripting:script-resolver-environment=${arguments.scriptResolverEnvironment!!.joinToString(
|
||||
","
|
||||
)}"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
pluginOptions.add("plugin:kotlin.scripting:disable=true")
|
||||
}
|
||||
return PluginCliParser.loadPluginsSafe(pluginClasspaths, pluginOptions, configuration)
|
||||
}
|
||||
|
||||
@@ -207,9 +207,6 @@ class KotlinCoreEnvironment private constructor(
|
||||
})
|
||||
sourceFiles.sortBy { it.virtualFile.path }
|
||||
|
||||
// We should always support at least the standard script definition
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
|
||||
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider
|
||||
if (scriptDefinitionProvider != null) {
|
||||
scriptDefinitionProvider.setScriptDefinitions(
|
||||
@@ -410,6 +407,12 @@ class KotlinCoreEnvironment private constructor(
|
||||
parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
|
||||
): KotlinCoreEnvironment {
|
||||
setCompatibleBuild()
|
||||
// If not disabled explicitly, we should always support at least the standard script definition
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
|
||||
!configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).contains(StandardScriptDefinition)
|
||||
) {
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
}
|
||||
val appEnv = getOrCreateApplicationEnvironmentForProduction(configuration)
|
||||
// Disposing of the environment is unsafe in production then parallel builds are enabled, but turning it off universally
|
||||
// breaks a lot of tests, therefore it is disabled for production and enabled for tests
|
||||
@@ -444,7 +447,10 @@ class KotlinCoreEnvironment private constructor(
|
||||
parentDisposable: Disposable, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles
|
||||
): KotlinCoreEnvironment {
|
||||
val configuration = initialConfiguration.copy()
|
||||
if (configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).isEmpty()) {
|
||||
// in tests we assume that standard definition should only be added if no other explicit defs are already added
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
|
||||
configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).isEmpty()
|
||||
) {
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
}
|
||||
// Tests are supposed to create a single project and dispose it right after use
|
||||
|
||||
@@ -49,6 +49,9 @@ public class JVMConfigurationKeys {
|
||||
public static final CompilerConfigurationKey<List<KotlinScriptDefinition>> SCRIPT_DEFINITIONS =
|
||||
CompilerConfigurationKey.create("script definitions");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> DISABLE_STANDARD_SCRIPT_DEFINITION =
|
||||
CompilerConfigurationKey.create("Disable standard kotlin script support");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> RETAIN_OUTPUT_IN_MEMORY =
|
||||
CompilerConfigurationKey.create("retain compiled classes in memory for further use, e.g. when running scripts");
|
||||
|
||||
|
||||
+1
@@ -10,6 +10,7 @@ where advanced options include:
|
||||
-Xdump-declarations-to=<path> Path to JSON file to dump Java to Kotlin declaration mappings
|
||||
-Xdisable-default-scripting-plugin
|
||||
Do not enable scripting plugin by default
|
||||
-Xdisable-standard-script Disable standard kotlin script support
|
||||
-Xenable-jvm-default Allow to use '@JvmDefault' for JVM default method support
|
||||
-Xmultifile-parts-inherit Compile multifile classes as a hierarchy of parts and facade
|
||||
-Xmodule-path=<path> Paths where to find Java 9+ modules
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
error: specify path to the script file as the first argument
|
||||
error: specify path to the script file (.kts) as the first argument
|
||||
COMPILATION_ERROR
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
error: specify path to the script file as the first argument
|
||||
error: specify path to the script file (.kts) as the first argument
|
||||
COMPILATION_ERROR
|
||||
|
||||
+29
-2
@@ -11,15 +11,19 @@ import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
|
||||
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
|
||||
object ScriptingConfigurationKeys {
|
||||
val DISABLE_SCRIPTING_PLUGIN_OPTION: CompilerConfigurationKey<Boolean> =
|
||||
CompilerConfigurationKey.create("Disable scripting plugin")
|
||||
|
||||
val SCRIPT_DEFINITIONS: CompilerConfigurationKey<List<String>> =
|
||||
CompilerConfigurationKey.create("Script definition classes")
|
||||
|
||||
val SCRIPT_DEFINITIONS_CLASSPATH: CompilerConfigurationKey<List<File>> =
|
||||
CompilerConfigurationKey.create("Additional classpath for the script definitions")
|
||||
|
||||
val DISABLE_SCRIPT_DEFINITIONS_FROM_CLSSPATH_OPTION: CompilerConfigurationKey<Boolean> =
|
||||
val DISABLE_SCRIPT_DEFINITIONS_FROM_CLASSPATH_OPTION: CompilerConfigurationKey<Boolean> =
|
||||
CompilerConfigurationKey.create("Do not extract script definitions from the compilation classpath")
|
||||
|
||||
val LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION: CompilerConfigurationKey<MutableMap<String, Any?>> =
|
||||
@@ -28,6 +32,10 @@ object ScriptingConfigurationKeys {
|
||||
|
||||
class ScriptingCommandLineProcessor : CommandLineProcessor {
|
||||
companion object {
|
||||
val DISABLE_SCRIPTING_PLUGIN_OPTION = CliOption(
|
||||
"disable", "true/false", "Disable scripting plugin",
|
||||
required = false, allowMultipleOccurrences = false
|
||||
)
|
||||
val SCRIPT_DEFINITIONS_OPTION = CliOption(
|
||||
"script-definitions", "<fully qualified class name[,]>", "Script definition classes",
|
||||
required = false, allowMultipleOccurrences = true
|
||||
@@ -36,6 +44,10 @@ class ScriptingCommandLineProcessor : CommandLineProcessor {
|
||||
"script-definitions-classpath", "<classpath entry[:]>", "Additional classpath for the script definitions",
|
||||
required = false, allowMultipleOccurrences = true
|
||||
)
|
||||
val DISABLE_STANDARD_SCRIPT_DEFINITION_OPTION = CliOption(
|
||||
"disable-standard-script", "true/false", "Disable standard kotlin script support",
|
||||
required = false, allowMultipleOccurrences = false
|
||||
)
|
||||
val DISABLE_SCRIPT_DEFINITIONS_FROM_CLSSPATH_OPTION = CliOption(
|
||||
"disable-script-definitions-from-classpath", "true/false", "Do not extract script definitions from the compilation classpath",
|
||||
required = false, allowMultipleOccurrences = false
|
||||
@@ -56,14 +68,23 @@ class ScriptingCommandLineProcessor : CommandLineProcessor {
|
||||
override val pluginId = PLUGIN_ID
|
||||
override val pluginOptions =
|
||||
listOf(
|
||||
DISABLE_SCRIPTING_PLUGIN_OPTION,
|
||||
SCRIPT_DEFINITIONS_OPTION,
|
||||
SCRIPT_DEFINITIONS_CLASSPATH_OPTION,
|
||||
DISABLE_STANDARD_SCRIPT_DEFINITION_OPTION,
|
||||
DISABLE_SCRIPT_DEFINITIONS_FROM_CLSSPATH_OPTION,
|
||||
LEGACY_SCRIPT_TEMPLATES_OPTION,
|
||||
LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION
|
||||
)
|
||||
|
||||
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) = when (option) {
|
||||
DISABLE_SCRIPTING_PLUGIN_OPTION -> {
|
||||
configuration.put(
|
||||
ScriptingConfigurationKeys.DISABLE_SCRIPTING_PLUGIN_OPTION,
|
||||
value.takeUnless { it.isBlank() }?.toBoolean() ?: true
|
||||
)
|
||||
}
|
||||
|
||||
SCRIPT_DEFINITIONS_OPTION, LEGACY_SCRIPT_TEMPLATES_OPTION -> {
|
||||
val currentDefs = configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS).toMutableList()
|
||||
currentDefs.addAll(value.split(','))
|
||||
@@ -74,9 +95,15 @@ class ScriptingCommandLineProcessor : CommandLineProcessor {
|
||||
currentCP.addAll(value.split(File.pathSeparatorChar).map(::File))
|
||||
configuration.put(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS_CLASSPATH, currentCP)
|
||||
}
|
||||
DISABLE_STANDARD_SCRIPT_DEFINITION_OPTION -> {
|
||||
configuration.put(
|
||||
JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION,
|
||||
value.takeUnless { it.isBlank() }?.toBoolean() ?: true
|
||||
)
|
||||
}
|
||||
DISABLE_SCRIPT_DEFINITIONS_FROM_CLSSPATH_OPTION -> {
|
||||
configuration.put(
|
||||
ScriptingConfigurationKeys.DISABLE_SCRIPT_DEFINITIONS_FROM_CLSSPATH_OPTION,
|
||||
ScriptingConfigurationKeys.DISABLE_SCRIPT_DEFINITIONS_FROM_CLASSPATH_OPTION,
|
||||
value.takeUnless { it.isBlank() }?.toBoolean() ?: true
|
||||
)
|
||||
}
|
||||
|
||||
+34
-21
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.extensions.CompilerConfigurationExtension
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import org.jetbrains.kotlin.script.StandardScriptDefinition
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
@@ -28,30 +29,39 @@ class ScriptingCompilerConfigurationExtension(val project: MockProject) : Compil
|
||||
|
||||
override fun updateConfiguration(configuration: CompilerConfiguration) {
|
||||
|
||||
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) ?: MessageCollector.NONE
|
||||
val explicitScriptDefinitions = configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS)
|
||||
if (!configuration.getBoolean(ScriptingConfigurationKeys.DISABLE_SCRIPTING_PLUGIN_OPTION)) {
|
||||
|
||||
val scriptDefinitions =
|
||||
if (configuration.getBoolean(ScriptingConfigurationKeys.DISABLE_SCRIPT_DEFINITIONS_FROM_CLSSPATH_OPTION))
|
||||
explicitScriptDefinitions
|
||||
else
|
||||
explicitScriptDefinitions + discoverScriptTemplatesInClasspath(configuration, messageCollector)
|
||||
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) ?: MessageCollector.NONE
|
||||
val explicitScriptDefinitions = configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS)
|
||||
|
||||
if (scriptDefinitions.isNotEmpty()) {
|
||||
val projectRoot = project.run { basePath ?: baseDir?.canonicalPath }?.let(::File)
|
||||
if (projectRoot != null) {
|
||||
configuration.put(
|
||||
ScriptingConfigurationKeys.LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION,
|
||||
"projectRoot",
|
||||
projectRoot
|
||||
val scriptDefinitions =
|
||||
if (configuration.getBoolean(ScriptingConfigurationKeys.DISABLE_SCRIPT_DEFINITIONS_FROM_CLASSPATH_OPTION))
|
||||
explicitScriptDefinitions
|
||||
else
|
||||
explicitScriptDefinitions + discoverScriptTemplatesInClasspath(configuration, messageCollector)
|
||||
|
||||
if (scriptDefinitions.isNotEmpty()) {
|
||||
val projectRoot = project.run { basePath ?: baseDir?.canonicalPath }?.let(::File)
|
||||
if (projectRoot != null) {
|
||||
configuration.put(
|
||||
ScriptingConfigurationKeys.LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION,
|
||||
"projectRoot",
|
||||
projectRoot
|
||||
)
|
||||
}
|
||||
configureScriptDefinitions(
|
||||
scriptDefinitions,
|
||||
configuration,
|
||||
messageCollector,
|
||||
configuration.getMap(ScriptingConfigurationKeys.LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION)
|
||||
)
|
||||
}
|
||||
configureScriptDefinitions(
|
||||
scriptDefinitions,
|
||||
configuration,
|
||||
messageCollector,
|
||||
configuration.getMap(ScriptingConfigurationKeys.LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION)
|
||||
)
|
||||
// If not disabled explicitly, we should always support at least the standard script definition
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
|
||||
!configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).contains(StandardScriptDefinition)
|
||||
) {
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,7 +113,10 @@ private fun discoverScriptTemplatesInClasspath(configuration: CompilerConfigurat
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> messageCollector.report(CompilerMessageSeverity.WARNING, "Configure scripting: Unknown classpath entry $dep")
|
||||
else -> {
|
||||
// assuming that invalid classpath entries will be reported elsewhere anyway, so do not spam user with additional warnings here
|
||||
messageCollector.report(CompilerMessageSeverity.LOGGING, "Configure scripting: Unknown classpath entry $dep")
|
||||
}
|
||||
}
|
||||
}
|
||||
return templates
|
||||
|
||||
Reference in New Issue
Block a user