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
13 changes: 12 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"))
Expand Down
171 changes: 49 additions & 122 deletions src/main/kotlin/kscript/app/DependencyUtil.kt
Original file line number Diff line number Diff line change
@@ -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


Expand Down Expand Up @@ -40,150 +45,72 @@ fun resolveDependencies(depIds: List<String>, customRepos: List<MavenRepo> = 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<String> {
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<String>, customRepos: List<MavenRepo>, loggingEnabled: Boolean): List<Artifact> {
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<String>, customRepos: List<MavenRepo>): 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
}

"""
<dependency>
<groupId>${matchResult.groupValues[1]}</groupId>
<artifactId>${matchResult.groupValues[2]}</artifactId>
<version>$version</version>
${matchResult.groups[5]?.let { "<classifier>" + it.value + "</classifier>" } ?: ""}
${matchResult.groups[7]?.let { "<type>" + it.value + "</type>" } ?: ""}
</dependency>
"""
}

// see https://github.com/holgerbrandl/kscript/issues/22
val repoTags = customRepos.map {
"""
<repository>
<id>${it.id}</id>
<url>${it.url}</url>
</repository>
"""

}

return """
<?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>kscript</groupId>
<artifactId>maven_template</artifactId>
<version>1.0</version>

<repositories>
<repository>
<id>jcenter</id>
<url>http://jcenter.bintray.com/</url>
</repository>
${repoTags.joinToString("\n")}
</repositories>

<dependencies>
${depTags.joinToString("\n")}
</dependencies>
</project>
"""
}


// called by unit tests
object DependencyUtil {
@JvmStatic
Expand Down
42 changes: 0 additions & 42 deletions src/test/kotlin/Tests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "" +
" <dependency>\n" +
" <groupId>org.javamoney</groupId>\n" +
" <artifactId>moneta</artifactId>\n" +
" <version>1.3</version>\n" +
" \n" +
" \n" +
" </dependency>\n" +
" \n" +
"\n" +
" <dependency>\n" +
" <groupId>org.javamoney</groupId>\n" +
" <artifactId>moneta</artifactId>\n" +
" <version>1.3</version>\n" +
" <classifier>pom</classifier>\n" +
" \n" +
" </dependency>\n" +
" \n" +
"\n" +
" <dependency>\n" +
" <groupId>org.javamoney</groupId>\n" +
" <artifactId>moneta</artifactId>\n" +
" <version>1.3</version>\n" +
" \n" +
" <type>pom</type>\n" +
" </dependency>"
" \n" +
"\n" +
" <dependency>\n" +
" <groupId>org.javamoney</groupId>\n" +
" <artifactId>moneta</artifactId>\n" +
" <version>[1.3,)</version>\n" +
" \n" +
" \n" +
" </dependency>\n" +
assertTrue(pom.contains(expected))
}

@Test
fun mixedDependencyCollect() {
val lines = listOf(
Expand Down