Add kotlin-script-util lib with tests
- collection of standard templates and resolvers
This commit is contained in:
@@ -104,6 +104,7 @@
|
|||||||
<module>tools/kotlin-gradle-plugin-api</module>
|
<module>tools/kotlin-gradle-plugin-api</module>
|
||||||
<module>tools/kotlin-android-extensions</module>
|
<module>tools/kotlin-android-extensions</module>
|
||||||
<module>tools/kotlin-maven-plugin-test</module>
|
<module>tools/kotlin-maven-plugin-test</module>
|
||||||
|
<module>tools/kotlin-script-util</module>
|
||||||
|
|
||||||
<module>examples/kotlin-java-example</module>
|
<module>examples/kotlin-java-example</module>
|
||||||
<module>examples/js-example</module>
|
<module>examples/js-example</module>
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<properties>
|
||||||
|
<maven-plugin-anno.version>1.4.1</maven-plugin-anno.version>
|
||||||
|
<maven.version>3.0.4</maven.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-project</artifactId>
|
||||||
|
<version>1.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>kotlin-script-util</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<description>Kotlin scripting support utilities</description>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jetbrains-utils</id>
|
||||||
|
<url>http://repository.jetbrains.com/utils</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-compiler</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jcabi</groupId>
|
||||||
|
<artifactId>jcabi-aether</artifactId>
|
||||||
|
<version>0.10.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.sonatype.aether</groupId>
|
||||||
|
<artifactId>aether-api</artifactId>
|
||||||
|
<version>1.13.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven</groupId>
|
||||||
|
<artifactId>maven-core</artifactId>
|
||||||
|
<version>3.0.3</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
||||||
|
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<version>2.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>properties</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>kotlin-maven-plugin</artifactId>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>compile</id>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals> <goal>compile</goal> </goals>
|
||||||
|
</execution>
|
||||||
|
|
||||||
|
<execution>
|
||||||
|
<id>test-compile</id>
|
||||||
|
<phase>test-compile</phase>
|
||||||
|
<goals> <goal>test-compile</goal> </goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
|
<version>2.6</version>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<runtimeJar>${org.jetbrains.kotlin:kotlin-stdlib:jar}</runtimeJar>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>integration-test</goal>
|
||||||
|
<goal>verify</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.FILE, AnnotationTarget.EXPRESSION, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class DependsOn(val value: String)
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.FILE, AnnotationTarget.EXPRESSION, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class Repository(val value: String)
|
||||||
|
|
||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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.jetbrains.kotlin.script.*
|
||||||
|
import org.jetbrains.kotlin.script.util.resolvers.DirectResolver
|
||||||
|
import org.jetbrains.kotlin.script.util.resolvers.FlatLibDirectoryResolver
|
||||||
|
import org.jetbrains.kotlin.script.util.resolvers.MavenResolver
|
||||||
|
import org.jetbrains.kotlin.script.util.resolvers.Resolver
|
||||||
|
import java.io.File
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
import java.net.URL
|
||||||
|
import java.net.URLClassLoader
|
||||||
|
import java.util.concurrent.Future
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
open class KotlinAnnotatedScriptDependenciesResolver(val baseClassPath: List<File>, resolvers: Iterable<Resolver>)
|
||||||
|
: ScriptDependenciesResolver
|
||||||
|
{
|
||||||
|
private val resolvers: MutableList<Resolver> = resolvers.toMutableList()
|
||||||
|
|
||||||
|
@AcceptedAnnotations(DependsOn::class, Repository::class)
|
||||||
|
override fun resolve(script: ScriptContents,
|
||||||
|
environment: Map<String, Any?>?,
|
||||||
|
report: (ScriptDependenciesResolver.ReportSeverity, String, ScriptContents.Position?) -> Unit,
|
||||||
|
previousDependencies: KotlinScriptExternalDependencies?
|
||||||
|
): Future<KotlinScriptExternalDependencies?>
|
||||||
|
= (if (previousDependencies != null && resolveFromAnnotations(script).isEmpty()) previousDependencies
|
||||||
|
else
|
||||||
|
object : KotlinScriptExternalDependencies {
|
||||||
|
override val classpath: Iterable<File> = if (resolvers.isEmpty()) baseClassPath else baseClassPath + resolveFromAnnotations(script)
|
||||||
|
override val imports: Iterable<String> =
|
||||||
|
previousDependencies?.let { emptyList<String>() } ?: listOf(DependsOn::class.java.`package`.name + ".*")
|
||||||
|
}
|
||||||
|
).asFuture()
|
||||||
|
|
||||||
|
private fun resolveFromAnnotations(script: ScriptContents): List<File> {
|
||||||
|
script.annotations.forEach {
|
||||||
|
when (it) {
|
||||||
|
is Repository ->
|
||||||
|
when {
|
||||||
|
File(it.value).run { exists() && isDirectory } -> resolvers.add(FlatLibDirectoryResolver(File(it.value)))
|
||||||
|
else -> throw IllegalArgumentException("Illegal argument for Repository annotation: ${it.value}")
|
||||||
|
}
|
||||||
|
is DependsOn -> {}
|
||||||
|
is InvalidScriptResolverAnnotation -> throw Exception("Invalid annotation ${it.name}", it.error)
|
||||||
|
else -> throw Exception("Unknown annotation ${it.javaClass}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return script.annotations.filterIsInstance(DependsOn::class.java).flatMap { dep ->
|
||||||
|
resolvers.asSequence().mapNotNull { it.tryResolve(dep) }.firstOrNull() ?:
|
||||||
|
throw Exception("Unable to resolve dependency $dep")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun URL.toFile() =
|
||||||
|
try {
|
||||||
|
File(toURI().schemeSpecificPart)
|
||||||
|
}
|
||||||
|
catch (e: java.net.URISyntaxException) {
|
||||||
|
if (protocol != "file") null
|
||||||
|
else File(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun classpathFromClassloader(classLoader: ClassLoader): List<File>? =
|
||||||
|
generateSequence(classLoader) { it.parent }.toList().flatMap { (it as? URLClassLoader)?.urLs?.mapNotNull { it.toFile() } ?: emptyList() }
|
||||||
|
|
||||||
|
private fun classpathFromClasspathProperty(): List<File>? =
|
||||||
|
System.getProperty("java.class.path")?.let {
|
||||||
|
it.split(String.format("\\%s", File.pathSeparatorChar).toRegex()).dropLastWhile(String::isEmpty).toTypedArray()
|
||||||
|
.map(::File)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun classpathFromClass(classLoader: ClassLoader, klass: KClass<out Any>): List<File>? {
|
||||||
|
val clp = "${klass.qualifiedName?.replace('.', '/')}.class"
|
||||||
|
val url = classLoader.getResource(clp)
|
||||||
|
return url?.toURI()?.path?.removeSuffix(clp)?.let {
|
||||||
|
listOf(File(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val defaultScriptBaseClasspath: List<File> by lazy {
|
||||||
|
classpathFromClass(Thread.currentThread().contextClassLoader, KotlinAnnotatedScriptDependenciesResolver::class)
|
||||||
|
?: classpathFromClasspathProperty()
|
||||||
|
?: classpathFromClassloader(Thread.currentThread().contextClassLoader)
|
||||||
|
?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultKotlinResolver() :
|
||||||
|
KotlinAnnotatedScriptDependenciesResolver(defaultScriptBaseClasspath, arrayListOf())
|
||||||
|
|
||||||
|
class DefaultKotlinAnnotatedScriptDependenciesResolver :
|
||||||
|
KotlinAnnotatedScriptDependenciesResolver(defaultScriptBaseClasspath, arrayListOf(DirectResolver(), MavenResolver()))
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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.resolvers
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.script.util.DependsOn
|
||||||
|
import java.io.File
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
|
||||||
|
interface Resolver {
|
||||||
|
fun tryResolve(dependsOn: DependsOn): Iterable<File>?
|
||||||
|
}
|
||||||
|
|
||||||
|
class DirectResolver : Resolver {
|
||||||
|
override fun tryResolve(dependsOn: DependsOn): Iterable<File>? =
|
||||||
|
if (dependsOn.value.isNotBlank() && File(dependsOn.value).exists()) listOf(File(dependsOn.value)) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
class FlatLibDirectoryResolver(val path: File) : Resolver {
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (!path.exists() || !path.isDirectory) throw IllegalArgumentException("Invalid flat lib directory repository path '$path'")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tryResolve(dependsOn: DependsOn): Iterable<File>? =
|
||||||
|
when {
|
||||||
|
dependsOn.value.isNotBlank() && File(path, dependsOn.value).exists() -> listOf(File(path, dependsOn.value))
|
||||||
|
// TODO: add coordinates and wildcard matching
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
+58
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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.resolvers
|
||||||
|
|
||||||
|
import com.jcabi.aether.Aether
|
||||||
|
import org.jetbrains.kotlin.script.util.DependsOn
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
import org.sonatype.aether.repository.RemoteRepository
|
||||||
|
import org.sonatype.aether.resolution.DependencyResolutionException
|
||||||
|
import org.sonatype.aether.util.artifact.DefaultArtifact
|
||||||
|
import org.sonatype.aether.util.artifact.JavaScopes
|
||||||
|
|
||||||
|
val mavenCentral = RemoteRepository("maven-central", "default", "http://repo1.maven.org/maven2/")
|
||||||
|
|
||||||
|
class MavenResolver(val reportError: ((String) -> Unit) = {}): Resolver {
|
||||||
|
|
||||||
|
// TODO: make robust
|
||||||
|
val localRepo = File(File(System.getProperty("user.home")!!, ".m2"), "repository")
|
||||||
|
|
||||||
|
val repos: ArrayList<RemoteRepository> = arrayListOf()
|
||||||
|
|
||||||
|
private fun currentRepos() = if (repos.isEmpty()) arrayListOf(mavenCentral) else repos
|
||||||
|
|
||||||
|
override fun tryResolve(dependsOn: DependsOn): Iterable<File>? {
|
||||||
|
if (dependsOn.value.count { it == ':' } == 2) {
|
||||||
|
try {
|
||||||
|
val deps = Aether(currentRepos(), localRepo).resolve(
|
||||||
|
DefaultArtifact(dependsOn.value),
|
||||||
|
JavaScopes.RUNTIME)
|
||||||
|
if (deps != null)
|
||||||
|
return deps.map { it.file }
|
||||||
|
else {
|
||||||
|
reportError("resolving [${dependsOn.value}] failed: no results")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e: DependencyResolutionException) {
|
||||||
|
reportError("resolving [${dependsOn.value}] failed: $e")
|
||||||
|
}
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("unused") // an API
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.script.util
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.script.ScriptTemplateDefinition
|
||||||
|
|
||||||
|
@ScriptTemplateDefinition(resolver = DefaultKotlinResolver::class, scriptFilePattern = ".*\\.kts")
|
||||||
|
abstract class StandardScript(val args: Array<String>)
|
||||||
|
|
||||||
|
@ScriptTemplateDefinition(resolver = DefaultKotlinAnnotatedScriptDependenciesResolver::class, scriptFilePattern = ".*\\.kts")
|
||||||
|
abstract class StandardScriptWithAnnotatedResolving(val args: Array<String>)
|
||||||
|
|
||||||
|
@ScriptTemplateDefinition(resolver = DefaultKotlinResolver::class, scriptFilePattern = ".*\\.kts")
|
||||||
|
abstract class ScriptWithBindings(val bindings: Map<String, Any?>)
|
||||||
|
|
||||||
|
@ScriptTemplateDefinition(resolver = DefaultKotlinAnnotatedScriptDependenciesResolver::class, scriptFilePattern = ".*\\.kts")
|
||||||
|
abstract class ScriptWithBindingsAndAnnotatedResolving(val bindings: Map<String, Any?>)
|
||||||
+161
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.*
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
|
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
|
||||||
|
import org.jetbrains.kotlin.config.addKotlinSourceRoot
|
||||||
|
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||||
|
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromTemplate
|
||||||
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Test
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.io.PrintStream
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class ScriptUtilIT {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val argsHelloWorldOutput =
|
||||||
|
"""Hello, world!
|
||||||
|
a1
|
||||||
|
done
|
||||||
|
"""
|
||||||
|
private val bindingsHelloWorldOutput =
|
||||||
|
"""Hello, world!
|
||||||
|
a1 = 42
|
||||||
|
done
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testArgsHelloWorld() {
|
||||||
|
val scriptClass = compileScript("args-hello-world.kts", StandardScript::class)
|
||||||
|
Assert.assertNotNull(scriptClass)
|
||||||
|
val ctor = scriptClass?.getConstructor(Array<String>::class.java)
|
||||||
|
Assert.assertNotNull(ctor)
|
||||||
|
captureOut {
|
||||||
|
ctor!!.newInstance(arrayOf("a1"))
|
||||||
|
}.let {
|
||||||
|
Assert.assertEquals(argsHelloWorldOutput, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBndHelloWorld() {
|
||||||
|
val scriptClass = compileScript("bindings-hello-world.kts", ScriptWithBindings::class)
|
||||||
|
Assert.assertNotNull(scriptClass)
|
||||||
|
val ctor = scriptClass?.getConstructor(Map::class.java)
|
||||||
|
Assert.assertNotNull(ctor)
|
||||||
|
captureOut {
|
||||||
|
ctor!!.newInstance(hashMapOf("a1" to 42))
|
||||||
|
}.let {
|
||||||
|
Assert.assertEquals(bindingsHelloWorldOutput, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testResolveStdHelloWorld() {
|
||||||
|
Assert.assertNull(compileScript("args-junit-hello-world.kts", StandardScript::class))
|
||||||
|
|
||||||
|
val scriptClass = compileScript("args-junit-hello-world.kts", StandardScriptWithAnnotatedResolving::class)
|
||||||
|
Assert.assertNotNull(scriptClass)
|
||||||
|
captureOut {
|
||||||
|
scriptClass!!.getConstructor(Array<String>::class.java)!!.newInstance(arrayOf("a1"))
|
||||||
|
}.let {
|
||||||
|
Assert.assertEquals(argsHelloWorldOutput, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun compileScript(
|
||||||
|
scriptFileName: String,
|
||||||
|
scriptTemplate: KClass<out Any>,
|
||||||
|
environment: Map<String, Any?>? = null,
|
||||||
|
runIsolated: Boolean = true,
|
||||||
|
suppressOutput: Boolean = false): Class<*>? =
|
||||||
|
compileScriptImpl("src/test/resources/scripts/" + scriptFileName, KotlinScriptDefinitionFromTemplate(scriptTemplate, null, null, environment), runIsolated, suppressOutput)
|
||||||
|
|
||||||
|
private fun compileScriptImpl(
|
||||||
|
scriptPath: String,
|
||||||
|
scriptDefinition: KotlinScriptDefinition,
|
||||||
|
runIsolated: Boolean,
|
||||||
|
suppressOutput: Boolean): Class<*>?
|
||||||
|
{
|
||||||
|
val paths = PathUtil.getKotlinPathsForDistDirectory()
|
||||||
|
val messageCollector =
|
||||||
|
if (suppressOutput) MessageCollector.NONE
|
||||||
|
else PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false)
|
||||||
|
|
||||||
|
val rootDisposable = Disposer.newDisposable()
|
||||||
|
try {
|
||||||
|
val configuration = CompilerConfiguration().apply {
|
||||||
|
addJvmClasspathRoots(PathUtil.getJdkClassesRoots())
|
||||||
|
val rtJar = System.getProperty("runtimeJar")
|
||||||
|
Assert.assertNotNull(rtJar)
|
||||||
|
addJvmClasspathRoot(File(rtJar))
|
||||||
|
put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
|
||||||
|
addKotlinSourceRoot(scriptPath)
|
||||||
|
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script-util-test")
|
||||||
|
add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition)
|
||||||
|
put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
|
||||||
|
put(JVMConfigurationKeys.INCLUDE_RUNTIME, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||||
|
|
||||||
|
try {
|
||||||
|
return if (runIsolated) KotlinToJVMBytecodeCompiler.compileScript(environment, paths)
|
||||||
|
else KotlinToJVMBytecodeCompiler.compileScript(environment, this.javaClass.classLoader)
|
||||||
|
}
|
||||||
|
catch (e: CompilationException) {
|
||||||
|
messageCollector.report(CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(e),
|
||||||
|
MessageUtil.psiElementToMessageLocation(e.element))
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
catch (t: Throwable) {
|
||||||
|
MessageCollectorUtil.reportException(messageCollector, t)
|
||||||
|
throw t
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Disposer.dispose(rootDisposable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun captureOut(body: () -> Unit): String {
|
||||||
|
val outStream = ByteArrayOutputStream()
|
||||||
|
val prevOut = System.out
|
||||||
|
System.setOut(PrintStream(outStream))
|
||||||
|
body()
|
||||||
|
System.out.flush()
|
||||||
|
System.setOut(prevOut)
|
||||||
|
return outStream.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
println("Hello, world!")
|
||||||
|
|
||||||
|
if (args.isNotEmpty()) {
|
||||||
|
println(args.joinToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
println("done")
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
@file:DependsOn("junit:junit:4.11")
|
||||||
|
|
||||||
|
org.junit.Assert.assertTrue(true)
|
||||||
|
|
||||||
|
println("Hello, world!")
|
||||||
|
|
||||||
|
if (args.isNotEmpty()) {
|
||||||
|
println(args.joinToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
println("done")
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
println("Hello, world!")
|
||||||
|
|
||||||
|
if (bindings.isNotEmpty()) {
|
||||||
|
println(bindings.entries.joinToString { "${it.key} = ${it.value}" })
|
||||||
|
}
|
||||||
|
|
||||||
|
println("done")
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
println("Hello, world!")
|
||||||
|
|
||||||
|
if (bindings.isNotEmpty()) {
|
||||||
|
println(bindings.joinToString { "${it.key} = ${it.value}" })
|
||||||
|
}
|
||||||
|
|
||||||
|
println("done")
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
println("Hello, world!")
|
||||||
|
|
||||||
|
if (args.isNotEmpty()) {
|
||||||
|
println(args.joinToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
println("done")
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
println("Hello, world!")
|
||||||
|
|
||||||
|
if (args.isNotEmpty()) {
|
||||||
|
println(args.joinToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
println("done")
|
||||||
Reference in New Issue
Block a user