Add support for custom script compilation and execution to maven plugin, add simple test, relevant refactorings on the compiler side
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.cli.common
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KParameter
|
||||
import kotlin.reflect.KType
|
||||
|
||||
fun tryConstructScriptClass(scriptClass: Class<*>, scriptArgs: List<String>): Any? {
|
||||
|
||||
fun convertPrimitive(type: KType?, arg: String): Any? =
|
||||
when (type?.classifier) {
|
||||
String::class -> arg
|
||||
Int::class -> arg.toInt()
|
||||
Long::class -> arg.toLong()
|
||||
Short::class -> arg.toShort()
|
||||
Byte::class -> arg.toByte()
|
||||
Char::class -> arg[0]
|
||||
Float::class -> arg.toFloat()
|
||||
Double::class -> arg.toDouble()
|
||||
Boolean::class -> arg.toBoolean()
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun convertArray(type: KType?, args: List<String>): Any? =
|
||||
when (type?.classifier) {
|
||||
String::class -> args.toTypedArray()
|
||||
Int::class -> args.map(String::toInt).toTypedArray()
|
||||
Long::class -> args.map(String::toLong).toTypedArray()
|
||||
Short::class -> args.map(String::toShort).toTypedArray()
|
||||
Byte::class -> args.map(String::toByte).toTypedArray()
|
||||
Char::class -> args.map { it[0] }.toTypedArray()
|
||||
Float::class -> args.map(String::toFloat).toTypedArray()
|
||||
Double::class -> args.map(String::toDouble).toTypedArray()
|
||||
Boolean::class -> args.map(String::toBoolean).toTypedArray()
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun foldingFunc(state: Pair<List<Any>, List<String>?>, par: KParameter): Pair<List<Any>, List<String>?> {
|
||||
state.second?.let { scriptArgsLeft ->
|
||||
try {
|
||||
if (scriptArgsLeft.isNotEmpty()) {
|
||||
val primArgCandidate = convertPrimitive(par.type, scriptArgsLeft.first())
|
||||
if (primArgCandidate != null)
|
||||
return@foldingFunc Pair(state.first + primArgCandidate, scriptArgsLeft.drop(1))
|
||||
}
|
||||
|
||||
if ((par.type.classifier as? KClass<*>)?.qualifiedName == Array<Any>::class.qualifiedName) {
|
||||
val arrCompType = par.type.arguments.getOrNull(0)?.type
|
||||
val arrayArgCandidate = convertArray(arrCompType, scriptArgsLeft)
|
||||
if (arrayArgCandidate != null)
|
||||
return@foldingFunc Pair(state.first + arrayArgCandidate, null)
|
||||
}
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
} // just skips to return below
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
try {
|
||||
return scriptClass.getConstructor(Array<String>::class.java).newInstance(*arrayOf<Any>(scriptArgs.toTypedArray()))
|
||||
}
|
||||
catch (e: java.lang.NoSuchMethodException) {
|
||||
for (ctor in scriptClass.kotlin.constructors) {
|
||||
val (ctorArgs, scriptArgsLeft) = ctor.parameters.fold(Pair(emptyList<Any>(), scriptArgs), ::foldingFunc)
|
||||
if (ctorArgs.size <= ctor.parameters.size && (scriptArgsLeft == null || scriptArgsLeft.isEmpty())) {
|
||||
val argsMap = ctorArgs.zip(ctor.parameters) { a, p -> Pair(p, a) }.toMap()
|
||||
try {
|
||||
return ctor.callBy(argsMap)
|
||||
}
|
||||
catch (e: Exception) { // TODO: find the exact exception type thrown then callBy fails
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
): KotlinCoreEnvironment? {
|
||||
|
||||
val scriptResolverEnv = hashMapOf<String, Any?>()
|
||||
configureScriptDefinitions(arguments, configuration, messageCollector, scriptResolverEnv)
|
||||
configureScriptDefinitions(arguments.scriptTemplates, configuration, messageCollector, scriptResolverEnv)
|
||||
if (!messageCollector.hasErrors()) {
|
||||
val environment = createCoreEnvironment(rootDisposable, configuration)
|
||||
if (!messageCollector.hasErrors()) {
|
||||
@@ -248,50 +248,6 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun configureScriptDefinitions(arguments: K2JVMCompilerArguments,
|
||||
configuration: CompilerConfiguration,
|
||||
messageCollector: MessageCollector,
|
||||
scriptResolverEnv: HashMap<String, Any?>) {
|
||||
val classpath = configuration.getList(JVMConfigurationKeys.CONTENT_ROOTS).filterIsInstance(JvmClasspathRoot::class.java).mapNotNull { it.file }
|
||||
// TODO: consider using escaping to allow kotlin escaped names in class names
|
||||
if (arguments.scriptTemplates != null && arguments.scriptTemplates.isNotEmpty()) {
|
||||
val classloader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), this.javaClass.classLoader)
|
||||
var hasErrors = false
|
||||
for (template in arguments.scriptTemplates) {
|
||||
try {
|
||||
val cls = classloader.loadClass(template)
|
||||
val def = KotlinScriptDefinitionFromTemplate(cls.kotlin, null, null, scriptResolverEnv)
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, def)
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.INFO,
|
||||
"Added script definition $template to configuration: files pattern = \"${def.scriptFilePattern}\", resolver = ${def.resolver?.javaClass?.name}",
|
||||
CompilerMessageLocation.NO_LOCATION
|
||||
)
|
||||
}
|
||||
catch (ex: ClassNotFoundException) {
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.ERROR, "Cannot find script definition template class $template", CompilerMessageLocation.NO_LOCATION
|
||||
)
|
||||
hasErrors = true
|
||||
}
|
||||
catch (ex: Exception) {
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.ERROR, "Error processing script definition template $template: ${ex.message}", CompilerMessageLocation.NO_LOCATION
|
||||
)
|
||||
hasErrors = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (hasErrors) {
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.LOGGING, "(Classpath used for templates loading: $classpath)", CompilerMessageLocation.NO_LOCATION
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
}
|
||||
|
||||
private fun createCoreEnvironment(rootDisposable: Disposable, configuration: CompilerConfiguration): KotlinCoreEnvironment {
|
||||
val result = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||
|
||||
@@ -431,6 +387,50 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
}
|
||||
return OK
|
||||
}
|
||||
|
||||
fun configureScriptDefinitions(scriptTemplates: Array<String>?,
|
||||
configuration: CompilerConfiguration,
|
||||
messageCollector: MessageCollector,
|
||||
scriptResolverEnv: HashMap<String, Any?>) {
|
||||
val classpath = configuration.getList(JVMConfigurationKeys.CONTENT_ROOTS).filterIsInstance(JvmClasspathRoot::class.java).mapNotNull { it.file }
|
||||
// TODO: consider using escaping to allow kotlin escaped names in class names
|
||||
if (scriptTemplates != null && scriptTemplates.isNotEmpty()) {
|
||||
val classloader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), Thread.currentThread().contextClassLoader)
|
||||
var hasErrors = false
|
||||
for (template in scriptTemplates) {
|
||||
try {
|
||||
val cls = classloader.loadClass(template)
|
||||
val def = KotlinScriptDefinitionFromTemplate(cls.kotlin, null, null, scriptResolverEnv)
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, def)
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.INFO,
|
||||
"Added script definition $template to configuration: files pattern = \"${def.scriptFilePattern}\", resolver = ${def.resolver?.javaClass?.name}",
|
||||
CompilerMessageLocation.NO_LOCATION
|
||||
)
|
||||
}
|
||||
catch (ex: ClassNotFoundException) {
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.ERROR, "Cannot find script definition template class $template", CompilerMessageLocation.NO_LOCATION
|
||||
)
|
||||
hasErrors = true
|
||||
}
|
||||
catch (ex: Exception) {
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.ERROR, "Error processing script definition template $template: ${ex.message}", CompilerMessageLocation.NO_LOCATION
|
||||
)
|
||||
hasErrors = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (hasErrors) {
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.LOGGING, "(Classpath used for templates loading: $classpath)", CompilerMessageLocation.NO_LOCATION
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-78
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.messages.*
|
||||
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll
|
||||
import org.jetbrains.kotlin.cli.common.tryConstructScriptClass
|
||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
||||
import org.jetbrains.kotlin.cli.jvm.config.*
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||
@@ -66,10 +67,6 @@ import java.lang.reflect.InvocationTargetException
|
||||
import java.net.URLClassLoader
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.jar.Attributes
|
||||
import kotlin.reflect.KParameter
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.defaultType
|
||||
import kotlin.reflect.jvm.javaType
|
||||
|
||||
object KotlinToJVMBytecodeCompiler {
|
||||
|
||||
@@ -230,7 +227,7 @@ object KotlinToJVMBytecodeCompiler {
|
||||
|
||||
try {
|
||||
try {
|
||||
tryConstructClass(scriptClass, scriptArgs)
|
||||
tryConstructScriptClass(scriptClass, scriptArgs)
|
||||
?: throw RuntimeException("unable to find appropriate constructor for class ${scriptClass.name} accepting arguments $scriptArgs\n")
|
||||
}
|
||||
finally {
|
||||
@@ -295,78 +292,6 @@ object KotlinToJVMBytecodeCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun tryConstructClassPub(scriptClass: Class<*>, scriptArgs: List<String>): Any? = tryConstructClass(scriptClass, scriptArgs)
|
||||
|
||||
private fun tryConstructClass(scriptClass: Class<*>, scriptArgs: List<String>): Any? {
|
||||
|
||||
fun convertPrimitive(type: KType?, arg: String): Any? =
|
||||
when (type) {
|
||||
String::class.defaultType -> arg
|
||||
Int::class.defaultType -> arg.toInt()
|
||||
Long::class.defaultType -> arg.toLong()
|
||||
Short::class.defaultType -> arg.toShort()
|
||||
Byte::class.defaultType -> arg.toByte()
|
||||
Char::class.defaultType -> arg[0]
|
||||
Float::class.defaultType -> arg.toFloat()
|
||||
Double::class.defaultType -> arg.toDouble()
|
||||
Boolean::class.defaultType -> arg.toBoolean()
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun convertArray(type: KType?, args: List<String>): Any? =
|
||||
when (type) {
|
||||
String::class.defaultType -> args.toTypedArray()
|
||||
Int::class.defaultType -> args.map { it.toInt() }.toTypedArray()
|
||||
Long::class.defaultType -> args.map { it.toLong() }.toTypedArray()
|
||||
Short::class.defaultType -> args.map { it.toShort() }.toTypedArray()
|
||||
Byte::class.defaultType -> args.map { it.toByte() }.toTypedArray()
|
||||
Char::class.defaultType -> args.map { it[0] }.toTypedArray()
|
||||
Float::class.defaultType -> args.map { it.toFloat() }.toTypedArray()
|
||||
Double::class.defaultType -> args.map { it.toDouble() }.toTypedArray()
|
||||
Boolean::class.defaultType -> args.map { it.toBoolean() }.toTypedArray()
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun foldingFunc(state: Pair<List<Any>, List<String>?>, par: KParameter): Pair<List<Any>, List<String>?> {
|
||||
state.second?.let { scriptArgsLeft ->
|
||||
try {
|
||||
if (scriptArgsLeft.isNotEmpty()) {
|
||||
val primArgCandidate = convertPrimitive(par.type, scriptArgsLeft.first())
|
||||
if (primArgCandidate != null)
|
||||
return@foldingFunc Pair(state.first + primArgCandidate, scriptArgsLeft.drop(1))
|
||||
}
|
||||
|
||||
val arrCompType = (par.type.javaType as? Class<*>)?.componentType?.kotlin?.defaultType
|
||||
val arrayArgCandidate = convertArray(arrCompType, scriptArgsLeft)
|
||||
if (arrayArgCandidate != null)
|
||||
return@foldingFunc Pair(state.first + arrayArgCandidate, null)
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
} // just skips to return below
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
try {
|
||||
return scriptClass.getConstructor(Array<String>::class.java).newInstance(*arrayOf<Any>(scriptArgs.toTypedArray()))
|
||||
}
|
||||
catch (e: java.lang.NoSuchMethodException) {
|
||||
for (ctor in scriptClass.kotlin.constructors) {
|
||||
val (ctorArgs, scriptArgsLeft) = ctor.parameters.fold(Pair(emptyList<Any>(), scriptArgs), ::foldingFunc)
|
||||
if (ctorArgs.size <= ctor.parameters.size && (scriptArgsLeft == null || scriptArgsLeft.isEmpty())) {
|
||||
val argsMap = ctorArgs.zip(ctor.parameters) { a, p -> Pair(p, a) }.toMap()
|
||||
try {
|
||||
return ctor.callBy(argsMap)
|
||||
}
|
||||
catch (e: Exception) { // TODO: find the exact exception type thrown then callBy fails
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun compileScript(environment: KotlinCoreEnvironment, paths: KotlinPaths): Class<*>? =
|
||||
compileScript(environment,
|
||||
{
|
||||
@@ -481,7 +406,7 @@ object KotlinToJVMBytecodeCompiler {
|
||||
configuration,
|
||||
GenerationState.GenerateClassFilter.GENERATE_ALL,
|
||||
module?.let(::TargetId),
|
||||
module?.let { it.getModuleName() },
|
||||
module?.let(Module::getModuleName),
|
||||
module?.let { File(it.getOutputDirectory()) },
|
||||
createOutputFilesFlushingCallbackIfPossible(configuration)
|
||||
)
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.scripts
|
||||
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.common.tryConstructScriptClass
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
|
||||
@@ -43,7 +44,7 @@ class ScriptTest : KtUsefulTestCase() {
|
||||
val aClass = compileScript("fib_std.kts", StandardScriptDefinition)
|
||||
Assert.assertNotNull(aClass)
|
||||
val out = captureOut {
|
||||
val anObj = KotlinToJVMBytecodeCompiler.tryConstructClassPub(aClass!!, listOf("4", "comment"))
|
||||
val anObj = tryConstructScriptClass(aClass!!, listOf("4", "comment"))
|
||||
Assert.assertNotNull(anObj)
|
||||
}
|
||||
Assert.assertEquals(NUM_4_LINE + " (comment)" + FIB_SCRIPT_OUTPUT_TAIL, out)
|
||||
@@ -54,7 +55,7 @@ class ScriptTest : KtUsefulTestCase() {
|
||||
val aClass = compileScript("fib_std.kts", StandardScriptDefinition)
|
||||
Assert.assertNotNull(aClass)
|
||||
val out = captureOut {
|
||||
val anObj = KotlinToJVMBytecodeCompiler.tryConstructClassPub(aClass!!, emptyList())
|
||||
val anObj = tryConstructScriptClass(aClass!!, emptyList())
|
||||
Assert.assertNotNull(anObj)
|
||||
}
|
||||
Assert.assertEquals(NUM_4_LINE + " (none)" + FIB_SCRIPT_OUTPUT_TAIL, out)
|
||||
@@ -67,7 +68,7 @@ class ScriptTest : KtUsefulTestCase() {
|
||||
val aClass = compileScript("fib_std.kts", StandardScriptDefinition, saveClassesDir = tmpdir)
|
||||
Assert.assertNotNull(aClass)
|
||||
val out1 = captureOut {
|
||||
val anObj = KotlinToJVMBytecodeCompiler.tryConstructClassPub(aClass!!, emptyList())
|
||||
val anObj = tryConstructScriptClass(aClass!!, emptyList())
|
||||
Assert.assertNotNull(anObj)
|
||||
}
|
||||
Assert.assertEquals(NUM_4_LINE + " (none)" + FIB_SCRIPT_OUTPUT_TAIL, out1)
|
||||
@@ -75,7 +76,7 @@ class ScriptTest : KtUsefulTestCase() {
|
||||
val aClassSaved = savedClassLoader.loadClass(aClass.name)
|
||||
Assert.assertNotNull(aClassSaved)
|
||||
val out2 = captureOut {
|
||||
val anObjSaved = KotlinToJVMBytecodeCompiler.tryConstructClassPub(aClassSaved!!, emptyList())
|
||||
val anObjSaved = tryConstructScriptClass(aClassSaved!!, emptyList())
|
||||
Assert.assertNotNull(anObjSaved)
|
||||
}
|
||||
Assert.assertEquals(NUM_4_LINE + " (none)" + FIB_SCRIPT_OUTPUT_TAIL, out2)
|
||||
@@ -134,4 +135,4 @@ class ScriptTest : KtUsefulTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
class TestParamClass(val memberNum: Int)
|
||||
class TestParamClass(@Suppress("unused") val memberNum: Int)
|
||||
@@ -23,6 +23,16 @@
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-script-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-js-library</artifactId>
|
||||
@@ -75,6 +85,7 @@
|
||||
<!--This could speed up test by providing local repo as remote repo for test but might be tricky on different OS-->
|
||||
<!--<settingsFile>src/it/settings.xml</settingsFile>-->
|
||||
<localRepositoryPath>local-repo</localRepositoryPath>
|
||||
<showErrors>true</showErrors>
|
||||
<postBuildHookScript>verify</postBuildHookScript>
|
||||
<streamLogs>false</streamLogs>
|
||||
<invokerPropertiesFile>invoker.properties</invokerPropertiesFile>
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>test-executeKotlinScriptFile</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-script-util</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<kotlin.compiler.scriptTemplates>org.jetbrains.kotlin.script.util.StandardScript</kotlin.compiler.scriptTemplates>
|
||||
<kotlin.compiler.scriptClasspath>${org.jetbrains.kotlin:kotlin-script-util:jar}</kotlin.compiler.scriptClasspath>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
||||
<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>${kotlin.version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-script-util</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>execute-kotlin-script</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>script</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<scriptFile>script.kts</scriptFile>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
|
||||
if (!args.isEmpty())
|
||||
println("some args passed")
|
||||
|
||||
println("Hello from Kotlin script file!")
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
source(new File(basedir, "../../../verify-common.bsh").getAbsolutePath());
|
||||
|
||||
assertBuildLogHasLine("Hello from Kotlin script file!")
|
||||
+19
-14
@@ -35,6 +35,7 @@ import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.component.repository.ComponentDependency;
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
|
||||
import org.jetbrains.kotlin.cli.common.ReflectionUtilKt;
|
||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler;
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
|
||||
@@ -49,16 +50,14 @@ import org.jetbrains.kotlin.config.KotlinSourceRoot;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.KtScript;
|
||||
import org.jetbrains.kotlin.script.StandardScriptDefinition;
|
||||
import org.jetbrains.kotlin.utils.PathUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -108,6 +107,15 @@ public class ExecuteKotlinScriptMojo extends AbstractMojo {
|
||||
@Parameter(defaultValue = "${localRepository}", required = true, readonly = true)
|
||||
private ArtifactRepository localRepository;
|
||||
|
||||
@Parameter(property = "kotlin.compiler.scriptTemplates", required = false, readonly = false)
|
||||
protected List<String> scriptTemplates;
|
||||
|
||||
@Parameter(property = "kotlin.compiler.scriptArguments", required = false, readonly = false)
|
||||
protected List<String> scriptArguments;
|
||||
|
||||
@Parameter(property = "kotlin.compiler.scriptClasspath", required = false, readonly = false)
|
||||
protected List<String> scriptClasspath;
|
||||
|
||||
@Component
|
||||
private ArtifactHandlerManager artifactHandlerManager;
|
||||
|
||||
@@ -176,7 +184,8 @@ public class ExecuteKotlinScriptMojo extends AbstractMojo {
|
||||
|
||||
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, new KotlinSourceRoot(scriptFile.getAbsolutePath()));
|
||||
configuration.put(CommonConfigurationKeys.MODULE_NAME, JvmAbi.DEFAULT_MODULE_NAME);
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition.INSTANCE);
|
||||
|
||||
K2JVMCompiler.Companion.configureScriptDefinitions(scriptTemplates.toArray(new String[scriptTemplates.size()]), configuration, messageCollector, new HashMap<String, Object>());
|
||||
|
||||
KotlinCoreEnvironment environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
|
||||
|
||||
@@ -192,17 +201,9 @@ public class ExecuteKotlinScriptMojo extends AbstractMojo {
|
||||
|
||||
try {
|
||||
Class<?> klass = classLoader.loadClass(nameForScript.asString());
|
||||
Constructor<?> constructor = klass.getConstructor(String[].class);
|
||||
ExecuteKotlinScriptMojo.INSTANCE = this;
|
||||
constructor.newInstance(new Object[]{new String[]{}});
|
||||
} catch (InstantiationException e) {
|
||||
throw new ScriptExecutionException(scriptFile, "internal error", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ScriptExecutionException(scriptFile, "script threw an exception", e.getCause());
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new ScriptExecutionException(scriptFile, "internal error", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ScriptExecutionException(scriptFile, "internal error", e);
|
||||
if (ReflectionUtilKt.tryConstructScriptClass(klass, scriptArguments) == null)
|
||||
throw new ScriptExecutionException(scriptFile, "unable to construct script");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ScriptExecutionException(scriptFile, "internal error", e);
|
||||
}
|
||||
@@ -221,6 +222,10 @@ public class ExecuteKotlinScriptMojo extends AbstractMojo {
|
||||
|
||||
deps.addAll(getThisPluginDependencies());
|
||||
|
||||
for (String cp: scriptClasspath) {
|
||||
deps.add(new File(cp));
|
||||
}
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
|
||||
+7
@@ -65,6 +65,9 @@ public class K2JVMCompileMojo extends KotlinCompileMojoBase<K2JVMCompilerArgumen
|
||||
@Parameter(property = "kotlin.compiler.jdkHome", required = false, readonly = false)
|
||||
protected String jdkHome;
|
||||
|
||||
@Parameter(property = "kotlin.compiler.scriptTemplates", required = false, readonly = false)
|
||||
protected List<String> scriptTemplates;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected K2JVMCompiler createCompiler() {
|
||||
@@ -114,5 +117,9 @@ public class K2JVMCompileMojo extends KotlinCompileMojoBase<K2JVMCompilerArgumen
|
||||
getLog().info("Overriding JDK home path with: " + jdkHome);
|
||||
arguments.jdkHome = jdkHome;
|
||||
}
|
||||
|
||||
if (scriptTemplates != null && !scriptTemplates.isEmpty()) {
|
||||
arguments.scriptTemplates = scriptTemplates.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user