diff --git a/build.gradle.kts b/build.gradle.kts index caf6b82e..d741f34e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { kotlin("jvm") version "1.2.70" - id("com.github.johnrengelman.plugin-shadow") version "2.0.2" + id("com.github.johnrengelman.shadow") version "2.0.4" } group = "com.github.holgerbrandl.kscript.launcher" @@ -12,6 +12,17 @@ dependencies { compile("com.offbytwo:docopt:0.6.0.20150202") + compile("com.jcabi:jcabi-aether:0.10.1") { + exclude("org.hibernate", "hibernate-validator") + exclude("org.slf4j", "slf4j-api") + exclude("org.slf4j", "jcl-over-slf4j") + exclude("org.apache.commons", "commons-lang3") + exclude("cglib", "cglib") + exclude("org.kuali.maven.wagons", "maven-s3-wagon") + } + compile("org.apache.maven:maven-core:3.0.3") + compile("org.slf4j:slf4j-nop:1.7.25") + testCompile("junit:junit:4.12") testCompile( "io.kotlintest:kotlintest:2.0.7") testCompile(kotlin("script-runtime")) diff --git a/src/main/kotlin/kscript/app/DependencyUtil.kt b/src/main/kotlin/kscript/app/DependencyUtil.kt index d7d9efa0..3781bdfb 100644 --- a/src/main/kotlin/kscript/app/DependencyUtil.kt +++ b/src/main/kotlin/kscript/app/DependencyUtil.kt @@ -1,6 +1,11 @@ package kscript.app -import kscript.app.ShellUtils.requireInPath +import com.jcabi.aether.Aether +import org.sonatype.aether.RepositoryException +import org.sonatype.aether.artifact.Artifact +import org.sonatype.aether.repository.RemoteRepository +import org.sonatype.aether.util.artifact.DefaultArtifact +import org.sonatype.aether.util.artifact.JavaScopes.COMPILE import java.io.File @@ -40,150 +45,72 @@ fun resolveDependencies(depIds: List, customRepos: List = emp } - if (loggingEnabled) System.err.print("[kscript] Resolving dependencies...") - var hasLoggedDownload = false + if (loggingEnabled) infoMsg("[kscript] Resolving dependencies...") - fun runMaven(pom: String, goal: String): Iterable { - val temp = File.createTempFile("__resdeps__temp__", "_pom.xml") - temp.writeText(pom) + try { + val artifacts = resolveDependenciesViaAether(depIds, customRepos, loggingEnabled) + val classPath = artifacts.map { it.file.absolutePath }.joinToString(CP_SEPARATOR_CHAR) - requireInPath("mvn") - - val mavenCmd = if (System.getenv("PATH").run { this != null && contains("cygwin") }) { - // when running with cygwin we need to map the pom path into windows space to work - "mvn -f $(cygpath -w '${temp.absolutePath}') ${goal}" - } else { - "mvn -f ${temp.absolutePath} ${goal}" - } - - return evalBash(mavenCmd, stdoutConsumer = object : StringBuilderConsumer() { - override fun accept(t: String) { - super.accept(t) + if (loggingEnabled) infoMsg("Dependencies resolved") + // Add classpath to cache + DEP_LOOKUP_CACHE_FILE.appendText(depsHash + " " + classPath + "\n") - // log artifact downloading (see https://github.com/holgerbrandl/kscript/issues/23) - if (loggingEnabled && t.startsWith("Downloading: ")) { - if (!hasLoggedDownload) System.err.println() - hasLoggedDownload = true - - System.err.println("[kscript] " + t) - } - } - }).stdout.lines() + // Print the classpath + return classPath + } catch (e: RepositoryException) { + errorMsg("Failed to lookup dependencies. Check dependency locators or file a bug on https://github.com/holgerbrandl/kscript") + errorMsg("Exception: $e") + quit(1) } +} - val pom = buildPom(depIds, customRepos) - val mavenResult = runMaven(pom, "dependency:build-classpath") +fun resolveDependenciesViaAether(depIds: List, customRepos: List, loggingEnabled: Boolean): List { + val jcenter = RemoteRepository("jcenter", "default", "http://jcenter.bintray.com/") + val customRemoteRepos = customRepos.map { it -> RemoteRepository(it.id, "default", it.url) } + val remoteRepos = customRemoteRepos + jcenter + val aether = Aether(remoteRepos, File(System.getProperty("user.home") + "/.m2/repository")) + return depIds.flatMap { + if (loggingEnabled) System.err.print("[kscript] Resolving $it...") - // The following artifacts could not be resolved: log4ja:log4ja:jar:9.8.87, log4j:log4j:jar:9.8.105: Could not + val artifacts = aether.resolve(depIdToArtifact(it), COMPILE) - // Check for errors (e.g. when using non-existing deps resdeps.kts log4j:log4j:1.2.14 org.org.docopt:org.docopt:22.3-MISSING) - mavenResult.filter { it.startsWith("[ERROR]") }.find { it.contains("Could not resolve dependencie") }?.let { - System.err.println("Failed to lookup dependencies. Maven reported the following error:") - System.err.println(it) + if (loggingEnabled) System.err.println("Done") - quit(1) + artifacts } +} +fun depIdToArtifact(depId: String): Artifact { + val regex = Regex("^([^:]*):([^:]*):([^:@]*)(:(.*))?(@(.*))?\$") + val matchResult = regex.find(depId) - // Extract the classpath from the maven output - val classPath = mavenResult.dropWhile { !it.contains("Dependencies classpath:") }.drop(1).firstOrNull() - - if (classPath == null) { - errorMsg("Failed to lookup dependencies. Check dependency locators or file a bug on https://github.com/holgerbrandl/kscript") - System.err.println("[kscript] The error reported by maven was:") - mavenResult.map { it.prependIndent("[kscript] [mvn] ") }.forEach { System.err.println(it) } - - System.err.println("[kscript] Generated pom file was:") - pom.lines() - // .map{it.prependIndent("[kscript] [pom] ")} - .forEach { System.err.println(it) } + if (matchResult == null) { + System.err.println("[ERROR] Invalid dependency locator: '${depId}'. Expected format is groupId:artifactId:version[:classifier][@type]") quit(1) } + val groupId = matchResult.groupValues[1] + val artifactId = matchResult.groupValues[2] + val version = formatVersion(matchResult.groupValues[3]) + val classifier = matchResult.groups[5]?.value + val type = matchResult.groups[7]?.value ?: "jar" - // Add classpath to cache - if (loggingEnabled && !hasLoggedDownload) { - System.err.println("Done") - } - - DEP_LOOKUP_CACHE_FILE.appendText(depsHash + " " + classPath + "\n") - - // Print the classpath - return classPath + return DefaultArtifact(groupId, artifactId, classifier, type, version) } - -internal fun buildPom(depIds: List, customRepos: List): String { - val depTags = depIds.map { - val regex = Regex("^([^:]*):([^:]*):([^:@]*)(:(.*))?(@(.*))?\$") - val matchResult = regex.find(it) - - if (matchResult == null) { - System.err.println("[ERROR] Invalid dependency locator: '${it}'. Expected format is groupId:artifactId:version[:classifier][@type]") - quit(1) - } - - // replace + with open version range for maven - val version = matchResult.groupValues[3].let { - if(it.endsWith("+")) { - "[${it.dropLast(1)},)" - } else { - it - } +fun formatVersion(version: String): String { + // replace + with open version range for maven + return version.let { it -> + if (it.endsWith("+")) { + "[${it.dropLast(1)},)" + } else { + it } - - """ - - ${matchResult.groupValues[1]} - ${matchResult.groupValues[2]} - $version - ${matchResult.groups[5]?.let { "" + it.value + "" } ?: ""} - ${matchResult.groups[7]?.let { "" + it.value + "" } ?: ""} - - """ } - - // see https://github.com/holgerbrandl/kscript/issues/22 - val repoTags = customRepos.map { - """ - - ${it.id} - ${it.url} - - """ - - } - - return """ - - - - 4.0.0 - - kscript - maven_template - 1.0 - - - - jcenter - http://jcenter.bintray.com/ - - ${repoTags.joinToString("\n")} - - - - ${depTags.joinToString("\n")} - - -""" } - // called by unit tests object DependencyUtil { @JvmStatic diff --git a/src/test/kotlin/Tests.kt b/src/test/kotlin/Tests.kt index 38b84b8c..6c12ae1c 100644 --- a/src/test/kotlin/Tests.kt +++ b/src/test/kotlin/Tests.kt @@ -47,48 +47,6 @@ class Tests { // } } - @Test - fun parseAnnotWithTypeAndClassifier() { - val pom = buildPom(listOf("org.javamoney:moneta:1.3", "org.javamoney:moneta:1.3:pom", "org.javamoney:moneta:1.3@pom", "org.javamoney:moneta:1.3+"), emptyList()) - - val expected = "" + - " \n" + - " org.javamoney\n" + - " moneta\n" + - " 1.3\n" + - " \n" + - " \n" + - " \n" + - " \n" + - "\n" + - " \n" + - " org.javamoney\n" + - " moneta\n" + - " 1.3\n" + - " pom\n" + - " \n" + - " \n" + - " \n" + - "\n" + - " \n" + - " org.javamoney\n" + - " moneta\n" + - " 1.3\n" + - " \n" + - " pom\n" + - " " - " \n" + - "\n" + - " \n" + - " org.javamoney\n" + - " moneta\n" + - " [1.3,)\n" + - " \n" + - " \n" + - " \n" + - assertTrue(pom.contains(expected)) - } - @Test fun mixedDependencyCollect() { val lines = listOf(