[CLI] add support running scripts in js compiler, extract common code with jvm part
This commit is contained in:
committed by
romanart
parent
50c08b25d3
commit
f59e393e37
+6
@@ -76,6 +76,9 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
|
||||
)
|
||||
var progressiveMode by FreezableVar(false)
|
||||
|
||||
@Argument(value = "-script", description = "Evaluate the script file")
|
||||
var script: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(value = "-P", valueDescription = PLUGIN_OPTION_FORMAT, description = "Pass an option to a plugin")
|
||||
var pluginOptions: Array<String>? by FreezableVar(null)
|
||||
|
||||
@@ -304,6 +307,9 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
|
||||
)
|
||||
var useFir: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(value = "-Xdisable-default-scripting-plugin", description = "Do not enable scripting plugin by default")
|
||||
var disableDefaultScriptingPlugin: Boolean by FreezableVar(false)
|
||||
|
||||
open fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
|
||||
return HashMap<AnalysisFlag<*>, Any>().apply {
|
||||
put(AnalysisFlags.skipMetadataVersionCheck, skipMetadataVersionCheck)
|
||||
|
||||
+3
@@ -137,4 +137,7 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
|
||||
|
||||
@Argument(value = "-Xmetadata-only", description = "Generate *.meta.js and *.kjsm files only")
|
||||
var metadataOnly: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(value = "-Xenable-js-scripting", description = "Enable experimental support of .kts files using K/JS (with -Xir only)")
|
||||
var enableJsScripting: Boolean by FreezableVar(false)
|
||||
}
|
||||
|
||||
-6
@@ -45,9 +45,6 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value = "-no-reflect", description = "Don't include kotlin-reflect.jar into classpath")
|
||||
var noReflect: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(value = "-script", description = "Evaluate the script file")
|
||||
var script: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(
|
||||
value = "-script-templates",
|
||||
valueDescription = "<fully qualified class name[,]>",
|
||||
@@ -254,9 +251,6 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
)
|
||||
var jvmDefault: String by FreezableVar(JvmDefaultMode.DEFAULT.description)
|
||||
|
||||
@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)
|
||||
|
||||
|
||||
@@ -95,6 +95,9 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
|
||||
return irCompiler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addPlatformOptions(@NotNull List<String> $self, @NotNull K2JSCompilerArguments arguments) {}
|
||||
|
||||
static {
|
||||
moduleKindMap.put(K2JsArgumentConstants.MODULE_PLAIN, ModuleKind.PLAIN);
|
||||
moduleKindMap.put(K2JsArgumentConstants.MODULE_COMMONJS, ModuleKind.COMMON_JS);
|
||||
@@ -195,8 +198,7 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
|
||||
return COMPILATION_ERROR;
|
||||
}
|
||||
|
||||
ExitCode pluginLoadResult =
|
||||
PluginCliParser.loadPluginsSafe(arguments.getPluginClasspaths(), arguments.getPluginOptions(), configuration);
|
||||
ExitCode pluginLoadResult = loadPlugins(paths, arguments, configuration);
|
||||
if (pluginLoadResult != ExitCode.OK) return pluginLoadResult;
|
||||
|
||||
configuration.put(JSConfigurationKeys.LIBRARIES, configureLibraries(arguments, paths, messageCollector));
|
||||
|
||||
@@ -9,11 +9,11 @@ import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.cli.common.*
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode.OK
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode.*
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants
|
||||
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.extensions.ScriptEvaluationExtension
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
|
||||
import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.util.Logger
|
||||
import org.jetbrains.kotlin.utils.JsMetadataVersion
|
||||
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import org.jetbrains.kotlin.utils.join
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
@@ -70,6 +71,33 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
): ExitCode {
|
||||
val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
|
||||
val pluginLoadResult = loadPlugins(paths, arguments, configuration)
|
||||
if (pluginLoadResult != ExitCode.OK) return pluginLoadResult
|
||||
|
||||
//TODO: add to configuration everything that may come in handy at script compiler and use it there
|
||||
if (arguments.script) {
|
||||
|
||||
if (!arguments.enableJsScripting) {
|
||||
messageCollector.report(ERROR, "Script for K/JS should be enabled explicitly, see -Xenable-js-scripting")
|
||||
return COMPILATION_ERROR
|
||||
}
|
||||
|
||||
configuration.put(CommonConfigurationKeys.MODULE_NAME, "repl.kts")
|
||||
|
||||
val environment = KotlinCoreEnvironment.getOrCreateApplicationEnvironmentForProduction(rootDisposable, configuration)
|
||||
val projectEnv = KotlinCoreEnvironment.ProjectEnvironment(rootDisposable, environment)
|
||||
projectEnv.registerExtensionsFromPlugins(configuration)
|
||||
|
||||
val scriptingEvaluators = ScriptEvaluationExtension.getInstances(projectEnv.project)
|
||||
val scriptingEvaluator = scriptingEvaluators.find { it.isAccepted(arguments) }
|
||||
if (scriptingEvaluator == null) {
|
||||
messageCollector.report(ERROR, "Unable to evaluate script, no scripting plugin loaded")
|
||||
return COMPILATION_ERROR
|
||||
}
|
||||
|
||||
return scriptingEvaluator.eval(arguments, configuration, projectEnv)
|
||||
}
|
||||
|
||||
if (arguments.freeArgs.isEmpty() && !IncrementalCompilation.isEnabledForJs()) {
|
||||
if (arguments.version) {
|
||||
return OK
|
||||
@@ -78,13 +106,6 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
return COMPILATION_ERROR
|
||||
}
|
||||
|
||||
val pluginLoadResult = PluginCliParser.loadPluginsSafe(
|
||||
arguments.pluginClasspaths,
|
||||
arguments.pluginOptions,
|
||||
configuration
|
||||
)
|
||||
if (pluginLoadResult != OK) return pluginLoadResult
|
||||
|
||||
val libraries: List<String> = configureLibraries(arguments.libraries)
|
||||
val friendLibraries: List<String> = configureLibraries(arguments.friendModules)
|
||||
|
||||
@@ -99,11 +120,11 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
|
||||
val environmentForJS =
|
||||
KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JS_CONFIG_FILES)
|
||||
|
||||
val project = environmentForJS.project
|
||||
val projectJs = environmentForJS.project
|
||||
val configurationJs = environmentForJS.configuration
|
||||
val sourcesFiles = environmentForJS.getSourceFiles()
|
||||
|
||||
environmentForJS.configuration.put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, arguments.allowKotlinPackage)
|
||||
configurationJs.put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, arguments.allowKotlinPackage)
|
||||
|
||||
if (!checkKotlinPackageUsage(environmentForJS, sourcesFiles)) return ExitCode.COMPILATION_ERROR
|
||||
|
||||
@@ -128,9 +149,11 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
|
||||
val outputFile = File(outputFilePath)
|
||||
|
||||
configuration.put(CommonConfigurationKeys.MODULE_NAME, FileUtil.getNameWithoutExtension(outputFile))
|
||||
configurationJs.put(CommonConfigurationKeys.MODULE_NAME, FileUtil.getNameWithoutExtension(outputFile))
|
||||
|
||||
val config = JsConfig(project, configuration)
|
||||
// TODO: in this method at least 3 different compiler configurations are used (original, env.configuration, jsConfig.configuration)
|
||||
// Such situation seems a bit buggy...
|
||||
val config = JsConfig(projectJs, configurationJs)
|
||||
val outputDir: File = outputFile.parentFile ?: outputFile.absoluteFile.parentFile!!
|
||||
try {
|
||||
config.configuration.put(JSConfigurationKeys.OUTPUT_DIR, outputDir.canonicalFile)
|
||||
@@ -179,9 +202,9 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
val phaseConfig = createPhaseConfig(jsPhases, arguments, messageCollector)
|
||||
|
||||
val compiledModule = compile(
|
||||
project,
|
||||
projectJs,
|
||||
sourcesFiles,
|
||||
configuration,
|
||||
config.configuration,
|
||||
phaseConfig,
|
||||
allDependencies = resolvedLibraries,
|
||||
friendDependencies = friendDependencies,
|
||||
@@ -293,6 +316,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
return JsMetadataVersion(*versionArray)
|
||||
}
|
||||
|
||||
override fun MutableList<String>.addPlatformOptions(arguments: K2JSCompilerArguments) {}
|
||||
|
||||
companion object {
|
||||
private val moduleKindMap = mapOf(
|
||||
K2JsArgumentConstants.MODULE_PLAIN to ModuleKind.PLAIN,
|
||||
@@ -349,4 +374,15 @@ fun messageCollectorLogger(collector: MessageCollector) = object : Logger {
|
||||
(collector as? GroupingMessageCollector)?.flush()
|
||||
kotlin.error(message)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadPluginsForTests(configuration: CompilerConfiguration): ExitCode {
|
||||
var pluginClasspaths: Iterable<String> = emptyList()
|
||||
val kotlinPaths = PathUtil.kotlinPathsForCompiler
|
||||
val libPath = kotlinPaths.libPath.takeIf { it.exists() && it.isDirectory } ?: File(".")
|
||||
val (jars, _) =
|
||||
PathUtil.KOTLIN_SCRIPTING_PLUGIN_CLASSPATH_JARS.mapNotNull { File(libPath, it) }.partition { it.exists() }
|
||||
pluginClasspaths = jars.map { it.canonicalPath } + pluginClasspaths
|
||||
|
||||
return PluginCliParser.loadPluginsSafe(pluginClasspaths, mutableListOf(), configuration)
|
||||
}
|
||||
@@ -24,11 +24,10 @@ import org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode.INTERNAL_ERROR
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
|
||||
import org.jetbrains.kotlin.cli.common.messages.*
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.INFO
|
||||
import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
|
||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
@@ -36,8 +35,10 @@ import org.jetbrains.kotlin.progress.CompilationCanceledException
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import java.util.ArrayList
|
||||
|
||||
abstract class CLICompiler<A : CommonCompilerArguments> : CLITool<A>() {
|
||||
|
||||
@@ -134,5 +135,51 @@ abstract class CLICompiler<A : CommonCompilerArguments> : CLITool<A>() {
|
||||
rootDisposable: Disposable,
|
||||
paths: KotlinPaths?
|
||||
): ExitCode
|
||||
|
||||
protected abstract fun MutableList<String>.addPlatformOptions(arguments: A)
|
||||
|
||||
protected fun loadPlugins(paths: KotlinPaths?, arguments: A, configuration: CompilerConfiguration): ExitCode {
|
||||
var pluginClasspaths: Iterable<String> = arguments.pluginClasspaths?.asIterable() ?: emptyList()
|
||||
val pluginOptions = arguments.pluginOptions?.toMutableList() ?: ArrayList()
|
||||
|
||||
if (!arguments.disableDefaultScriptingPlugin) {
|
||||
val explicitOrLoadedScriptingPlugin =
|
||||
pluginClasspaths.any { File(it).name.startsWith(PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_NAME) } ||
|
||||
tryLoadScriptingPluginFromCurrentClassLoader(configuration)
|
||||
if (!explicitOrLoadedScriptingPlugin) {
|
||||
val kotlinPaths = paths ?: PathUtil.kotlinPathsForCompiler
|
||||
val libPath = kotlinPaths.libPath.takeIf { it.exists() && it.isDirectory } ?: File(".")
|
||||
val (jars, missingJars) =
|
||||
PathUtil.KOTLIN_SCRIPTING_PLUGIN_CLASSPATH_JARS.map { File(libPath, it) }.partition { it.exists() }
|
||||
if (missingJars.isEmpty()) {
|
||||
pluginClasspaths = jars.map { it.canonicalPath } + pluginClasspaths
|
||||
} else {
|
||||
val messageCollector = configuration.getNotNull(MESSAGE_COLLECTOR_KEY)
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.LOGGING,
|
||||
"Scripting plugin will not be loaded: not all required jars are present in the classpath (missing files: $missingJars)"
|
||||
)
|
||||
}
|
||||
}
|
||||
pluginOptions.addPlatformOptions(arguments)
|
||||
} else {
|
||||
pluginOptions.add("plugin:kotlin.scripting:disable=true")
|
||||
}
|
||||
return PluginCliParser.loadPluginsSafe(pluginClasspaths, pluginOptions, configuration)
|
||||
}
|
||||
|
||||
private fun tryLoadScriptingPluginFromCurrentClassLoader(configuration: CompilerConfiguration): Boolean = try {
|
||||
val pluginRegistrarClass = PluginCliParser::class.java.classLoader.loadClass(
|
||||
"org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar"
|
||||
)
|
||||
val pluginRegistrar = pluginRegistrarClass.newInstance() as? ComponentRegistrar
|
||||
if (pluginRegistrar != null) {
|
||||
configuration.add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, pluginRegistrar)
|
||||
true
|
||||
} else false
|
||||
} catch (_: Throwable) {
|
||||
// TODO: add finer error processing and logging
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -198,59 +198,17 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadPlugins(paths: KotlinPaths?, arguments: K2JVMCompilerArguments, configuration: CompilerConfiguration): ExitCode {
|
||||
var pluginClasspaths: Iterable<String> = arguments.pluginClasspaths?.asIterable() ?: emptyList()
|
||||
val pluginOptions = arguments.pluginOptions?.toMutableList() ?: ArrayList()
|
||||
|
||||
if (!arguments.disableDefaultScriptingPlugin) {
|
||||
val explicitOrLoadedScriptingPlugin =
|
||||
pluginClasspaths.any { File(it).name.startsWith(PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_NAME) } ||
|
||||
tryLoadScriptingPluginFromCurrentClassLoader(configuration)
|
||||
// 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 kotlinPaths = paths ?: PathUtil.kotlinPathsForCompiler
|
||||
val libPath = kotlinPaths.libPath.takeIf { it.exists() && it.isDirectory } ?: File(".")
|
||||
val (jars, missingJars) =
|
||||
PathUtil.KOTLIN_SCRIPTING_PLUGIN_CLASSPATH_JARS.mapNotNull { File(libPath, it) }.partition { it.exists() }
|
||||
if (missingJars.isEmpty()) {
|
||||
pluginClasspaths = jars.map { it.canonicalPath } + pluginClasspaths
|
||||
} else {
|
||||
val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
messageCollector.report(
|
||||
LOGGING,
|
||||
"Scripting plugin will not be loaded: not all required jars are present in the classpath (missing files: $missingJars)"
|
||||
)
|
||||
}
|
||||
}
|
||||
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")
|
||||
override fun MutableList<String>.addPlatformOptions(arguments: K2JVMCompilerArguments) {
|
||||
if (arguments.scriptTemplates?.isNotEmpty() == true) {
|
||||
add("plugin:kotlin.scripting:script-templates=${arguments.scriptTemplates!!.joinToString(",")}")
|
||||
}
|
||||
if (arguments.scriptResolverEnvironment?.isNotEmpty() == true) {
|
||||
add(
|
||||
"plugin:kotlin.scripting:script-resolver-environment=${arguments.scriptResolverEnvironment!!.joinToString(
|
||||
","
|
||||
)}"
|
||||
)
|
||||
}
|
||||
return PluginCliParser.loadPluginsSafe(pluginClasspaths, pluginOptions, configuration)
|
||||
}
|
||||
|
||||
private fun tryLoadScriptingPluginFromCurrentClassLoader(configuration: CompilerConfiguration): Boolean = try {
|
||||
val pluginRegistrarClass = PluginCliParser::class.java.classLoader.loadClass(
|
||||
"org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar"
|
||||
)
|
||||
val pluginRegistrar = pluginRegistrarClass.newInstance() as? ComponentRegistrar
|
||||
if (pluginRegistrar != null) {
|
||||
configuration.add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, pluginRegistrar)
|
||||
true
|
||||
} else false
|
||||
} catch (_: Throwable) {
|
||||
// TODO: add finer error processing and logging
|
||||
false
|
||||
}
|
||||
|
||||
private fun createCoreEnvironment(
|
||||
|
||||
@@ -49,6 +49,8 @@ class K2MetadataCompiler : CLICompiler<K2MetadataCompilerArguments>() {
|
||||
// No specific arguments yet
|
||||
}
|
||||
|
||||
override fun MutableList<String>.addPlatformOptions(arguments: K2MetadataCompilerArguments) {}
|
||||
|
||||
override fun doExecute(
|
||||
arguments: K2MetadataCompilerArguments,
|
||||
configuration: CompilerConfiguration,
|
||||
@@ -57,7 +59,7 @@ class K2MetadataCompiler : CLICompiler<K2MetadataCompilerArguments>() {
|
||||
): ExitCode {
|
||||
val collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
|
||||
val pluginLoadResult = PluginCliParser.loadPluginsSafe(arguments.pluginClasspaths, arguments.pluginOptions, configuration)
|
||||
val pluginLoadResult = loadPlugins(paths, arguments, configuration)
|
||||
if (pluginLoadResult != ExitCode.OK) return pluginLoadResult
|
||||
|
||||
for (arg in arguments.freeArgs) {
|
||||
|
||||
Reference in New Issue
Block a user