Implement base jvm scripting infrastructure
This commit is contained in:
@@ -0,0 +1 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.Coroutines
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2000-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 kotlin.script.experimental.jvm.impl
|
||||
|
||||
import kotlinx.coroutines.experimental.runBlocking
|
||||
import java.io.File
|
||||
import kotlin.script.dependencies.Environment
|
||||
import kotlin.script.dependencies.ScriptContents
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
import kotlin.script.experimental.dependencies.ScriptReport
|
||||
import kotlin.script.experimental.host.toScriptSource
|
||||
import kotlin.script.experimental.jvm.JvmDependency
|
||||
import kotlin.script.experimental.jvm.defaultConfiguration
|
||||
import kotlin.script.experimental.jvm.mapToLegacyScriptReportPosition
|
||||
import kotlin.script.experimental.jvm.mapToLegacyScriptReportSeverity
|
||||
|
||||
class BridgeDependenciesResolver(
|
||||
val scriptConfigurator: ScriptConfigurator?,
|
||||
val baseScriptCompilerConfiguration: ScriptCompileConfiguration = scriptConfigurator.defaultConfiguration,
|
||||
val onClasspathUpdated: (List<File>) -> Unit = {}
|
||||
) : AsyncDependenciesResolver {
|
||||
|
||||
override fun resolve(scriptContents: ScriptContents, environment: Environment): DependenciesResolver.ResolveResult =
|
||||
runBlocking {
|
||||
resolveAsync(scriptContents, environment)
|
||||
}
|
||||
|
||||
override suspend fun resolveAsync(scriptContents: ScriptContents, environment: Environment): DependenciesResolver.ResolveResult {
|
||||
return try {
|
||||
|
||||
val diagnostics = arrayListOf<ScriptReport>()
|
||||
val processedScriptData =
|
||||
ProcessedScriptData(ProcessedScriptDataParams.annotations to scriptContents.annotations)
|
||||
|
||||
val scriptCompilerConfiguration = baseScriptCompilerConfiguration.cloneWith(
|
||||
ScriptCompileConfigurationParams.scriptSourceFragments to scriptContents.toScriptSourceFragments()
|
||||
)
|
||||
|
||||
val refinedConfiguration = scriptConfigurator?.let {
|
||||
val res = scriptConfigurator.refineConfiguration(scriptCompilerConfiguration, processedScriptData)
|
||||
when (res) {
|
||||
is ResultWithDiagnostics.Failure ->
|
||||
return@resolveAsync DependenciesResolver.ResolveResult.Failure(res.reports.mapScriptReportsToDiagnostics())
|
||||
is ResultWithDiagnostics.Success -> {
|
||||
diagnostics.addAll(res.reports.mapScriptReportsToDiagnostics())
|
||||
res.value
|
||||
}
|
||||
}
|
||||
} ?: scriptCompilerConfiguration
|
||||
|
||||
val newClasspath = refinedConfiguration.getOrNull(ScriptCompileConfigurationParams.dependencies)
|
||||
?.flatMap { (it as JvmDependency).classpath } ?: emptyList()
|
||||
if (refinedConfiguration != scriptCompilerConfiguration) {
|
||||
val oldClasspath = scriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationParams.dependencies)
|
||||
?.flatMap { (it as JvmDependency).classpath } ?: emptyList()
|
||||
if (newClasspath != oldClasspath) {
|
||||
onClasspathUpdated(newClasspath)
|
||||
}
|
||||
}
|
||||
DependenciesResolver.ResolveResult.Success(
|
||||
ScriptDependencies(
|
||||
classpath = newClasspath, // TODO: maybe it should return only increment from the initial config
|
||||
imports = refinedConfiguration.getOrNull(ScriptCompileConfigurationParams.importedPackages)?.toList()
|
||||
?: emptyList()
|
||||
),
|
||||
diagnostics
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
DependenciesResolver.ResolveResult.Failure(
|
||||
ScriptReport(
|
||||
e.message ?: "unknown error $e"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun List<ScriptDiagnostic>.mapScriptReportsToDiagnostics() =
|
||||
map { ScriptReport(it.message, mapToLegacyScriptReportSeverity(it.severity), mapToLegacyScriptReportPosition(it.location)) }
|
||||
|
||||
internal fun ScriptContents.toScriptSourceFragments(): ScriptSourceFragments =
|
||||
ScriptSourceFragments(
|
||||
when {
|
||||
text != null -> text!!.toString().toScriptSource()
|
||||
file != null -> file!!.toScriptSource()
|
||||
else -> throw IllegalArgumentException("Unable to convert script contents $this into script source")
|
||||
},
|
||||
null
|
||||
)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2000-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.
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package kotlin.script.experimental.jvm
|
||||
|
||||
import kotlin.script.experimental.api.*
|
||||
|
||||
open class JvmScriptCompiler(
|
||||
val compilerProxy: KJVMCompilerProxy,
|
||||
val cache: CompiledJvmScriptsCache
|
||||
) : ScriptCompiler {
|
||||
|
||||
override suspend fun compile(configuration: ScriptCompileConfiguration, configurator: ScriptConfigurator?): ResultWithDiagnostics<CompiledScript<*>> {
|
||||
val refinedConfiguration = configurator?.refineConfiguration(configuration)?.let {
|
||||
when (it) {
|
||||
is ResultWithDiagnostics.Failure -> return it
|
||||
is ResultWithDiagnostics.Success -> it.value
|
||||
?: return ResultWithDiagnostics.Failure("Null script compile configuration received".asErrorDiagnostics())
|
||||
}
|
||||
} ?: configuration
|
||||
val cached = cache[refinedConfiguration[ScriptCompileConfigurationParams.scriptSourceFragments]]
|
||||
|
||||
if (cached != null) return cached.asSuccess()
|
||||
|
||||
return compilerProxy.compile(refinedConfiguration, configurator).also {
|
||||
if (it is ResultWithDiagnostics.Success) {
|
||||
cache.store(it.value as CompiledScript<*>)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface CompiledJvmScriptsCache {
|
||||
operator fun get(script: ScriptSourceFragments): CompiledScript<*>?
|
||||
fun store(compiledScript: CompiledScript<*>)
|
||||
}
|
||||
|
||||
interface KJVMCompilerProxy {
|
||||
fun compile(
|
||||
scriptCompilerConfiguration: ScriptCompileConfiguration,
|
||||
configurator: ScriptConfigurator?
|
||||
): ResultWithDiagnostics<CompiledScript<*>>
|
||||
}
|
||||
|
||||
class DummyCompiledJvmScriptCache : CompiledJvmScriptsCache {
|
||||
override operator fun get(script: ScriptSourceFragments): CompiledScript<*>? = null
|
||||
override fun store(compiledScript: CompiledScript<*>) {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2000-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 kotlin.script.experimental.jvm
|
||||
|
||||
import kotlinx.coroutines.experimental.runBlocking
|
||||
import kotlin.script.experimental.api.*
|
||||
import java.io.File
|
||||
|
||||
fun jvmConfigWithJavaHome(vararg params: Pair<TypedKey<*>, Any?>): ScriptCompileConfiguration =
|
||||
ScriptCompileConfiguration(
|
||||
JvmScriptCompileConfigurationParams.javaHomeDir to File(System.getProperty("java.home")),
|
||||
*params
|
||||
)
|
||||
|
||||
val ScriptConfigurator?.defaultConfiguration: ScriptCompileConfiguration
|
||||
get() = this?.let { runBlocking { baseConfiguration(null) } }?.resultOrNull() ?: ScriptCompileConfiguration()
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2000-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 kotlin.script.experimental.jvm
|
||||
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.api.ScriptDependency
|
||||
import kotlin.script.experimental.api.TypedKey
|
||||
|
||||
object JvmScriptCompileConfigurationParams {
|
||||
|
||||
val javaHomeDir = TypedKey<File>("javaHomeDir")
|
||||
}
|
||||
|
||||
class JvmDependency(val classpath: Iterable<File>): ScriptDependency
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2000-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.
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package kotlin.script.experimental.jvm
|
||||
|
||||
import kotlin.script.experimental.api.ScriptConfigurator
|
||||
import kotlin.script.experimental.api.ScriptRunner
|
||||
import kotlin.script.experimental.api.typedKey
|
||||
import kotlin.script.experimental.host.BasicScriptingHost
|
||||
|
||||
open class JvmBasicScriptingHost<ScriptBase : Any>(
|
||||
configurationExtractor: ScriptConfigurator,
|
||||
compiler: JvmScriptCompiler,
|
||||
runner: ScriptRunner<ScriptBase>
|
||||
) : BasicScriptingHost<ScriptBase>(configurationExtractor, compiler, runner)
|
||||
|
||||
object JvmScriptEvaluationEnvironmentParams {
|
||||
val baseClassLoader by typedKey<ClassLoader?>()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2000-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.
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package kotlin.script.experimental.jvm
|
||||
|
||||
import kotlin.script.experimental.api.ScriptDiagnostic
|
||||
import kotlin.script.experimental.api.ScriptSource
|
||||
import kotlin.script.dependencies.ScriptContents
|
||||
import kotlin.script.dependencies.ScriptDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.ScriptReport
|
||||
|
||||
fun mapLegacyDiagnosticSeverity(severity: ScriptDependenciesResolver.ReportSeverity): ScriptDiagnostic.Severity = when (severity) {
|
||||
ScriptDependenciesResolver.ReportSeverity.ERROR -> ScriptDiagnostic.Severity.ERROR
|
||||
ScriptDependenciesResolver.ReportSeverity.WARNING -> ScriptDiagnostic.Severity.WARNING
|
||||
ScriptDependenciesResolver.ReportSeverity.INFO -> ScriptDiagnostic.Severity.INFO
|
||||
ScriptDependenciesResolver.ReportSeverity.DEBUG -> ScriptDiagnostic.Severity.DEBUG
|
||||
}
|
||||
|
||||
fun mapToLegacyScriptReportSeverity(severity: ScriptDiagnostic.Severity): ScriptReport.Severity = when (severity) {
|
||||
ScriptDiagnostic.Severity.ERROR -> ScriptReport.Severity.ERROR
|
||||
ScriptDiagnostic.Severity.WARNING -> ScriptReport.Severity.WARNING
|
||||
ScriptDiagnostic.Severity.INFO -> ScriptReport.Severity.INFO
|
||||
ScriptDiagnostic.Severity.DEBUG -> ScriptReport.Severity.DEBUG
|
||||
}
|
||||
|
||||
fun mapLegacyScriptPosition(pos: ScriptContents.Position?): ScriptSource.Location? =
|
||||
pos?.let { ScriptSource.Location(ScriptSource.Position(pos.line, pos.col)) }
|
||||
|
||||
fun mapToLegacyScriptReportPosition(pos: ScriptSource.Location?): ScriptReport.Position? =
|
||||
pos?.let { ScriptReport.Position(pos.start.line, pos.start.col) }
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2000-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 kotlin.script.experimental.jvm.runners
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.script.experimental.api.*
|
||||
|
||||
open class BasicJvmScriptRunner<ScriptBase : Any>(val baseClass: KClass<ScriptBase>? = null) : ScriptRunner<ScriptBase> {
|
||||
|
||||
override suspend fun run(
|
||||
compiledScript: CompiledScript<ScriptBase>,
|
||||
scriptEvaluationEnvironment: ScriptEvaluationEnvironment
|
||||
): ResultWithDiagnostics<EvaluationResult> =
|
||||
try {
|
||||
val obj = compiledScript.instantiate(scriptEvaluationEnvironment)
|
||||
when (obj) {
|
||||
is ResultWithDiagnostics.Failure -> obj
|
||||
is ResultWithDiagnostics.Success -> {
|
||||
// in the future, when (if) we'll stop to compile everything into constructor
|
||||
// run as SAM
|
||||
// return res
|
||||
val scriptObject = obj.value
|
||||
if (scriptObject !is Class<*>)
|
||||
ResultWithDiagnostics.Failure(ScriptDiagnostic("expecting class in this implementation, got ${scriptObject?.javaClass}"))
|
||||
else {
|
||||
scriptObject.getConstructor().newInstance()
|
||||
|
||||
ResultWithDiagnostics.Success(EvaluationResult(null, scriptEvaluationEnvironment))
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
ResultWithDiagnostics.Failure(e.asDiagnostics())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user