diff --git a/compiler/daemon/build.gradle.kts b/compiler/daemon/build.gradle.kts index e450b12197a..9c9d15b5102 100644 --- a/compiler/daemon/build.gradle.kts +++ b/compiler/daemon/build.gradle.kts @@ -11,6 +11,7 @@ dependencies { compile(project(":kotlin-build-common")) compile(commonDep("org.fusesource.jansi", "jansi")) compile(commonDep("org.jline", "jline")) + compileOnly(project(":kotlin-scripting-compiler")) compileOnly(intellijCoreDep()) { includeJars("intellij-core") } compileOnly(intellijDep()) { includeIntellijCoreJarDependencies(project) } } diff --git a/compiler/daemon/src/org/jetbrains/kotlin/daemon/KotlinRemoteReplService.kt b/compiler/daemon/src/org/jetbrains/kotlin/daemon/KotlinRemoteReplService.kt index 94b6bb7f567..599f2a0e791 100644 --- a/compiler/daemon/src/org/jetbrains/kotlin/daemon/KotlinRemoteReplService.kt +++ b/compiler/daemon/src/org/jetbrains/kotlin/daemon/KotlinRemoteReplService.kt @@ -24,11 +24,13 @@ import org.jetbrains.kotlin.cli.common.repl.* import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots import org.jetbrains.kotlin.cli.jvm.repl.GenericReplCompiler import org.jetbrains.kotlin.cli.jvm.repl.GenericReplCompilerState +import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.daemon.common.CompileService import org.jetbrains.kotlin.daemon.common.RemoteOperationsTracer import org.jetbrains.kotlin.script.KotlinScriptDefinition import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate +import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar import org.jetbrains.kotlin.utils.PathUtil import java.io.File import java.io.PrintStream @@ -56,6 +58,7 @@ open class KotlinJvmReplService( languageVersionSettings = LanguageVersionSettingsImpl( LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlags.skipMetadataVersionCheck to true) ) + configureScripting() } protected fun makeScriptDefinition(templateClasspath: List, templateClassName: String): KotlinScriptDefinition? { @@ -171,3 +174,20 @@ inline internal fun getValidId(counter: AtomicInteger, check: (Int) -> Boolean): } return newId } + +private fun CompilerConfiguration.configureScripting() { + val error = try { + add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, ScriptingCompilerConfigurationComponentRegistrar()) + null + } catch (e: NoClassDefFoundError) { + e + } catch (e: ClassNotFoundException) { + e + } + if (error != null) { + throw IllegalStateException( + "Unable to use scripting/REPL in the daemon, no kotlin-scripting-compiler.jar or its dependencies are found in the compiler classpath", + error + ) + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt b/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt index 067c4b9c874..db10be507ed 100644 --- a/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt @@ -51,11 +51,21 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() { data class CompilerResults(val resultCode: Int, val out: String) val compilerClassPath = listOf( - File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-compiler.jar")) + File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-compiler.jar") + ) + val scriptingCompilerClassPath = listOf( + File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-scripting-compiler.jar"), + File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-scripting-common.jar"), + File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-scripting-jvm.jar") + ) val daemonClientClassPath = listOf( File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-daemon-client.jar"), File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-compiler.jar")) val compilerId by lazy(LazyThreadSafetyMode.NONE) { CompilerId.makeCompilerId(compilerClassPath) } + val compilerWithScriptingId by lazy(LazyThreadSafetyMode.NONE) { + CompilerId.makeCompilerId(compilerClassPath + scriptingCompilerClassPath) + } + private fun compileOnDaemon(clientAliveFile: File, compilerId: CompilerId, daemonJVMOptions: DaemonJVMOptions, daemonOptions: DaemonOptions, vararg args: String): CompilerResults { val daemon = KotlinCompilerClient.connectToCompileService(compilerId, clientAliveFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true) assertNotNull("failed to connect daemon", daemon) @@ -710,8 +720,30 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() { } } + fun testDaemonReplScriptingNotInClasspathError() { + withDaemon(compilerId) { daemon -> + var repl: KotlinRemoteReplCompilerClient? = null + var isErrorThrown = false + try { + repl = KotlinRemoteReplCompilerClient( + daemon, null, CompileService.TargetPlatform.JVM, emptyArray(), TestMessageCollector(), + classpathFromClassloader(), ScriptWithNoParam::class.qualifiedName!! + ) + } catch (e: Exception) { + TestCase.assertEquals( + "Unable to use scripting/REPL in the daemon, no kotlin-scripting-compiler.jar or its dependencies are found in the compiler classpath", + e.message + ) + isErrorThrown = true + } finally { + repl?.dispose() + } + TestCase.assertTrue("Expecting exception that kotlin-scripting-plugin is not found in the classpath", isErrorThrown) + } + } + fun testDaemonReplLocalEvalNoParams() { - withDaemon { daemon -> + withDaemon(compilerWithScriptingId) { daemon -> val repl = KotlinRemoteReplCompilerClient(daemon, null, CompileService.TargetPlatform.JVM, emptyArray(), TestMessageCollector(), @@ -726,7 +758,7 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() { } fun testDaemonReplLocalEvalStandardTemplate() { - withDaemon { daemon -> + withDaemon(compilerWithScriptingId) { daemon -> val repl = KotlinRemoteReplCompilerClient(daemon, null, CompileService.TargetPlatform.JVM, emptyArray(), TestMessageCollector(), classpathFromClassloader(), @@ -775,7 +807,7 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() { withLogFile("kotlin-daemon-test") { logFile -> val daemonJVMOptions = makeTestDaemonJvmOptions(logFile) - val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true) + val daemon = KotlinCompilerClient.connectToCompileService(compilerWithScriptingId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true) assertNotNull("failed to connect daemon", daemon) val replCompiler = KotlinRemoteReplCompilerClient(daemon!!, null, CompileService.TargetPlatform.JVM, @@ -809,7 +841,7 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() { } } - internal fun withDaemon(body: (CompileService) -> Unit) { + internal fun withDaemon(compilerId: CompilerId = this.compilerId, body: (CompileService) -> Unit) { withFlagFile(getTestName(true), ".alive") { flagFile -> val daemonOptions = makeTestDaemonOptions(getTestName(true)) withLogFile("kotlin-daemon-test") { logFile ->