Implement simple "add to compilation" functionality for scripts
(incomplete import - scripts added to the compilation but not yet imported into scope) Base functionality needed for #KT-27960
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripts
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.daemon.TestMessageCollector
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.compiler.plugin.KotlinScriptDefinitionAdapterFromNewAPI
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.FileScriptSource
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
import kotlin.script.experimental.host.configurationDependencies
|
||||
import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate
|
||||
import kotlin.script.experimental.jvm.JvmDependency
|
||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.dependenciesFromCurrentContext
|
||||
import kotlin.script.experimental.jvm.jvm
|
||||
|
||||
private const val testDataPath = "compiler/testData/script/"
|
||||
|
||||
class ScriptCliCompilationTest : KtUsefulTestCase() {
|
||||
|
||||
@Test
|
||||
fun testPrerequisites() {
|
||||
Assert.assertTrue(thisClasspath.isNotEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSimpleScript() {
|
||||
val out = checkRun("hello.kts")
|
||||
Assert.assertEquals("Hello from basic script!", out)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSimpleScriptWithArgs() {
|
||||
val out = checkRun("hello_args.kts", listOf("kotlin"))
|
||||
Assert.assertEquals("Hello, kotlin!", out)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testScriptWithRequire() {
|
||||
val out = checkRun("hello.req1.kts", scriptDef = TestScriptWithRequire::class)
|
||||
Assert.assertEquals("Hello from required!", out)
|
||||
}
|
||||
|
||||
|
||||
private val thisClasspath = listOf(PathUtil.getResourcePathForClass(ScriptCliCompilationTest::class.java))
|
||||
|
||||
private fun runCompiler(
|
||||
script: File,
|
||||
args: List<String> = emptyList(),
|
||||
scriptDef: KClass<*>? = null,
|
||||
classpath: List<File> = emptyList()
|
||||
): Pair<ExitCode, MessageCollector> {
|
||||
|
||||
val collector = TestMessageCollector()
|
||||
|
||||
val configuration = KotlinTestUtils.newConfiguration(ConfigurationKind.NO_KOTLIN_REFLECT, TestJdkKind.FULL_JDK).apply {
|
||||
put(MESSAGE_COLLECTOR_KEY, collector)
|
||||
addKotlinSourceRoot(script.path)
|
||||
if (scriptDef != null) {
|
||||
val hostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) {
|
||||
configurationDependencies(JvmDependency(classpath))
|
||||
}
|
||||
val scriptDefinition = KotlinScriptDefinitionAdapterFromNewAPI(
|
||||
createCompilationConfigurationFromTemplate(
|
||||
KotlinType(scriptDef),
|
||||
hostConfiguration, KotlinScriptDefinition::class
|
||||
),
|
||||
hostConfiguration
|
||||
)
|
||||
add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition)
|
||||
}
|
||||
}
|
||||
|
||||
val environment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||
|
||||
return KotlinToJVMBytecodeCompiler.compileAndExecuteScript(environment, args) to collector
|
||||
}
|
||||
|
||||
private fun checkRun(
|
||||
scriptFileName: String,
|
||||
args: List<String> = emptyList(),
|
||||
scriptDef: KClass<*>? = null,
|
||||
classpath: List<File> = emptyList()
|
||||
): String =
|
||||
captureOut {
|
||||
val res = runCompiler(File(testDataPath, scriptFileName), args, scriptDef, classpath)
|
||||
val resMessage = lazy {
|
||||
"Compilation results:\n" + res.second.toString()
|
||||
}
|
||||
Assert.assertEquals(resMessage.value, ExitCode.OK, res.first)
|
||||
Assert.assertFalse(resMessage.value, res.second.hasErrors())
|
||||
}
|
||||
}
|
||||
|
||||
@KotlinScript(
|
||||
fileExtension = "req1.kts",
|
||||
compilationConfiguration = TestScriptWithRequireConfiguration::class
|
||||
)
|
||||
abstract class TestScriptWithRequire
|
||||
|
||||
object TestScriptWithRequireConfiguration : ScriptCompilationConfiguration(
|
||||
{
|
||||
defaultImports(Import::class)
|
||||
jvm {
|
||||
dependenciesFromCurrentContext(wholeClasspath = true)
|
||||
}
|
||||
refineConfiguration {
|
||||
onAnnotations(Import::class) { context: ScriptConfigurationRefinementContext ->
|
||||
val sources = context.collectedData?.get(ScriptCollectedData.foundAnnotations)
|
||||
?.flatMap {
|
||||
(it as? Import)?.sources?.map { sourceName -> FileScriptSource(File(testDataPath, sourceName)) } ?: emptyList()
|
||||
}
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?: return@onAnnotations context.compilationConfiguration.asSuccess()
|
||||
ScriptCompilationConfiguration(context.compilationConfiguration) {
|
||||
importScripts.append(sources)
|
||||
}.asSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@Target(AnnotationTarget.FILE)
|
||||
@Repeatable
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class Import(vararg val sources: String)
|
||||
Reference in New Issue
Block a user