Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 0 additions & 43 deletions IntegrationTest345.main.kts

This file was deleted.

33 changes: 20 additions & 13 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.github.jengelman.gradle.plugins.shadow.transformers.ComponentsXmlResourceTransformer
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent

val kotlinVersion: String = "1.6.20"
val kotlinVersion: String = "1.6.21"

plugins {
kotlin("jvm") version "1.6.20"
kotlin("jvm") version "1.6.21"
application
id("com.github.johnrengelman.shadow") version "6.1.0"
id("com.github.johnrengelman.shadow") version "7.1.2"
}

repositories {
Expand All @@ -20,51 +21,57 @@ tasks.test {
useJUnitPlatform()

testLogging {
events(TestLogEvent.FAILED); exceptionFormat = TestExceptionFormat.FULL
events(TestLogEvent.FAILED)
exceptionFormat = TestExceptionFormat.FULL
}
}

tasks.withType<Test> {
addTestListener(object : TestListener {
override fun beforeSuite(suite: TestDescriptor) { logger.quiet("\nTest class: ${suite.displayName}") }
override fun beforeSuite(suite: TestDescriptor) {
logger.quiet("\nTest class: ${suite.displayName}")
}

override fun beforeTest(testDescriptor: TestDescriptor) {}
override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) {
logger.quiet("${String.format( "%-60s - %-10s", testDescriptor.name, result.resultType )} ")
logger.quiet("${String.format("%-60s - %-10s", testDescriptor.name, result.resultType)} ")
}

override fun afterSuite(suite: TestDescriptor, result: TestResult) {}
})
}

val launcherClassName: String ="kscript.app.KscriptKt"
val launcherClassName: String = "kscript.app.KscriptKt"

dependencies {
implementation("com.offbytwo:docopt:0.6.0.20150202")

implementation("org.jetbrains.kotlin:kotlin-scripting-common:$kotlinVersion")
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0-RC3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1")

implementation("org.jetbrains.kotlin:kotlin-scripting-common:$kotlinVersion")
implementation("org.jetbrains.kotlin:kotlin-scripting-jvm:$kotlinVersion")
implementation("org.jetbrains.kotlin:kotlin-scripting-dependencies:$kotlinVersion")
implementation("org.jetbrains.kotlin:kotlin-scripting-dependencies-maven:$kotlinVersion")
implementation("org.jetbrains.kotlin:kotlin-scripting-dependencies-maven-all:$kotlinVersion")

implementation("commons-io:commons-io:2.11.0")
implementation("commons-codec:commons-codec:1.15")

implementation("org.slf4j:slf4j-nop:1.7.32")
implementation("org.slf4j:slf4j-nop:1.7.36")

testImplementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.8.2")
testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.25")
testImplementation("io.mockk:mockk:1.12.1")
testImplementation("io.mockk:mockk:1.12.3")

testImplementation(kotlin("script-runtime"))
}

