Refactor script resolving interface again

- remove Future from resovler since the idea need additional considerations
- simplify script contents interface
 -extend script dependencies with additional javaHome property
This commit is contained in:
Ilya Chernikov
2016-06-30 15:18:14 +02:00
parent dfec16d8e0
commit 55e084db8e
6 changed files with 37 additions and 51 deletions
@@ -47,25 +47,24 @@ data class KotlinConfigurableScriptDefinition(val config: KotlinScriptConfig, va
private val evaluatedClasspath by lazy { config.classpath.evalWithVars(environmentVars).map { File(it) }.distinctBy { it.canonicalPath } } private val evaluatedClasspath by lazy { config.classpath.evalWithVars(environmentVars).map { File(it) }.distinctBy { it.canonicalPath } }
override fun <TF> getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): Future<KotlinScriptExternalDependencies>? = override fun <TF> getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): KotlinScriptExternalDependencies? =
makeNullableFakeFuture( if (!isScript(file)) null
if (!isScript(file)) null else {
else { val extDeps = getScriptDependenciesFromConfig(file)
val extDeps = getScriptDependenciesFromConfig(file) when {
when { extDeps != null ->
extDeps != null -> object : KotlinScriptExternalDependencies {
object : KotlinScriptExternalDependencies { override val classpath: Iterable<File> = evaluatedClasspath + extDeps.classpath
override val classpath: Iterable<File> = evaluatedClasspath + extDeps.classpath override val imports = extDeps.imports
override val imports = extDeps.imports override val sources: Iterable<File> = extDeps.sources
override val sources: Iterable<File> = extDeps.sources }
} !evaluatedClasspath.isEmpty() ->
!evaluatedClasspath.isEmpty() -> object : KotlinScriptExternalDependencies {
object : KotlinScriptExternalDependencies { override val classpath: Iterable<File> = evaluatedClasspath
override val classpath: Iterable<File> = evaluatedClasspath }
} else -> null
else -> null }
} }
})
} }
@@ -54,10 +54,11 @@ interface KotlinScriptDefinition {
fun getScriptName(script: KtScript): Name = fun getScriptName(script: KtScript): Name =
ScriptNameUtil.fileNameWithExtensionStripped(script, KotlinParserDefinition.STD_SCRIPT_EXT) ScriptNameUtil.fileNameWithExtensionStripped(script, KotlinParserDefinition.STD_SCRIPT_EXT)
fun <TF> getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): Future<KotlinScriptExternalDependencies>? = null fun <TF> getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): KotlinScriptExternalDependencies? = null
} }
interface KotlinScriptExternalDependencies { interface KotlinScriptExternalDependencies {
val javaHome: String? get() = null
val classpath: Iterable<File> get() = emptyList() val classpath: Iterable<File> get() = emptyList()
val imports: Iterable<String> get() = emptyList() val imports: Iterable<String> get() = emptyList()
val sources: Iterable<File> get() = emptyList() val sources: Iterable<File> get() = emptyList()
@@ -65,6 +66,7 @@ interface KotlinScriptExternalDependencies {
} }
class KotlinScriptExternalDependenciesUnion(val dependencies: Iterable<KotlinScriptExternalDependencies>) : KotlinScriptExternalDependencies { class KotlinScriptExternalDependenciesUnion(val dependencies: Iterable<KotlinScriptExternalDependencies>) : KotlinScriptExternalDependencies {
override val javaHome: String? get() = dependencies.firstOrNull { it.javaHome != null }?.javaHome
override val classpath: Iterable<File> get() = dependencies.flatMap { it.classpath } override val classpath: Iterable<File> get() = dependencies.flatMap { it.classpath }
override val imports: Iterable<String> get() = dependencies.flatMap { it.imports } override val imports: Iterable<String> get() = dependencies.flatMap { it.imports }
override val sources: Iterable<File> get() = dependencies.flatMap { it.sources } override val sources: Iterable<File> get() = dependencies.flatMap { it.sources }
@@ -100,14 +102,3 @@ fun getKotlinTypeByFqName(scriptDescriptor: ScriptDescriptor, fqName: String): K
ClassId.topLevel(FqName(fqName)), ClassId.topLevel(FqName(fqName)),
NotFoundClasses(LockBasedStorageManager.NO_LOCKS, scriptDescriptor.module) NotFoundClasses(LockBasedStorageManager.NO_LOCKS, scriptDescriptor.module)
).defaultType ).defaultType
class FakeFuture<T: Any?>(val value: T) : Future<T> {
override fun isCancelled(): Boolean = false
override fun cancel(mayInterruptIfRunning: Boolean): Boolean = false
override fun get(): T = value
override fun get(timeout: Long, unit: TimeUnit): T = value
override fun isDone(): Boolean = true
}
fun <T: Any> makeNullableFakeFuture(value: T?): Future<T>? =
value?.let { FakeFuture(it) } ?: (null as Future<T>?)
@@ -37,7 +37,7 @@ class KotlinScriptExternalImportsProvider(val project: Project, private val scri
cache[path] cache[path]
?: if (cacheOfNulls.contains(path)) null ?: if (cacheOfNulls.contains(path)) null
else scriptDefinitionProvider.findScriptDefinition(file) else scriptDefinitionProvider.findScriptDefinition(file)
?.let { it.getDependenciesFor(file, project, null)?.get() } ?.let { it.getDependenciesFor(file, project, null) }
.apply { cacheLock.write { .apply { cacheLock.write {
if (this == null) { if (this == null) {
cacheOfNulls.add(path) cacheOfNulls.add(path)
@@ -58,7 +58,7 @@ class KotlinScriptExternalImportsProvider(val project: Project, private val scri
if (!cache.containsKey(path) && !cacheOfNulls.contains(path) && !uncached.contains(path)) { if (!cache.containsKey(path) && !cacheOfNulls.contains(path) && !uncached.contains(path)) {
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) val scriptDef = scriptDefinitionProvider.findScriptDefinition(file)
if (scriptDef != null) { if (scriptDef != null) {
val deps = scriptDef.getDependenciesFor(file, project, null)?.get() val deps = scriptDef.getDependenciesFor(file, project, null)
if (deps != null) { if (deps != null) {
cache.put(path, deps) cache.put(path, deps)
} }
@@ -80,7 +80,7 @@ class KotlinScriptExternalImportsProvider(val project: Project, private val scri
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) val scriptDef = scriptDefinitionProvider.findScriptDefinition(file)
if (scriptDef != null) { if (scriptDef != null) {
val oldDeps = cache[path] val oldDeps = cache[path]
val deps = scriptDef.getDependenciesFor(file, project, oldDeps)?.get() val deps = scriptDef.getDependenciesFor(file, project, oldDeps)
when { when {
deps != null && (oldDeps == null || deps != null && (oldDeps == null ||
!deps.classpath.isSamePathListAs(oldDeps.classpath) || !deps.sources.isSamePathListAs(oldDeps.sources)) -> { !deps.classpath.isSamePathListAs(oldDeps.classpath) || !deps.sources.isSamePathListAs(oldDeps.sources)) -> {
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.io.File import java.io.File
import java.io.InputStream
import java.lang.reflect.InvocationHandler import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method import java.lang.reflect.Method
import java.lang.reflect.Proxy import java.lang.reflect.Proxy
@@ -55,8 +54,7 @@ annotation class ScriptDependencyResolver(val resolver: KClass<out ScriptDepende
interface ScriptContents { interface ScriptContents {
val file: File? val file: File?
val annotations: Iterable<Annotation> val annotations: Iterable<Annotation>
val contents: CharSequence? val text: CharSequence?
val contentsStream: InputStream?
} }
// TODO: rename to just ScriptDependenciesResolver as soon as current deprecated one will be dropped // TODO: rename to just ScriptDependenciesResolver as soon as current deprecated one will be dropped
@@ -64,7 +62,7 @@ interface ScriptDependenciesResolverEx {
fun resolve(script: ScriptContents, fun resolve(script: ScriptContents,
environment: Map<String, Any?>?, environment: Map<String, Any?>?,
previousDependencies: KotlinScriptExternalDependencies? = null previousDependencies: KotlinScriptExternalDependencies? = null
): Future<KotlinScriptExternalDependencies>? = null ): KotlinScriptExternalDependencies? = null
} }
@Deprecated("Use new ScriptDependenciesResolverEx") @Deprecated("Use new ScriptDependenciesResolverEx")
@@ -110,13 +108,13 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass<out Any>, val
override fun resolve(script: ScriptContents, override fun resolve(script: ScriptContents,
environment: Map<String, Any?>?, environment: Map<String, Any?>?,
previousDependencies: KotlinScriptExternalDependencies? previousDependencies: KotlinScriptExternalDependencies?
): Future<KotlinScriptExternalDependencies>? = makeNullableFakeFuture( ): KotlinScriptExternalDependencies? =
resolver?.resolve( resolver?.resolve(
environment?.get("projectRoot") as? File?, environment?.get("projectRoot") as? File?,
script.file, script.file,
emptyList(), emptyList(),
environment as Any? environment as Any?
)) )
} }
private val definitionData by lazy { private val definitionData by lazy {
@@ -146,7 +144,7 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass<out Any>, val
// TODO: implement other strategy - e.g. try to extract something from match with ScriptFilePattern // TODO: implement other strategy - e.g. try to extract something from match with ScriptFilePattern
override fun getScriptName(script: KtScript): Name = ScriptNameUtil.fileNameWithExtensionStripped(script, KotlinParserDefinition.STD_SCRIPT_EXT) override fun getScriptName(script: KtScript): Name = ScriptNameUtil.fileNameWithExtensionStripped(script, KotlinParserDefinition.STD_SCRIPT_EXT)
override fun <TF> getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): Future<KotlinScriptExternalDependencies>? { override fun <TF> getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): KotlinScriptExternalDependencies? {
val fileAnnotations = getAnnotationEntries(file, project) val fileAnnotations = getAnnotationEntries(file, project)
.map { KtAnnotationWrapper(it) } .map { KtAnnotationWrapper(it) }
.mapNotNull { wrappedAnn -> .mapNotNull { wrappedAnn ->
@@ -196,8 +194,7 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass<out Any>, val
class BasicScriptContents<out TF>(val myFile: TF, override val annotations: Iterable<Annotation>) : ScriptContents { class BasicScriptContents<out TF>(val myFile: TF, override val annotations: Iterable<Annotation>) : ScriptContents {
override val file: File? get() = getFile(myFile) override val file: File? get() = getFile(myFile)
override val contents: CharSequence? get() = getFileContents(myFile) override val text: CharSequence? get() = getFileContents(myFile)
override val contentsStream: InputStream? get() = getFileContentsStream(myFile)
} }
} }
@@ -32,11 +32,10 @@ abstract class BaseScriptDefinition (val extension: String, val cp: List<File>?
override val name = "Test Kotlin Script" override val name = "Test Kotlin Script"
override fun <TF> isScript(file: TF): Boolean = getFileName(file).endsWith(extension) override fun <TF> isScript(file: TF): Boolean = getFileName(file).endsWith(extension)
override fun getScriptName(script: KtScript): Name = ScriptNameUtil.fileNameWithExtensionStripped(script, extension) override fun getScriptName(script: KtScript): Name = ScriptNameUtil.fileNameWithExtensionStripped(script, extension)
override fun <TF> getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): Future<KotlinScriptExternalDependencies>? = override fun <TF> getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): KotlinScriptExternalDependencies? =
makeNullableFakeFuture( object : KotlinScriptExternalDependencies {
object : KotlinScriptExternalDependencies { override val classpath: Iterable<File> = cp ?: (classpathFromProperty() + classpathFromClassloader(BaseScriptDefinition::class.java.classLoader)).distinct()
override val classpath: Iterable<File> = cp ?: (classpathFromProperty() + classpathFromClassloader(BaseScriptDefinition::class.java.classLoader)).distinct() }
})
} }
open class SimpleParamsWithClasspathTestScriptDefinition(extension: String, val parameters: List<ScriptParameter>, classpath: List<File>? = null, val extraDependencies: KotlinScriptExternalDependencies? = null) open class SimpleParamsWithClasspathTestScriptDefinition(extension: String, val parameters: List<ScriptParameter>, classpath: List<File>? = null, val extraDependencies: KotlinScriptExternalDependencies? = null)
@@ -127,7 +127,7 @@ class TestKotlinScriptDependenciesResolver : ScriptDependenciesResolverEx {
override fun resolve(script: ScriptContents, override fun resolve(script: ScriptContents,
environment: Map<String, Any?>?, environment: Map<String, Any?>?,
previousDependencies: KotlinScriptExternalDependencies? previousDependencies: KotlinScriptExternalDependencies?
): Future<KotlinScriptExternalDependencies>? ): KotlinScriptExternalDependencies?
{ {
val cp = script.annotations.flatMap { val cp = script.annotations.flatMap {
when (it) { when (it) {
@@ -136,10 +136,10 @@ class TestKotlinScriptDependenciesResolver : ScriptDependenciesResolverEx {
else -> throw Exception("Unknown annotation ${it.javaClass}") else -> throw Exception("Unknown annotation ${it.javaClass}")
} }
} }
return makeNullableFakeFuture(object : KotlinScriptExternalDependencies { return object : KotlinScriptExternalDependencies {
override val classpath: Iterable<File> = classpathFromClassloader() + cp override val classpath: Iterable<File> = classpathFromClassloader() + cp
override val imports: Iterable<String> = listOf("org.jetbrains.kotlin.scripts.DependsOn") override val imports: Iterable<String> = listOf("org.jetbrains.kotlin.scripts.DependsOn")
}) }
} }
private fun classpathFromClassloader(): List<File> = private fun classpathFromClassloader(): List<File> =