Refactor script definitions and resolving/refining infrastructure:

- implement wrappers to wrap old and new API providers and resolvers
- make old API deprecated (with error where possible)
- drop old internal classes related to the old API
- refactor usages accordingly
- fix and add missing features to the scripting API where necessary
This commit is contained in:
Ilya Chernikov
2019-05-12 22:26:37 +02:00
parent e5054f9648
commit e542c9ea84
94 changed files with 1554 additions and 764 deletions
@@ -40,7 +40,7 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator {
?.onFailure {
return@invoke ResultWithDiagnostics.Failure(it.reports)
}
?.resultOrNull()
?.valueOrNull()
?: configuration
val instance =
@@ -48,8 +48,13 @@ fun mapLegacyScriptPosition(pos: ScriptReport.Position?): SourceCode.Location? =
}
fun mapToLegacyScriptReportPosition(pos: SourceCode.Location?): ScriptReport.Position? =
pos?.let { ScriptReport.Position(pos.start.line, pos.start.col) }
pos?.let { ScriptReport.Position(pos.start.line, pos.start.col, pos.end?.line, pos.end?.col) }
fun Iterable<ScriptReport>.mapToDiagnostics(): List<ScriptDiagnostic> = map { (message, severity, position: ScriptReport.Position?) ->
fun Iterable<ScriptReport>.mapToDiagnostics(): List<ScriptDiagnostic> = map { (message, severity, position) ->
ScriptDiagnostic(message, mapLegacyDiagnosticSeverity(severity), null, mapLegacyScriptPosition(position))
}
fun Iterable<ScriptDiagnostic>.mapToLegacyReports(): List<ScriptReport> = map { (message, severity, _, location, exception) ->
val reportMessage = if (exception == null) message else "$message ($exception)"
ScriptReport(reportMessage, mapToLegacyScriptReportSeverity(severity), mapToLegacyScriptReportPosition(location))
}
@@ -41,16 +41,6 @@ class BridgeDependenciesResolver(
)
)
val defaultImports = scriptCompilationConfiguration[ScriptCompilationConfiguration.defaultImports]?.toList() ?: emptyList()
fun ScriptCompilationConfiguration.toDependencies(classpath: List<File>): ScriptDependencies =
ScriptDependencies(
classpath = classpath,
sources = this[ScriptCompilationConfiguration.ide.dependenciesSources].toClassPathOrEmpty(),
imports = defaultImports,
scripts = this[ScriptCompilationConfiguration.importScripts].toFilesOrEmpty()
)
val script = getScriptSource(scriptContents) ?: scriptContents.toScriptSource()
val refineResults = scriptCompilationConfiguration.refineWith(
@@ -92,6 +82,17 @@ class BridgeDependenciesResolver(
}
}
fun ScriptCompilationConfiguration.toDependencies(classpath: List<File>): ScriptDependencies {
val defaultImports = this[ScriptCompilationConfiguration.defaultImports]?.toList() ?: emptyList()
return ScriptDependencies(
classpath = classpath,
sources = this[ScriptCompilationConfiguration.ide.dependenciesSources].toClassPathOrEmpty(),
imports = defaultImports,
scripts = this[ScriptCompilationConfiguration.importScripts].toFilesOrEmpty()
)
}
internal fun List<ScriptDiagnostic>.mapScriptReportsToDiagnostics() =
map { ScriptReport(it.message, mapToLegacyScriptReportSeverity(it.severity), mapToLegacyScriptReportPosition(it.location)) }
@@ -101,7 +102,7 @@ internal fun ScriptContents.toScriptSource(): SourceCode = when {
else -> throw IllegalArgumentException("Unable to convert script contents $this into script source")
}
internal fun List<ScriptDependency>?.toClassPathOrEmpty() = this?.flatMap { (it as JvmDependency).classpath } ?: emptyList()
fun List<ScriptDependency>?.toClassPathOrEmpty() = this?.flatMap { (it as JvmDependency).classpath } ?: emptyList()
internal fun List<SourceCode>?.toFilesOrEmpty() = this?.map {
val externalSource = it as? ExternalSourceCode
@@ -9,6 +9,7 @@ package kotlin.script.experimental.jvm
import kotlin.reflect.KClass
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.util.PropertiesCollection
interface JvmScriptEvaluationConfigurationKeys
@@ -21,7 +22,10 @@ open class JvmScriptEvaluationConfigurationBuilder : PropertiesCollection.Builde
/**
* The base classloader to use for script classes loading
*/
val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection.key<ClassLoader?>(Thread.currentThread().contextClassLoader)
val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection.key<ClassLoader?> {
get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jvm.baseClassLoader)
?: Thread.currentThread().contextClassLoader
}
/**
* Load script dependencies before evaluation, true by default
@@ -11,6 +11,7 @@ import java.net.URLClassLoader
import kotlin.reflect.KClass
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.*
import kotlin.script.experimental.jvm.impl.toClassPathOrEmpty
import kotlin.script.experimental.util.PropertiesCollection
interface JvmScriptingHostConfigurationKeys
@@ -25,6 +26,12 @@ val JvmScriptingHostConfigurationKeys.javaHome by PropertiesCollection.key<File>
val JvmScriptingHostConfigurationKeys.jdkHome by PropertiesCollection.key<File>()
val JvmScriptingHostConfigurationKeys.baseClassLoader by PropertiesCollection.key<ClassLoader> {
get(ScriptingHostConfiguration.configurationDependencies)?.let {
URLClassLoader(it.toClassPathOrEmpty().map { f -> f.toURI().toURL() }.toTypedArray())
}
}
@Suppress("unused")
val ScriptingHostConfigurationKeys.jvm
get() = JvmScriptingHostConfigurationBuilder()
@@ -49,15 +56,17 @@ class JvmGetScriptingClass : GetScriptingClass, Serializable {
@Transient
private var baseClassLoader: ClassLoader? = null
override fun invoke(classType: KotlinType, contextClass: KClass<*>, hostConfiguration: ScriptingHostConfiguration): KClass<*> =
invoke(classType, contextClass.java.classLoader, hostConfiguration)
@Synchronized
override fun invoke(classType: KotlinType, contextClass: KClass<*>, hostConfiguration: ScriptingHostConfiguration): KClass<*> {
operator fun invoke(classType: KotlinType, contextClassLoader: ClassLoader?, hostConfiguration: ScriptingHostConfiguration): KClass<*> {
// checking if class already loaded in the same context
val contextClassloader = contextClass.java.classLoader
val fromClass = classType.fromClass
if (fromClass != null) {
if (fromClass.java.classLoader == null) return fromClass // root classloader
val actualClassLoadersChain = generateSequence(contextClassloader) { it.parent }
val actualClassLoadersChain = generateSequence(contextClassLoader) { it.parent }
if (actualClassLoadersChain.any { it == fromClass.java.classLoader }) return fromClass
}
@@ -71,7 +80,7 @@ class JvmGetScriptingClass : GetScriptingClass, Serializable {
}
if (baseClassLoaderIsInitialized != true) {
baseClassLoader = contextClassloader
baseClassLoader = contextClassLoader
baseClassLoaderIsInitialized = true
}
// TODO: this check breaks testLazyScriptDefinition, find out the reason and fix
@@ -88,12 +97,12 @@ class JvmGetScriptingClass : GetScriptingClass, Serializable {
}
}
classLoader =
if (classpath == null || classpath.isEmpty()) baseClassLoader
else URLClassLoader(classpath.toTypedArray(), baseClassLoader)
if (classpath == null || classpath.isEmpty()) baseClassLoader
else URLClassLoader(classpath.toTypedArray(), baseClassLoader)
}
return try {
classLoader!!.loadClass(classType.typeName).kotlin
(classLoader ?: ClassLoader.getSystemClassLoader()).loadClass(classType.typeName).kotlin
} catch (e: Throwable) {
throw IllegalArgumentException("unable to load class $classType", e)
}