val shadowJar by tasks.getting(ShadowJar::class) {
// set empty string to classifier and version to get predictable jar file name: build/libs/kscript.jar
archiveFileName.set("kscript.jar")
transform(ComponentsXmlResourceTransformer())

doLast {
copy {
from(File(projectDir, "src/kscript"))
Expand All @@ -74,7 +81,7 @@ val shadowJar by tasks.getting(ShadowJar::class) {
}

application {
mainClassName = launcherClassName
mainClass.set(launcherClassName)
}

// Disable standard jar task to avoid building non-shadow jars
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
2 changes: 1 addition & 1 deletion src/main/kotlin/kscript/app/Kscript.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import org.docopt.DocOptWrapper
* @author Marcin Kuszczak
*/

const val KSCRIPT_VERSION = "4.0.0"
const val KSCRIPT_VERSION = "4.0.1"

fun main(args: Array<String>) {
try {
Expand Down
6 changes: 5 additions & 1 deletion src/main/kotlin/kscript/app/KscriptHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import kscript.app.util.Logger.infoMsg
import org.docopt.DocOptWrapper
import java.net.URI


class KscriptHandler(private val config: Config, private val docopt: DocOptWrapper) {

fun handle(userArgs: List<String>) {
Expand All @@ -24,6 +23,11 @@ class KscriptHandler(private val config: Config, private val docopt: DocOptWrapp
devMsg("KScript configuration:")
devMsg(config.toString())

if (Logger.devMode) {
devMsg("Classpath:")
devMsg(System.getProperty("java.class.path"))
}

// create kscript dir if it does not yet exist
val appDir = AppDir(config.kscriptDir)

Expand Down
5 changes: 1 addition & 4 deletions src/main/kotlin/kscript/app/code/Templates.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package kscript.app.code

import kscript.app.model.Dependency
import kscript.app.model.PackageName
import kscript.app.model.Repository
import kscript.app.model.Script
import kscript.app.util.ScriptUtils.dropExtension
import org.intellij.lang.annotations.Language

Expand Down Expand Up @@ -33,7 +30,7 @@ object Templates {
exec java -jar ${'$'}0 "${'$'}@"
""".trimIndent()

fun wrapperForScript(packageName: PackageName, className: String) : String {
fun wrapperForScript(packageName: PackageName, className: String): String {
val classReference = packageName.value + "." + className

return """
Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/kscript/app/model/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ data class Config(
val intellijCommand: String,
val gradleCommand: String,
val kotlinHome: Path?,
val osName: String,
val classPathSeparator: String,
val separatorChar: Char,
val homeDir: Path,
Expand Down
6 changes: 4 additions & 2 deletions src/main/kotlin/kscript/app/model/ConfigBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ class ConfigBuilder internal constructor() {
var intellijCommand: String = System.getenv("KSCRIPT_IDEA_COMMAND") ?: "idea"
var gradleCommand: String = System.getenv("KSCRIPT_GRADLE_COMMAND") ?: "gradle"
var kotlinHome: Path? = (System.getenv("KOTLIN_HOME") ?: guessKotlinHome())?.let { Paths.get(it).absolute() }
var classPathSeparator: String = if (System.getProperty("os.name").lowercase().contains("windows")) ";" else ":"
var separatorChar: Char = File.separatorChar
var osName: String = System.getProperty("os.name")
var homeDir: Path = Paths.get(System.getProperty("user.home")!!)
var classPathSeparator: String = if (osName.lowercase().contains("windows")) ";" else ":"
var separatorChar: Char = File.separatorChar
var kotlinOptsEnvVariable = System.getenv("KSCRIPT_KOTLIN_OPTS") ?: ""
var repositoryUrlEnvVariable = System.getenv("KSCRIPT_REPOSITORY_URL") ?: ""
var repositoryUserEnvVariable = System.getenv("KSCRIPT_REPOSITORY_USER") ?: ""
Expand All @@ -29,6 +30,7 @@ class ConfigBuilder internal constructor() {
intellijCommand,
gradleCommand,
kotlinHome,
osName,
classPathSeparator,
separatorChar,
homeDir,
Expand Down
27 changes: 19 additions & 8 deletions src/main/kotlin/kscript/app/resolver/CommandResolver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@ import kotlin.io.path.absolutePathString
import kotlin.io.path.div

class CommandResolver(private val config: Config, private val script: Script) {
//Syntax for different OS-es:
//LINUX: kotlin -classpath "/home/vagrant/workspace/Kod/Repos/kscript/test:/home/vagrant/.kscript/cache/jar_2ccd53e06b0355d3573a4ae8698398fe/scriplet.jar:/usr/local/sdkman/candidates/kotlin/1.6.21/lib/kotlin-script-runtime.jar" Main_Scriplet
//GIT-BASH: kotlin -classpath "C:\Users\Admin;C:\Users\Admin\.kscript\cache\jar_2ccd53e06b0355d3573a4ae8698398fe\scriplet.jar;C:\Users\Admin\.sdkman\candidates\kotlin\current\lib\kotlin-script-runtime.jar" Main_Scriplet
//CYGWIN: kotlin -classpath "C:\Users\Admin;C:\Users\Admin\.kscript\cache\jar_2ccd53e06b0355d3573a4ae8698398fe\scriplet.jar;C:\Users\Admin\.sdkman\candidates\kotlin\current\lib\kotlin-script-runtime.jar" Main_Scriplet
//WINDOWS: kotlin -classpath "C:\Users\Admin;C:\Users\Admin\.kscript\cache\jar_2ccd53e06b0355d3573a4ae8698398fe\scriplet.jar;C:\Users\Admin\.sdkman\candidates\kotlin\current\lib\kotlin-script-runtime.jar" Main_Scriplet

//Path conversion (Cygwin/mingw): cygpath -u "c:\Users\Admin"; /cygdrive/c/ - Cygwin; /c/ - Mingw
//uname --> CYGWIN_NT-10.0 or MINGW64_NT-10.0-19043
//How to find if mingw/cyg/win (second part): https://stackoverflow.com/questions/40877323/quickly-find-if-java-was-launched-from-windows-cmd-or-cygwin-terminal

fun compileKotlin(jar: Path, dependencies: Set<Path>, filePaths: Set<Path>): String {
val compilerOptsStr = resolveCompilerOpts(script.compilerOpts)
val classpath = resolveClasspath(dependencies)
val files = filePaths.joinToString(" ") { "'${it.absolutePathString()}'" }

val kotlinc =
if (config.kotlinHome != null) (config.kotlinHome / "bin" / "kotlinc").absolutePathString() else "kotlinc"
val kotlinc = resolveKotlinBinary("kotlinc")

return "'$kotlinc' $compilerOptsStr $classpath -d '${jar.absolutePathString()}' $files"
}
Expand All @@ -35,8 +43,7 @@ class CommandResolver(private val config: Config, private val script: Script) {
}

val classpath = resolveClasspath(dependenciesSet)

val kotlin = if (config.kotlinHome != null) (config.kotlinHome / "bin" / "kotlin").absolutePathString() else "kotlin"
val kotlin = resolveKotlinBinary("kotlin")

return "$kotlin $kotlinOptsStr $classpath ${jarArtifact.execClassName} $userArgsStr"
}
Expand All @@ -45,8 +52,7 @@ class CommandResolver(private val config: Config, private val script: Script) {
val compilerOptsStr = resolveCompilerOpts(script.compilerOpts)
val kotlinOptsStr = resolveKotlinOpts(script.kotlinOpts)
val classpath = resolveClasspath(dependencies)

val kotlinc = if (config.kotlinHome != null) (config.kotlinHome / "bin" / "kotlinc").absolutePathString() else "kotlinc"
val kotlinc = resolveKotlinBinary("kotlinc")

return "$kotlinc $compilerOptsStr $kotlinOptsStr $classpath"
}
Expand All @@ -60,10 +66,15 @@ class CommandResolver(private val config: Config, private val script: Script) {
}

private fun resolveKotlinOpts(kotlinOpts: Set<KotlinOpt>) = kotlinOpts.joinToString(" ") { it.value }

private fun resolveCompilerOpts(compilerOpts: Set<CompilerOpt>) = compilerOpts.joinToString(" ") { it.value }

private fun resolveUserArgs(userArgs: List<String>) =
userArgs.joinToString(" ") { "\"${it.replace("\"", "\\\"")}\"" }

private fun resolveClasspath(dependencies: Set<Path>) = if (dependencies.isEmpty()) ""
else "-classpath " + dependencies.joinToString(config.classPathSeparator) { "'${it.absolutePathString()}'" }
else "-classpath \"" + dependencies.joinToString(config.classPathSeparator) { it.absolutePathString() } + "\""

private fun resolveKotlinBinary(binary: String) =
if (config.kotlinHome != null) (config.kotlinHome / "bin" / binary).absolutePathString() else binary
}
25 changes: 19 additions & 6 deletions src/main/kotlin/kscript/app/resolver/DependencyResolver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,16 @@ class DependencyResolver(private val customRepos: Set<Repository>) {
devMsg("Resolved in: ${System.currentTimeMillis() - start}")
resolved
}
}.map {
it.valueOr {
throw IllegalStateException("Failed while connecting to the server. Check the connection (http/https, port, proxy, credentials, etc.) of your maven dependency locators. If you suspect this is a bug, you can create an issue on https://github.com/holgerbrandl/kscript" + it.reports.joinToString(
"\n"
) { it.exception?.toString() ?: it.message }, it.reports.find { it.exception != null }?.exception
)
}.asSequence().map { result ->
result.valueOr { failure ->
val details = failure.reports.joinToString("\n") { scriptDiagnostic ->
scriptDiagnostic.exception?.stackTraceToString() ?: scriptDiagnostic.message
}

val firstException =
failure.reports.find { scriptDiagnostic -> scriptDiagnostic.exception != null }?.exception

throw IllegalStateException(exceptionMessage + "\n" + details, firstException)
}
}.flatten().map {
it.toPath()
Expand All @@ -61,4 +65,13 @@ class DependencyResolver(private val customRepos: Set<Repository>) {

return resolvedDependencies
}

companion object {
//@formatter:off
private const val exceptionMessage =
"Failed while connecting to the server. Check the connection (http/https, port, proxy, credentials, etc.)" +
"of your maven dependency locators. If you suspect this is a bug, " +
"you can create an issue on https://github.com/holgerbrandl/kscript"
//@formatter:on
}
}
10 changes: 6 additions & 4 deletions src/test/kotlin/kscript/app/parser/LineParserTest.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package kscript.app.parser

import assertk.assertThat
import assertk.assertions.*
import assertk.assertions.containsExactly
import assertk.assertions.containsExactlyInAnyOrder
import assertk.assertions.isFailure
import assertk.assertions.messageContains
import kscript.app.model.*
import kscript.app.parser.LineParser.parseDependency
import kscript.app.parser.LineParser.parseEntry
import kscript.app.parser.LineParser.parseImport
import kscript.app.parser.LineParser.parseKotlinOpts
import kscript.app.parser.LineParser.parseRepository
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
Expand Down Expand Up @@ -45,11 +47,11 @@ class LineParserTest {
" //DEPS $listWithoutQuotesStrangelyFormatted",
)) {
println("Case: '$line'")
assertThat(parseDependency(line)).containsExactlyInAnyOrder(*list.map { Dependency(it.trim()) }.toTypedArray())
assertThat(parseDependency(line)).containsExactlyInAnyOrder(*list.map { Dependency(it.trim()) }
.toTypedArray())
}
}


@ParameterizedTest
@MethodSource("dynamicDependencies")
fun `Dependency parsing - dynamic dependencies`(list: List<String>) {
Expand Down
6 changes: 6 additions & 0 deletions test/resources/depends_on_klaxon.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@file:DependsOn("com.beust:klaxon:5.5")

import com.beust.klaxon.Parser
val p = Parser()

println("Successfully resolved klaxon")
10 changes: 6 additions & 4 deletions test/test_suite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,6 @@ if start_suite $SUITE $REQUESTED_SUITES; then
assert "kscript https://raw.githubusercontent.com/holgerbrandl/kscript/master/test/resources/url_test.kts" "I came from the internet"
assert "kscript https://git.io/fxHBv" "main was called"

## there are some dependencies which are not jar, but maybe pom, aar, ..
## make sure they work, too
assert "kscript ${PROJECT_DIR}/test/resources/depends_on_with_type.kts" "getBigDecimal(1L): 1"

# repeated compilation of buggy same script should end up in error again
assert_raises "kscript '1-'; kscript '1-'" 1

Expand Down Expand Up @@ -145,6 +141,9 @@ fi
########################################################################################################################
SUITE="annotation_driven_configuration"
if start_suite $SUITE $REQUESTED_SUITES; then
## there are some dependencies which are not jar, but maybe pom, aar,... make sure they work, too
assert "kscript ${PROJECT_DIR}/test/resources/depends_on_with_type.kts" "getBigDecimal(1L): 1"

# make sure that @file:DependsOn is parsed correctly
assert "kscript ${PROJECT_DIR}/test/resources/depends_on_annot.kts" "kscript with annotations rocks!"

Expand All @@ -161,6 +160,9 @@ if start_suite $SUITE $REQUESTED_SUITES; then
# make sure that @file:MavenRepository is parsed correctly
assert "kscript ${PROJECT_DIR}/test/resources/script_with_compile_flags.kts" "hoo_ray"

## Ensure dependencies are solved correctly #345
rm -rf ~/.m2/repository/com/beust
assert "kscript ${PROJECT_DIR}/test/resources/depends_on_klaxon.kts" "Successfully resolved klaxon"

assert_end "$SUITE"
fi
Expand Down