diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt index a9c0995b1b3..ecf6e127e02 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt @@ -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? by FreezableVar(null) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt index 43f1259d56b..825e56d48a0 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -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() { 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() { 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) } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index c63cadb659f..4120dfd2bb3 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -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 diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java b/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java index 814f139467c..7ff323a2059 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java @@ -49,6 +49,9 @@ public class JVMConfigurationKeys { public static final CompilerConfigurationKey> SCRIPT_DEFINITIONS = CompilerConfigurationKey.create("script definitions"); + public static final CompilerConfigurationKey DISABLE_STANDARD_SCRIPT_DEFINITION = + CompilerConfigurationKey.create("Disable standard kotlin script support"); + public static final CompilerConfigurationKey RETAIN_OUTPUT_IN_MEMORY = CompilerConfigurationKey.create("retain compiled classes in memory for further use, e.g. when running scripts"); diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index f4d76160867..261a80546ec 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -10,6 +10,7 @@ where advanced options include: -Xdump-declarations-to= 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= Paths where to find Java 9+ modules diff --git a/compiler/testData/cli/jvm/wrongScriptWithDirectory.out b/compiler/testData/cli/jvm/wrongScriptWithDirectory.out index a753b1e58f4..820f313eee6 100644 --- a/compiler/testData/cli/jvm/wrongScriptWithDirectory.out +++ b/compiler/testData/cli/jvm/wrongScriptWithDirectory.out @@ -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 diff --git a/compiler/testData/cli/jvm/wrongScriptWithKtSource.out b/compiler/testData/cli/jvm/wrongScriptWithKtSource.out index a753b1e58f4..820f313eee6 100644 --- a/compiler/testData/cli/jvm/wrongScriptWithKtSource.out +++ b/compiler/testData/cli/jvm/wrongScriptWithKtSource.out @@ -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 diff --git a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCommandLineProcessor.kt b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCommandLineProcessor.kt index eb6941c6351..c328f994769 100644 --- a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCommandLineProcessor.kt +++ b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCommandLineProcessor.kt @@ -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 = + CompilerConfigurationKey.create("Disable scripting plugin") + val SCRIPT_DEFINITIONS: CompilerConfigurationKey> = CompilerConfigurationKey.create("Script definition classes") val SCRIPT_DEFINITIONS_CLASSPATH: CompilerConfigurationKey> = CompilerConfigurationKey.create("Additional classpath for the script definitions") - val DISABLE_SCRIPT_DEFINITIONS_FROM_CLSSPATH_OPTION: CompilerConfigurationKey = + val DISABLE_SCRIPT_DEFINITIONS_FROM_CLASSPATH_OPTION: CompilerConfigurationKey = CompilerConfigurationKey.create("Do not extract script definitions from the compilation classpath") val LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION: CompilerConfigurationKey> = @@ -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", "", "Script definition classes", required = false, allowMultipleOccurrences = true @@ -36,6 +44,10 @@ class ScriptingCommandLineProcessor : CommandLineProcessor { "script-definitions-classpath", "", "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 ) } diff --git a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt index 8d8d1f6d9d1..7421d70d98b 100644 --- a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt +++ b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt @@ -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