diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/jsr223/KotlinJsr223StandardScriptEngineFactory4Idea.kt b/idea/idea-repl/src/org/jetbrains/kotlin/jsr223/KotlinJsr223StandardScriptEngineFactory4Idea.kt index b39ed959fde..0c5d7a31826 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/jsr223/KotlinJsr223StandardScriptEngineFactory4Idea.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/jsr223/KotlinJsr223StandardScriptEngineFactory4Idea.kt @@ -19,6 +19,12 @@ package org.jetbrains.kotlin.jsr223 import com.intellij.openapi.util.Disposer import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase import org.jetbrains.kotlin.utils.PathUtil +import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_JAVA_RUNTIME_JAR +import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_JAVA_SCRIPT_RUNTIME_JAR +import java.io.File +import java.io.FileNotFoundException +import java.net.URL +import java.net.URLClassLoader import javax.script.ScriptContext import javax.script.ScriptEngine @@ -29,9 +35,64 @@ class KotlinJsr223StandardScriptEngineFactory4Idea : KotlinJsr223JvmScriptEngine KotlinJsr223JvmScriptEngine4Idea( Disposer.newDisposable(), this, - listOf(PathUtil.getKotlinPathsForIdeaPlugin().runtimePath, PathUtil.getKotlinPathsForIdeaPlugin().scriptRuntimePath), + scriptCompilationClasspathFromContext(Thread.currentThread().contextClassLoader), "kotlin.script.templates.standard.ScriptTemplateWithBindings", { ctx -> arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)) }, arrayOf(Map::class.java) ) } + +// TODO: some common parts with the code from script-utils, consider placing in a shared lib + +private fun URL.toFile() = + try { + File(toURI().schemeSpecificPart) + } + catch (e: java.net.URISyntaxException) { + if (protocol != "file") null + else File(file) + } + +fun classpathFromClassloader(classLoader: ClassLoader): List? = + generateSequence(classLoader) { it.parent }.toList().flatMap { (it as? URLClassLoader)?.urLs?.mapNotNull(URL::toFile) ?: emptyList() } + +private fun File.existsOrNull(): File? = existsAndCheckOrNull { true } +private inline fun File.existsAndCheckOrNull(check: (File.() -> Boolean)): File? = if (exists() && check()) this else null + +private val kotlinCompilerJar: File by lazy { + // highest prio - explicit property + System.getProperty("kotlin.compiler.jar")?.let(::File)?.existsOrNull() + ?: PathUtil.getKotlinPathsForIdeaPlugin().compilerPath + ?: throw FileNotFoundException("Cannot find kotlin compiler jar, set kotlin.compiler.jar property to proper location") +} +private fun Iterable.anyOrNull(predicate: (T) -> Boolean) = if (any(predicate)) this else null + +private fun File.matchMaybeVersionedFile(baseName: String) = + name == baseName || + name == baseName.removeSuffix(".jar") || // for classes dirs + name.startsWith(baseName.removeSuffix(".jar") + "-") + +private fun contextClasspath(keyName: String, classLoader: ClassLoader): List? = + ( classpathFromClassloader(classLoader)?.anyOrNull { it.matchMaybeVersionedFile(keyName) } + )?.toList() + + +private fun scriptCompilationClasspathFromContext(classLoader: ClassLoader): List = + ( System.getProperty("kotlin.script.classpath")?.split(File.pathSeparator)?.map(::File) + ?: contextClasspath(KOTLIN_JAVA_RUNTIME_JAR, classLoader) + ?: listOf(kotlinRuntimeJar, kotlinScriptRuntimeJar) + ) + .map { it?.canonicalFile } + .distinct() + .mapNotNull { it?.existsOrNull() } + + +private val kotlinRuntimeJar: File? by lazy { + System.getProperty("kotlin.java.runtime.jar")?.let(::File)?.existsOrNull() + ?: kotlinCompilerJar.let { File(it.parentFile, KOTLIN_JAVA_RUNTIME_JAR) }.existsOrNull() +} + +private val kotlinScriptRuntimeJar: File? by lazy { + System.getProperty("kotlin.script.runtime.jar")?.let(::File)?.existsOrNull() + ?: kotlinCompilerJar.let { File(it.parentFile, KOTLIN_JAVA_SCRIPT_RUNTIME_JAR) }.existsOrNull() +} diff --git a/libraries/tools/kotlin-script-util/src/main/kotlin/org/jetbrains/kotlin/script/jsr223/KotlinJsr223ScriptEngineFactoryExamples.kt b/libraries/tools/kotlin-script-util/src/main/kotlin/org/jetbrains/kotlin/script/jsr223/KotlinJsr223ScriptEngineFactoryExamples.kt index 48179257e48..a01b5d5e804 100644 --- a/libraries/tools/kotlin-script-util/src/main/kotlin/org/jetbrains/kotlin/script/jsr223/KotlinJsr223ScriptEngineFactoryExamples.kt +++ b/libraries/tools/kotlin-script-util/src/main/kotlin/org/jetbrains/kotlin/script/jsr223/KotlinJsr223ScriptEngineFactoryExamples.kt @@ -73,7 +73,7 @@ private inline fun File.existsAndCheckOrNull(check: (File.() -> Boolean)): File? private val kotlinCompilerJar: File by lazy { // highest prio - explicit property System.getProperty("kotlin.compiler.jar")?.let(::File)?.existsOrNull() - // search classpath from context classloader and `java.calss.path` property + // search classpath from context classloader and `java.class.path` property ?: (classpathFromClass(Thread.currentThread().contextClassLoader, K2JVMCompiler::class) ?: contextClasspath(KOTLIN_COMPILER_JAR, Thread.currentThread().contextClassLoader) ?: classpathFromClasspathProperty() diff --git a/libraries/tools/kotlin-script-util/src/main/kotlin/org/jetbrains/kotlin/script/util/context.kt b/libraries/tools/kotlin-script-util/src/main/kotlin/org/jetbrains/kotlin/script/util/context.kt index 13e4d1c717d..f89b8267633 100644 --- a/libraries/tools/kotlin-script-util/src/main/kotlin/org/jetbrains/kotlin/script/util/context.kt +++ b/libraries/tools/kotlin-script-util/src/main/kotlin/org/jetbrains/kotlin/script/util/context.kt @@ -1,7 +1,5 @@ package org.jetbrains.kotlin.script.util -import org.jetbrains.kotlin.script.util.resolvers.DirectResolver -import org.jetbrains.kotlin.script.util.resolvers.MavenResolver import java.io.File import java.net.URI import java.net.URL @@ -9,7 +7,6 @@ import java.net.URLClassLoader import java.util.jar.Manifest import kotlin.reflect.KClass - private fun URL.toFile() = try { File(toURI().schemeSpecificPart)