Refactor context classpath discovery, share it to idea's jsr223 host...

...from script-util
fix daemon usage in repls
define compiler classpath for script-util tests explicitly
minor refactorings in the build scripts for better import into idea
This commit is contained in:
Ilya Chernikov
2017-09-27 19:16:19 +02:00
parent 12e35ccf96
commit cff6d8cf17
10 changed files with 185 additions and 188 deletions
@@ -30,4 +30,6 @@ javadocJar()
dist()
ideaPlugin()
publish()
+5 -4
View File
@@ -4,11 +4,10 @@ import org.gradle.jvm.tasks.Jar
apply { plugin("kotlin") }
dependencies {
compile(projectDist(":kotlin-stdlib"))
compile(project(":kotlin-stdlib"))
compile(project(":core"))
compile(project(":compiler:backend"))
compile(project(":compiler:cli-common"))
compile(projectRuntimeJar(":kotlin-daemon-client"))
compile(project(":compiler:frontend"))
compile(project(":compiler:frontend.java"))
compile(project(":compiler:frontend.script"))
@@ -27,6 +26,8 @@ dependencies {
compile(project(":idea:kotlin-gradle-tooling"))
compile(project(":plugins:uast-kotlin"))
compile(project(":plugins:uast-kotlin-idea"))
// compile(project(":kotlin-daemon-client")) { isTransitive = false }
compile(project(":kotlin-script-util")) { isTransitive = false }
compile(ideaSdkCoreDeps("intellij-core", "util"))
@@ -39,8 +40,7 @@ dependencies {
compile(preloadedDeps("markdown", "kotlinx-coroutines-core"))
testCompile(projectDist(":kotlin-test:kotlin-test-junit"))
testCompile(project(":compiler:cli"))
testCompile(project(":kotlin-test:kotlin-test-junit"))
testCompile(project(":compiler.tests-common"))
testCompile(project(":idea:idea-test-framework")) { isTransitive = false }
testCompile(project(":idea:idea-jvm")) { isTransitive = false }
@@ -92,6 +92,7 @@ sourceSets {
java.srcDirs("idea-completion/src",
"idea-live-templates/src",
"idea-repl/src")
resources.srcDirs("idea-repl/src").apply { include("META-INF/**") }
}
"test" {
projectDefault()
@@ -18,13 +18,8 @@ package org.jetbrains.kotlin.jsr223
import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase
import org.jetbrains.kotlin.cli.common.repl.ScriptArgsWithTypes
import org.jetbrains.kotlin.script.util.scriptCompilationClasspathFromContext
import org.jetbrains.kotlin.utils.PathUtil
import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_JAVA_SCRIPT_RUNTIME_JAR
import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_JAVA_STDLIB_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
@@ -34,53 +29,10 @@ class KotlinJsr223StandardScriptEngineFactory4Idea : KotlinJsr223JvmScriptEngine
override fun getScriptEngine(): ScriptEngine =
KotlinJsr223JvmScriptEngine4Idea(
this,
scriptCompilationClasspathFromContext(Thread.currentThread().contextClassLoader),
scriptCompilationClasspathFromContext(PathUtil.KOTLIN_JAVA_SCRIPT_RUNTIME_JAR),
"kotlin.script.templates.standard.ScriptTemplateWithBindings",
{ ctx, argTypes -> ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), argTypes ?: emptyArray()) },
arrayOf(Map::class)
)
}
// 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<File>? =
generateSequence(classLoader) { it.parent }.toList().flatMap { (it as? URLClassLoader)?.urLs?.mapNotNull(URL::toFile) ?: emptyList() }
private val kotlinCompilerJar: File by lazy {
// highest prio - explicit property
System.getProperty("kotlin.compiler.jar")?.let(::File)?.takeIf(File::exists)
?: PathUtil.kotlinPathsForIdeaPlugin.compilerPath
?: throw FileNotFoundException("Cannot find kotlin compiler jar, set kotlin.compiler.jar property to proper location")
}
private fun scriptCompilationClasspathFromContext(classLoader: ClassLoader): List<File> =
( System.getProperty("kotlin.script.classpath")?.split(File.pathSeparator)?.map(::File)
?: classpathFromClassloader(classLoader)
).let {
it?.plus(kotlinScriptStandardJars) ?: kotlinScriptStandardJars
}
.map { it?.canonicalFile }
.distinct()
.mapNotNull { it?.takeIf(File::exists) }
private val kotlinStdlibJar: File? by lazy {
System.getProperty("kotlin.java.runtime.jar")?.let(::File)?.takeIf(File::exists)
?: File(kotlinCompilerJar.parentFile, KOTLIN_JAVA_STDLIB_JAR).takeIf(File::exists)
}
private val kotlinScriptRuntimeJar: File? by lazy {
System.getProperty("kotlin.script.runtime.jar")?.let(::File)?.takeIf(File::exists)
?: File(kotlinCompilerJar.parentFile, KOTLIN_JAVA_SCRIPT_RUNTIME_JAR).takeIf(File::exists)
}
private val kotlinScriptStandardJars by lazy { listOf(kotlinStdlibJar, kotlinScriptRuntimeJar) }
@@ -3,15 +3,24 @@ description = "Sample Kotlin JSR 223 scripting jar with daemon (out-of-process)
apply { plugin("kotlin") }
val compilerClasspath by configurations.creating
dependencies {
compile(projectDist(":kotlin-stdlib"))
compile(projectDist(":kotlin-script-runtime"))
compile(projectRuntimeJar(":kotlin-compiler"))
compile(project(":kotlin-script-util"))
compile(projectRuntimeJar(":kotlin-daemon-client"))
testCompile(project(":kotlin-stdlib"))
testCompile(project(":kotlin-script-runtime"))
testCompile(project(":kotlin-script-util"))
testCompile(project(":kotlin-daemon-client"))
testCompile(commonDep("junit:junit"))
testCompile(projectDist(":kotlin-test:kotlin-test-junit"))
testRuntime(projectDist(":kotlin-reflect"))
testCompile(project(":kotlin-test:kotlin-test-junit"))
testRuntime(project(":kotlin-reflect"))
compilerClasspath(projectRuntimeJar(":kotlin-compiler"))
compilerClasspath(projectDist(":kotlin-reflect"))
compilerClasspath(projectDist(":kotlin-stdlib"))
compilerClasspath(projectDist(":kotlin-script-runtime"))
}
projectTest()
projectTest {
doFirst {
systemProperty("kotlin.compiler.classpath", compilerClasspath.asFileTree.asPath)
}
}
@@ -4,15 +4,18 @@ description = "Kotlin scripting support utilities"
apply { plugin("kotlin") }
dependencies {
compile(projectDist(":kotlin-stdlib"))
compile(projectDist(":kotlin-script-runtime"))
compile(projectRuntimeJar(":kotlin-compiler"))
compile(projectRuntimeJar(":kotlin-daemon-client"))
compile(project(":kotlin-stdlib"))
compile(project(":kotlin-script-runtime"))
compileOnly(project(":compiler:cli"))
compileOnly(project(":compiler:daemon-common"))
compile(project(":kotlin-daemon-client"))
compileOnly("com.jcabi:jcabi-aether:0.10.1")
compileOnly("org.sonatype.aether:aether-api:1.13.1")
compileOnly("org.apache.maven:maven-core:3.0.3")
testCompile(projectDist(":kotlin-test:kotlin-test-junit"))
testRuntime(projectDist(":kotlin-reflect"))
runtime(projectRuntimeJar(":kotlin-compiler"))
testCompileOnly(project(":compiler:cli"))
testCompile(project(":kotlin-test:kotlin-test-junit"))
testRuntime(project(":kotlin-reflect"))
testCompile(commonDep("junit:junit"))
testRuntime("com.jcabi:jcabi-aether:0.10.1")
testRuntime("org.sonatype.aether:aether-api:1.13.1")
@@ -26,3 +29,5 @@ sourcesJar()
javadocJar()
publish()
ideaPlugin()
@@ -39,7 +39,7 @@ import kotlin.reflect.KClass
class KotlinJsr223JvmDaemonCompileScriptEngine(
disposable: Disposable,
factory: ScriptEngineFactory,
compilerJar: File,
compilerClasspath: List<File>,
templateClasspath: List<File>,
templateClassName: String,
val getScriptArgs: (ScriptContext, Array<out KClass<out Any>>?) -> ScriptArgsWithTypes?,
@@ -47,7 +47,7 @@ class KotlinJsr223JvmDaemonCompileScriptEngine(
compilerOut: OutputStream = System.err
) : KotlinJsr223JvmScriptEngineBase(factory), KotlinJsr223JvmInvocableScriptEngine {
private val daemon by lazy { connectToCompileService(compilerJar) }
private val daemon by lazy { connectToCompileService(compilerClasspath) }
override val replCompiler by lazy {
daemon.let {
@@ -73,8 +73,8 @@ class KotlinJsr223JvmDaemonCompileScriptEngine(
override fun overrideScriptArgs(context: ScriptContext): ScriptArgsWithTypes? = getScriptArgs(context, scriptArgsTypes)
private fun connectToCompileService(compilerJar: File): CompileService {
val compilerId = CompilerId.makeCompilerId(compilerJar)
private fun connectToCompileService(compilerCP: List<File>): CompileService {
val compilerId = CompilerId.makeCompilerId(*compilerCP.toTypedArray())
val daemonOptions = configureDaemonOptions()
val daemonJVMOptions = DaemonJVMOptions()
@@ -21,18 +21,10 @@ package org.jetbrains.kotlin.script.jsr223
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase
import org.jetbrains.kotlin.cli.common.repl.ScriptArgsWithTypes
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.script.util.classpathFromClass
import org.jetbrains.kotlin.script.util.classpathFromClassloader
import org.jetbrains.kotlin.script.util.classpathFromClasspathProperty
import org.jetbrains.kotlin.script.util.manifestClassPath
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.io.FileNotFoundException
import org.jetbrains.kotlin.script.util.*
import javax.script.Bindings
import javax.script.ScriptContext
import javax.script.ScriptEngine
import kotlin.script.templates.standard.ScriptTemplateWithArgs
class KotlinJsr223JvmLocalScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {
@@ -53,7 +45,7 @@ class KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory : KotlinJsr223JvmScriptE
KotlinJsr223JvmDaemonCompileScriptEngine(
Disposer.newDisposable(),
this,
kotlinCompilerJar,
KotlinJars.compilerClasspath,
scriptCompilationClasspathFromContext("kotlin-script-util.jar"),
KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!,
{ ctx, types -> ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray()) },
@@ -61,58 +53,3 @@ class KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory : KotlinJsr223JvmScriptE
)
}
private const val KOTLIN_COMPILER_JAR = "kotlin-compiler.jar"
private const val KOTLIN_JAVA_STDLIB_JAR = "kotlin-stdlib.jar"
private const val KOTLIN_JAVA_SCRIPT_RUNTIME_JAR = "kotlin-script-runtime.jar"
private fun File.existsOrNull(): File? = existsAndCheckOrNull { true }
private inline fun File.existsAndCheckOrNull(check: (File.() -> Boolean)): File? = if (exists() && check()) this else null
private fun <T> Iterable<T>.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<File>? =
(classpathFromClassloader(classLoader)?.anyOrNull { it.matchMaybeVersionedFile(keyName) }
?: manifestClassPath(classLoader)?.anyOrNull { it.matchMaybeVersionedFile(keyName) }
)?.toList()
private val validJarExtensions = setOf("jar", "zip")
private fun scriptCompilationClasspathFromContext(keyName: String, classLoader: ClassLoader = Thread.currentThread().contextClassLoader): List<File> =
(System.getProperty("kotlin.script.classpath")?.split(File.pathSeparator)?.map(::File)
?: contextClasspath(keyName, classLoader)
).let {
it?.plus(kotlinScriptStandardJars) ?: kotlinScriptStandardJars
}
.mapNotNull { it?.canonicalFile }
.distinct()
.filter { (it.isDirectory || (it.isFile && it.extension.toLowerCase() in validJarExtensions)) && it.exists() }
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.class.path` property
?: (classpathFromClass(Thread.currentThread().contextClassLoader, K2JVMCompiler::class)
?: contextClasspath(KOTLIN_COMPILER_JAR, Thread.currentThread().contextClassLoader)
?: classpathFromClasspathProperty()
)?.firstOrNull { it.matchMaybeVersionedFile(KOTLIN_COMPILER_JAR) }
?: throw FileNotFoundException("Cannot find kotlin compiler jar, set kotlin.compiler.jar property to proper location")
}
private val kotlinStdlibJar: File? by lazy {
System.getProperty("kotlin.java.runtime.jar")?.let(::File)?.existsOrNull()
?: kotlinCompilerJar.let { File(it.parentFile, KOTLIN_JAVA_STDLIB_JAR) }.existsOrNull()
?: PathUtil.getResourcePathForClass(JvmStatic::class.java).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()
?: PathUtil.getResourcePathForClass(ScriptTemplateWithArgs::class.java).existsOrNull()
}
private val kotlinScriptStandardJars by lazy { listOf(kotlinStdlibJar, kotlinScriptRuntimeJar) }
@@ -1,23 +1,36 @@
package org.jetbrains.kotlin.script.util
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.net.URI
import java.io.FileNotFoundException
import java.net.URL
import java.net.URLClassLoader
import java.util.jar.Manifest
import kotlin.reflect.KClass
import kotlin.script.templates.standard.ScriptTemplateWithArgs
private fun URL.toFile() =
try {
File(toURI().schemeSpecificPart)
}
catch (e: java.net.URISyntaxException) {
if (protocol != "file") null
else File(file)
}
// TODO: consider moving all these utilites to the build-common or some other shared compiler API module
internal const val KOTLIN_SCRIPT_CLASSPATH_PROPERTY = "kotlin.script.classpath"
internal const val KOTLIN_COMPILER_CLASSPATH_PROPERTY = "kotlin.compiler.classpath"
internal const val KOTLIN_COMPILER_JAR_PROPERTY = "kotlin.compiler.jar"
internal const val KOTLIN_STDLIB_JAR_PROPERTY = "kotlin.java.stdlib.jar"
// obsolete name, but maybe still used in the wild
// TODO: consider removing
internal const val KOTLIN_RUNTIME_JAR_PROPERTY = "kotlin.java.runtime.jar"
internal const val KOTLIN_SCRIPT_RUNTIME_JAR_PROPERTY = "kotlin.script.runtime.jar"
private val validClasspathFilesExtensions = setOf("jar", "zip", "java")
fun classpathFromClassloader(classLoader: ClassLoader): List<File>? =
generateSequence(classLoader) { it.parent }.toList().flatMap { (it as? URLClassLoader)?.urLs?.mapNotNull(URL::toFile) ?: emptyList() }
generateSequence(classLoader) { it.parent }.toList().flatMap {
(it as? URLClassLoader)?.urLs?.mapNotNull {
// taking only classpath elements pointing to dirs (presumably with classes) or jars, because this classpath is intended for
// usage with the kotlin compiler, which cannot process other types of entries, e.g. jni libs
it.toFile()?.takeIf { el -> el.isDirectory || validClasspathFilesExtensions.any { el.extension == it } }
}
?: emptyList()
}
fun classpathFromClasspathProperty(): List<File>? =
System.getProperty("java.class.path")
@@ -33,19 +46,74 @@ fun classpathFromClass(classLoader: ClassLoader, klass: KClass<out Any>): List<F
}
}
// Maven runners sometimes place classpath into the manifest, so we can use it for a fallback search
fun manifestClassPath(classLoader: ClassLoader): List<File>? =
classLoader.getResources("META-INF/MANIFEST.MF")
.asSequence()
.mapNotNull { ifFailed(null) { it.openStream().use { Manifest().apply { read(it) } } } }
.flatMap { it.mainAttributes?.getValue("Class-Path")?.splitToSequence(" ") ?: emptySequence() }
.mapNotNull { ifFailed(null) { File(URI.create(it)) } }
.toList()
.let { if (it.isNotEmpty()) it else null }
fun File.matchMaybeVersionedFile(baseName: String) =
name == baseName ||
name == baseName.removeSuffix(".jar") || // for classes dirs
Regex(Regex.escape(baseName.removeSuffix(".jar")) + "(-\\d.*)?\\.jar").matches(name)
private inline fun <R> ifFailed(default: R, block: () -> R) = try {
block()
} catch (t: Throwable) {
default
private const val KOTLIN_COMPILER_EMBEDDABLE_JAR = "${PathUtil.KOTLIN_COMPILER}-embeddable.jar"
internal fun List<File>.takeIfContainsAll(vararg keyNames: String): List<File>? =
takeIf { classpath ->
keyNames.all { key -> classpath.any { it.matchMaybeVersionedFile(key) } }
}
internal fun List<File>.takeIfContainsAny(vararg keyNames: String): List<File>? =
takeIf { classpath ->
keyNames.any { key -> classpath.any { it.matchMaybeVersionedFile(key) } }
}
fun scriptCompilationClasspathFromContext(vararg keyNames: String, classLoader: ClassLoader = Thread.currentThread().contextClassLoader): List<File> =
System.getProperty(KOTLIN_SCRIPT_CLASSPATH_PROPERTY)?.split(File.pathSeparator)?.map(::File)
?: classpathFromClassloader(classLoader)?.takeIfContainsAll(*keyNames)
?: classpathFromClasspathProperty()?.takeIfContainsAll(*keyNames)
?: KotlinJars.kotlinScriptStandardJars
object KotlinJars {
private val explicitCompilerClasspath: List<File>? by lazy {
System.getProperty(KOTLIN_COMPILER_CLASSPATH_PROPERTY)?.split(File.pathSeparator)?.map(::File)
?: System.getProperty(KOTLIN_COMPILER_JAR_PROPERTY)?.let(::File)?.takeIf(File::exists)?.let { listOf(it) }
}
val compilerClasspath: List<File> by lazy {
val kotlinCompilerJars = listOf(PathUtil.KOTLIN_COMPILER_JAR, KOTLIN_COMPILER_EMBEDDABLE_JAR)
val kotlinLibsJars = listOf(PathUtil.KOTLIN_JAVA_STDLIB_JAR, PathUtil.KOTLIN_JAVA_REFLECT_JAR, PathUtil.KOTLIN_JAVA_SCRIPT_RUNTIME_JAR)
val kotlinBaseJars = kotlinCompilerJars + kotlinLibsJars
val classpath = explicitCompilerClasspath
// search classpath from context classloader and `java.class.path` property
?: (classpathFromClass(Thread.currentThread().contextClassLoader, K2JVMCompiler::class)
?: classpathFromClassloader(Thread.currentThread().contextClassLoader)?.takeIf { it.isNotEmpty() }
?: classpathFromClasspathProperty()
)?.filter { f -> kotlinBaseJars.any { f.matchMaybeVersionedFile(it) } }?.takeIf { it.isNotEmpty() }
// if autodetected, additionaly check for presense of the compiler jars
if (classpath == null || (explicitCompilerClasspath == null && classpath.none { f -> kotlinCompilerJars.any { f.matchMaybeVersionedFile(it) } })) {
throw FileNotFoundException("Cannot find kotlin compiler jar, set kotlin.compiler.classpath property to proper location")
}
classpath!!
}
private fun getLib(propertyName: String, jarName: String, markerClass: KClass<*>): File? =
System.getProperty(propertyName)?.let(::File)?.takeIf(File::exists)
?: explicitCompilerClasspath?.firstOrNull { it.matchMaybeVersionedFile(jarName) }?.takeIf(File::exists)
?: PathUtil.getResourcePathForClass(markerClass.java).takeIf(File::exists)
val stdlib: File? by lazy {
System.getProperty(KOTLIN_STDLIB_JAR_PROPERTY)?.let(::File)?.takeIf(File::exists)
?: getLib(KOTLIN_RUNTIME_JAR_PROPERTY, PathUtil.KOTLIN_JAVA_STDLIB_JAR, JvmStatic::class)
}
val scriptRuntime: File? by lazy { getLib(KOTLIN_SCRIPT_RUNTIME_JAR_PROPERTY, PathUtil.KOTLIN_JAVA_SCRIPT_RUNTIME_JAR, ScriptTemplateWithArgs::class) }
val kotlinScriptStandardJars get() = listOf(stdlib, scriptRuntime).filterNotNull()
}
private fun URL.toFile() =
try {
File(toURI().schemeSpecificPart)
}
catch (e: java.net.URISyntaxException) {
if (protocol != "file") null
else File(file)
}
@@ -0,0 +1,44 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.script.util
import org.junit.Assert
import org.junit.Test
class ScriptUtilContextTests {
@Test
fun testExplicitScriptClasspath() {
withSysProp(KOTLIN_SCRIPT_CLASSPATH_PROPERTY, "a:b:c") {
val classpath = scriptCompilationClasspathFromContext()
Assert.assertEquals("a:b:c", classpath.joinToString(":"))
}
}
// TODO: more tests
}
private fun withSysProp(name: String, value: String, body: () -> Unit) {
val savedValue = System.setProperty(name, value)
try {
body()
}
finally {
if (savedValue != null) System.setProperty(name, savedValue)
else System.clearProperty(name)
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.script.util
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
@@ -24,7 +25,6 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.codegen.CompilationException
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
@@ -34,16 +34,13 @@ import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
import org.jetbrains.kotlin.script.util.templates.BindingsScriptTemplateWithLocalResolving
import org.jetbrains.kotlin.script.util.templates.StandardArgsScriptTemplateWithLocalResolving
import org.jetbrains.kotlin.script.util.templates.StandardArgsScriptTemplateWithMavenResolving
import org.jetbrains.kotlin.utils.PathUtil
//import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_JAVA_RUNTIME_JAR
import org.jetbrains.kotlin.utils.PathUtil.getResourcePathForClass
import org.junit.Assert
import org.junit.Test
import java.io.*
import java.net.URI
import java.util.jar.Manifest
import java.io.ByteArrayOutputStream
import java.io.OutputStream
import java.io.PrintStream
import kotlin.reflect.KClass
import kotlin.test.*
const val KOTLIN_JAVA_RUNTIME_JAR = "kotlin-stdlib.jar"
@@ -101,7 +98,7 @@ done
val scriptClass = compileScript("args-junit-hello-world.kts", StandardArgsScriptTemplateWithMavenResolving::class)
if (scriptClass == null) {
System.err.println(contextClasspath(KOTLIN_JAVA_RUNTIME_JAR, Thread.currentThread().contextClassLoader)?.joinToString())
System.err.println(classpathFromClassloader(Thread.currentThread().contextClassLoader)?.takeIfContainsAll(KOTLIN_JAVA_RUNTIME_JAR)?.joinToString())
}
Assert.assertNotNull(scriptClass)
captureOut {
@@ -132,7 +129,7 @@ done
val rootDisposable = Disposer.newDisposable()
try {
val configuration = CompilerConfiguration().apply {
contextClasspath(KOTLIN_JAVA_RUNTIME_JAR, Thread.currentThread().contextClassLoader)?.let {
classpathFromClassloader(Thread.currentThread().contextClassLoader)?.takeIfContainsAll(KOTLIN_JAVA_RUNTIME_JAR)?.let {
addJvmClasspathRoots(it)
}
@@ -142,13 +139,6 @@ done
if (it.exists()) {
addJvmClasspathRoot(it)
}
else {
// attempt to workaround some maven quirks
manifestClassPath(Thread.currentThread().contextClassLoader)?.let {
val files = it.filter { it.name.startsWith("kotlin-") }
addJvmClasspathRoots(files)
}
}
}
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script-util-test")
add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition)
@@ -206,14 +196,3 @@ private class NullOutputStream : OutputStream() {
override fun write(b: ByteArray, off: Int, len: Int) { }
}
private fun <T> Iterable<T>.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<File>? =
( classpathFromClassloader(classLoader)?.anyOrNull { it.matchMaybeVersionedFile(keyName) }
?: manifestClassPath(classLoader)?.anyOrNull { it.matchMaybeVersionedFile(keyName) }
)?.toList()