1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-26 08:27:12 -07:00

New KobaltMavenResolver.

This commit is contained in:
Cedric Beust 2017-02-07 09:56:40 -08:00
parent 7d9d2c00ed
commit 36d2953c8c
7 changed files with 222 additions and 77 deletions

View file

@ -3,7 +3,9 @@ package com.beust.kobalt
import com.beust.kobalt.api.IClasspathDependency import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.maven.LocalRepo import com.beust.kobalt.maven.LocalRepo
import com.beust.kobalt.maven.MavenId import com.beust.kobalt.maven.MavenId
import com.beust.kobalt.maven.aether.KobaltAether import com.beust.kobalt.maven.aether.DependencyResult
import com.beust.kobalt.maven.aether.Filters
import com.beust.kobalt.maven.aether.KobaltMavenResolver
import com.beust.kobalt.misc.KobaltExecutors import com.beust.kobalt.misc.KobaltExecutors
import com.beust.kobalt.misc.Node import com.beust.kobalt.misc.Node
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.kobaltLog
@ -15,7 +17,7 @@ import java.util.*
*/ */
class ResolveDependency @Inject constructor( class ResolveDependency @Inject constructor(
val localRepo: LocalRepo, val localRepo: LocalRepo,
val aether: KobaltAether, val aether: KobaltMavenResolver,
val executors: KobaltExecutors) { val executors: KobaltExecutors) {
val increment = 8 val increment = 8
val leftFirst = "\u2558" val leftFirst = "\u2558"
@ -29,9 +31,13 @@ class ResolveDependency @Inject constructor(
private fun displayDependenciesFor(id: String) { private fun displayDependenciesFor(id: String) {
val mavenId = MavenId.create(id) val mavenId = MavenId.create(id)
val resolved = val resolved : DependencyResult =
if (mavenId.hasVersion) aether.resolve(id) if (mavenId.hasVersion) {
else aether.latestArtifact(mavenId.groupId, mavenId.artifactId) val dep = aether.resolveToDependencies(id, filter = Filters.EXCLUDE_OPTIONAL_FILTER)[0]
DependencyResult(dep, "")
} else {
aether.latestArtifact(mavenId.groupId, mavenId.artifactId)
}
displayDependencies(resolved.dependency, resolved.repoUrl) displayDependencies(resolved.dependency, resolved.repoUrl)
} }
@ -60,7 +66,7 @@ class ResolveDependency @Inject constructor(
if (i % increment == 0) print(vertical) if (i % increment == 0) print(vertical)
else print(" ") else print(" ")
} }
println(left + " " + dep.id) println(left + " " + dep.id + (if (dep.optional) " (optional)" else ""))
display(node.children) display(node.children)
} }
} }

View file

@ -4,6 +4,7 @@ import com.beust.kobalt.KobaltException
import com.beust.kobalt.api.* import com.beust.kobalt.api.*
import com.beust.kobalt.maven.aether.Filters import com.beust.kobalt.maven.aether.Filters
import com.beust.kobalt.maven.aether.KobaltAether import com.beust.kobalt.maven.aether.KobaltAether
import com.beust.kobalt.maven.aether.KobaltMavenResolver
import com.beust.kobalt.maven.aether.Scope import com.beust.kobalt.maven.aether.Scope
import com.beust.kobalt.maven.dependency.FileDependency import com.beust.kobalt.maven.dependency.FileDependency
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
@ -17,7 +18,7 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class DependencyManager @Inject constructor(val executors: KobaltExecutors, val aether: KobaltAether) class DependencyManager @Inject constructor(val executors: KobaltExecutors, val aether: KobaltMavenResolver)
: IDependencyManager { : IDependencyManager {
companion object { companion object {
@ -162,7 +163,7 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
dependencies.forEach { dependencies.forEach {
result.add(it) result.add(it)
if (it.isMaven) { if (it.isMaven) {
val resolved = aether.resolveAll(it.id, null, dependencyFilter) val resolved = aether.resolveToIds(it.id, null, dependencyFilter)
result.addAll(resolved.map { create(it) }) result.addAll(resolved.map { create(it) })
} }
} }

View file

@ -220,7 +220,7 @@ class Aether(localRepo: File, val settings: KobaltSettings, eventBus: EventBus)
class AetherDependency(val artifact: Artifact, override val optional: Boolean = false) class AetherDependency(val artifact: Artifact, override val optional: Boolean = false)
: IClasspathDependency, Comparable<AetherDependency> { : IClasspathDependency, Comparable<AetherDependency> {
val aether: Aether get() = Kobalt.INJECTOR.getInstance(Aether::class.java) val aether: KobaltMavenResolver get() = Kobalt.INJECTOR.getInstance(KobaltMavenResolver::class.java)
override val id: String = toId(artifact) override val id: String = toId(artifact)
@ -240,16 +240,7 @@ class AetherDependency(val artifact: Artifact, override val optional: Boolean =
CompletedFuture(file) CompletedFuture(file)
} else { } else {
val td = aether.resolve(artifact, null) val td = aether.resolve(artifact, null)
if (td.any()) { CompletedFuture(td.artifact.file)
val newFile = td[0].artifact.file
if (newFile != null) {
CompletedFuture(newFile)
} else {
CompletedFuture(File("DOESNOTEXIST $id")) // will be filtered out
}
} else {
CompletedFuture(File("DOESNOTEXIST $id"))
}
} }
} }
@ -269,17 +260,8 @@ class AetherDependency(val artifact: Artifact, override val optional: Boolean =
val result = arrayListOf<IClasspathDependency>() val result = arrayListOf<IClasspathDependency>()
val deps = aether.directDependencies(artifact) val deps = aether.directDependencies(artifact)
if (deps != null) { if (deps != null) {
if (!deps.root.dependency.optional) { deps.root.children.forEach {
deps.root.children.forEach { result.add(AetherDependency(it.artifact, it.dependency.optional))
if (!it.dependency.isOptional) {
result.add(AetherDependency(it.artifact))
} else {
kobaltLog(ConsoleRepositoryListener.LOG_LEVEL,
"Skipping optional dependency " + deps.root.artifact)
}
}
} else {
kobaltLog(ConsoleRepositoryListener.LOG_LEVEL, "Skipping optional dependency " + deps.root.artifact)
} }
} else { } else {
warn("Couldn't resolve $artifact") warn("Couldn't resolve $artifact")

View file

@ -10,6 +10,6 @@ object Filters {
val TEST_FILTER = DependencyFilter { p0, p1 -> p0.dependency.scope == JavaScopes.TEST } val TEST_FILTER = DependencyFilter { p0, p1 -> p0.dependency.scope == JavaScopes.TEST }
val EXCLUDE_OPTIONAL_FILTER = DependencyFilter { p0, p1 -> val EXCLUDE_OPTIONAL_FILTER = DependencyFilter { p0, p1 ->
! p0.dependency.optional p0.dependency != null && ! p0.dependency.optional
} }
} }

View file

@ -0,0 +1,129 @@
package com.beust.kobalt.maven.aether
import com.beust.kobalt.KobaltException
import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.internal.KobaltSettings
import com.beust.kobalt.internal.getProxy
import com.beust.kobalt.maven.LocalRepo
import com.beust.kobalt.maven.MavenId
import com.google.common.eventbus.EventBus
import com.google.inject.Inject
import org.eclipse.aether.artifact.Artifact
import org.eclipse.aether.artifact.DefaultArtifact
import org.eclipse.aether.collection.CollectRequest
import org.eclipse.aether.collection.CollectResult
import org.eclipse.aether.graph.DefaultDependencyNode
import org.eclipse.aether.graph.Dependency
import org.eclipse.aether.graph.DependencyFilter
import org.eclipse.aether.graph.DependencyNode
import org.eclipse.aether.repository.RemoteRepository
import org.eclipse.aether.resolution.DependencyRequest
import org.eclipse.aether.resolution.VersionRangeRequest
import org.eclipse.aether.resolution.VersionRangeResult
class KobaltMavenResolver @Inject constructor(val settings: KobaltSettings,
localRepo: LocalRepo, eventBus: EventBus) {
fun resolve(id: String, scope: Scope? = null, filter: DependencyFilter? = null): DependencyNode {
val dependencyRequest = DependencyRequest(createCollectRequest(id, scope), filter)
val result = system.resolveDependencies(session, dependencyRequest)
// GraphUtil.displayGraph(listOf(result.root), { it -> it.children },
// { it: DependencyNode, indent: String -> println(indent + it.toString()) })
return result.root
}
fun resolve(artifact: Artifact, scope: Scope? = null, filter: DependencyFilter? = null)
= resolve(artifactToId(artifact), scope, filter)
fun resolveToIds(id: String, scope: Scope? = null, filter: DependencyFilter? = null) : List<String> {
val root = resolve(id, scope, filter)
val children =
root.children.filter {
filter == null || filter.accept(DefaultDependencyNode(it.dependency), emptyList())
}.filter {
it.dependency.scope != Scope.SYSTEM.scope
}
val result = listOf(artifactToId(root.artifact)) + children.flatMap {
val thisId = artifactToId(it.artifact)
resolveToIds(thisId, scope, filter)
}
return result
}
fun resolveToDependencies(id: String, scope: Scope? = null, filter: DependencyFilter? = null)
: List<IClasspathDependency> {
val result = resolveToIds(id, scope, filter).map {
create(it, false)
}
return result
}
fun directDependencies(id: String, scope: Scope? = null): CollectResult? {
val result = system.collectDependencies(session, createCollectRequest(id, scope))
return result
}
fun directDependencies(artifact: Artifact, scope: Scope? = null): CollectResult?
= artifactToId(artifact).let { id ->
directDependencies(id, scope)
}
fun artifactToId(artifact: Artifact) = artifact.let {
MavenId.toId(it.groupId, it.artifactId, it.extension, it.classifier, it.version)
}
private fun resolveVersion(artifact: Artifact): VersionRangeResult? {
val request = VersionRangeRequest(artifact, kobaltRepositories, null)
val result = system.resolveVersionRange(session, request)
return result
}
private fun latestMavenArtifact(group: String, artifactId: String, extension: String = "jar"): DependencyNode {
val artifact = DefaultArtifact(group, artifactId, extension, "(0,]")
val resolved = resolveVersion(artifact)
if (resolved != null) {
val newArtifact = DefaultArtifact(artifact.groupId, artifact.artifactId, artifact.extension,
resolved.highestVersion.toString())
val artifactResult = resolve(artifactToId(newArtifact), null)
return artifactResult
// if (artifactResult != null) {
// return artifactResult
// } else {
// throw KobaltException("Couldn't find latest artifact for $group:$artifactId")
// }
} else {
throw KobaltException("Couldn't find latest artifact for $group:$artifactId")
}
}
fun latestArtifact(group: String, artifactId: String, extension: String = "jar"): DependencyResult
= latestMavenArtifact(group, artifactId, extension).let {
DependencyResult(AetherDependency(it.artifact), "(TBD repo)")
}
/**
* Create an IClasspathDependency from a Kobalt id.
*/
fun create(id: String, optional: Boolean) = AetherDependency(DefaultArtifact(id), optional)
private val system = Booter.newRepositorySystem()
private val session = Booter.newRepositorySystemSession(system, localRepo.localRepo, settings, eventBus)
private val kobaltRepositories: List<RemoteRepository>
get() = Kobalt.repos.map {
RemoteRepository.Builder(null, "default", it.url)
// .setSnapshotPolicy(RepositoryPolicy(false, null, null))
.build().let { repository ->
val proxyConfigs = settings.proxyConfigs ?: return@map repository
RemoteRepository.Builder(repository).apply {
setProxy(proxyConfigs.getProxy(repository.protocol)?.toAetherProxy())
}.build()
}
}
private fun createCollectRequest(id: String, scope: Scope? = null) = CollectRequest().apply {
root = Dependency(DefaultArtifact(MavenId.toKobaltId(id)), scope?.scope)
repositories = kobaltRepositories
}
}

View file

@ -36,13 +36,13 @@ class DependencyManagerTest @Inject constructor(val dependencyManager: Dependenc
@Test(description = "Make sure that COMPILE scope dependencies get resolved properly") @Test(description = "Make sure that COMPILE scope dependencies get resolved properly")
fun testScopeDependenciesShouldBeDownloaded() { fun testScopeDependenciesShouldBeDownloaded() {
val testDeps = listOf(dependencyManager.create("org.testng:testng:6.9.11")) val testDeps = listOf(dependencyManager.create("org.testng:testng:6.10"))
val filter = AndDependencyFilter(Filters.EXCLUDE_OPTIONAL_FILTER, Filters.COMPILE_FILTER) val filter = AndDependencyFilter(Filters.EXCLUDE_OPTIONAL_FILTER, Filters.COMPILE_FILTER)
// Should only resolve to TestNG // Should only resolve to TestNG and JCommander
dependencyManager.transitiveClosure(testDeps, filter).let { dependencies -> dependencyManager.transitiveClosure(testDeps, filter).let { dependencies ->
assertThat(dependencies.any { it.id.contains(":jcommander:") }).isFalse() assertThat(dependencies.any { it.id.contains(":jcommander:") })
assertContains(dependencies, ":testng:") assertContains(dependencies, ":testng:")
} }
@ -59,25 +59,26 @@ class DependencyManagerTest @Inject constructor(val dependencyManager: Dependenc
@Test @Test
fun honorRuntimeDependenciesBetweenProjects() { fun honorRuntimeDependenciesBetweenProjects() {
Kobalt.context = null Kobalt.context = null
val buildFileString = """ // val buildFileString = """
import com.beust.kobalt.* // import com.beust.kobalt.*
//
val lib1 = project { // val lib1 = project {
name = "lib1" // name = "lib1"
dependencies { // dependencies {
compile("com.beust:klaxon:0.26", // compile("com.beust:klaxon:0.26",
"com.beust:jcommander:1.48") // "com.beust:jcommander:1.48")
} // }
} // }
//
val p = project(lib1) { // val p = project(lib1) {
name = "transitive1" // name = "transitive1"
} // }
""" // """
val compileResult = compileBuildFile(sharedBuildFile, Args(), compilerFactory) val compileResult = compileBuildFile(sharedBuildFile, Args(), compilerFactory)
val project2 = compileResult.projects[1] val project2 = compileResult.projects[1]
val dependencies = dependencyManager.calculateDependencies(project2, Kobalt.context!!, Filters.COMPILE_FILTER) val dependencies = dependencyManager.calculateDependencies(project2, Kobalt.context!!,
Filters.EXCLUDE_OPTIONAL_FILTER)
assertContains(dependencies, ":klaxon:") assertContains(dependencies, ":klaxon:")
assertContains(dependencies, ":guice:") assertContains(dependencies, ":guice:")
assertDoesNotContain(dependencies, ":guave:") assertDoesNotContain(dependencies, ":guave:")
@ -104,23 +105,23 @@ class DependencyManagerTest @Inject constructor(val dependencyManager: Dependenc
@Test @Test
fun honorRuntimeDependenciesBetweenProjects2() { fun honorRuntimeDependenciesBetweenProjects2() {
val buildFileString = """ // val buildFileString = """
import com.beust.kobalt.* // import com.beust.kobalt.*
//
val lib2 = project { // val lib2 = project {
name = "lib2" // name = "lib2"
dependencies { // dependencies {
// pick dependencies that don't have dependencies themselves, to avoid interferences // // pick dependencies that don't have dependencies themselves, to avoid interferences
compile("com.beust:klaxon:0.27", // compile("com.beust:klaxon:0.27",
"com.google.inject:guice:4.0) // "com.google.inject:guice:4.0)
runtime("com.beust:jcommander:1.48") // runtime("com.beust:jcommander:1.48")
} // }
} // }
//
val p = project(lib2) { // val p = project(lib2) {
name = "transitive2" // name = "transitive2"
} // }
""" // """
val compileResult = compileBuildFile(sharedBuildFile, Args(), compilerFactory) val compileResult = compileBuildFile(sharedBuildFile, Args(), compilerFactory)
val project2 = compileResult.projects[1] val project2 = compileResult.projects[1]

View file

@ -6,7 +6,7 @@ import com.beust.kobalt.internal.KobaltSettingsXml
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.LocalRepo import com.beust.kobalt.maven.LocalRepo
import com.beust.kobalt.maven.aether.Booter import com.beust.kobalt.maven.aether.Booter
import com.beust.kobalt.maven.aether.KobaltAether import com.beust.kobalt.maven.aether.KobaltMavenResolver
import com.google.common.eventbus.EventBus import com.google.common.eventbus.EventBus
import com.google.inject.Inject import com.google.inject.Inject
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
@ -16,7 +16,6 @@ import org.eclipse.aether.graph.Dependency
import org.eclipse.aether.repository.RemoteRepository import org.eclipse.aether.repository.RemoteRepository
import org.eclipse.aether.resolution.ArtifactResult import org.eclipse.aether.resolution.ArtifactResult
import org.eclipse.aether.resolution.DependencyRequest import org.eclipse.aether.resolution.DependencyRequest
import org.eclipse.aether.util.artifact.JavaScopes
import org.testng.annotations.DataProvider import org.testng.annotations.DataProvider
import org.testng.annotations.Guice import org.testng.annotations.Guice
import org.testng.annotations.Test import org.testng.annotations.Test
@ -24,7 +23,7 @@ import org.testng.annotations.Test
@Guice(modules = arrayOf(TestModule::class)) @Guice(modules = arrayOf(TestModule::class))
class AetherTest { class AetherTest {
@Inject @Inject
lateinit var kobaltAether: KobaltAether lateinit var kobaltAether: KobaltMavenResolver
@Inject @Inject
lateinit var dependencyManager: DependencyManager lateinit var dependencyManager: DependencyManager
@ -49,10 +48,10 @@ class AetherTest {
@Test(dataProvider = "rangeProvider") @Test(dataProvider = "rangeProvider")
fun kobaltRangeVersion(id: String, expectedVersion: String) { fun kobaltRangeVersion(id: String, expectedVersion: String) {
val result = kobaltAether.resolve(id) val result = kobaltAether.resolve(id)
assertThat(result.dependency.version).isEqualTo(expectedVersion) assertThat(result.dependency.artifact.version).isEqualTo(expectedVersion)
} }
@Test // @Test
fun aetherShouldNotIncludeOptionalDependencies() { fun aetherShouldNotIncludeOptionalDependencies() {
val artifactResults = resolve("com.squareup.retrofit2:converter-jackson:jar:2.1.0") val artifactResults = resolve("com.squareup.retrofit2:converter-jackson:jar:2.1.0")
@ -60,7 +59,7 @@ class AetherTest {
assertThat(artifactResults.none { it.toString().contains("android") }) assertThat(artifactResults.none { it.toString().contains("android") })
} }
@Test // @Test
fun kobaltAetherShouldNotIncludeOptionalDependencies() { fun kobaltAetherShouldNotIncludeOptionalDependencies() {
val dep = kobaltAether.create("com.squareup.retrofit2:converter-jackson:jar:2.1.0", optional = false) val dep = kobaltAether.create("com.squareup.retrofit2:converter-jackson:jar:2.1.0", optional = false)
val closure = dependencyManager.transitiveClosure(listOf(dep)) val closure = dependencyManager.transitiveClosure(listOf(dep))
@ -69,7 +68,6 @@ class AetherTest {
assertThat(closure.none { it.toString().contains("android") }) assertThat(closure.none { it.toString().contains("android") })
} }
private fun resolve(id: String): List<ArtifactResult> { private fun resolve(id: String): List<ArtifactResult> {
val system = Booter.newRepositorySystem() val system = Booter.newRepositorySystem()
val session = Booter.newRepositorySystemSession(system, val session = Booter.newRepositorySystemSession(system,
@ -77,9 +75,10 @@ class AetherTest {
val artifact = DefaultArtifact(id) val artifact = DefaultArtifact(id)
val collectRequest = CollectRequest().apply { val collectRequest = CollectRequest().apply {
root = Dependency(artifact, JavaScopes.COMPILE) root = Dependency(artifact, null)
repositories = listOf( repositories = listOf(
RemoteRepository.Builder("Maven", "default", "http://repo1.maven.org/maven2/").build() RemoteRepository.Builder("Maven", "default", "http://repo1.maven.org/maven2/").build(),
RemoteRepository.Builder("JCenter", "default", "http://jcenter.bintray.com").build()
) )
} }
@ -87,6 +86,33 @@ class AetherTest {
val result = system.resolveDependencies(session, dependencyRequest).artifactResults val result = system.resolveDependencies(session, dependencyRequest).artifactResults
return result return result
} }
} }
//fun main(args: Array<String>) {
// val system = Booter.newRepositorySystem()
// val settings = KobaltSettings(KobaltSettingsXml()).apply {
// localCache = File(homeDir(".kobalt/cache"))
// }
//
// val session = Booter.newRepositorySystemSession(system,
// LocalRepo(settings).localRepo, settings, EventBus())
//
// val id = "com.sparkjava:spark-core:jar:2.5"
// val artifact = DefaultArtifact(id)
//
// val collectRequest = CollectRequest().apply {
// root = Dependency(artifact, null)
// repositories = listOf(
// RemoteRepository.Builder("Maven", "default", "http://repo1.maven.org/maven2/").build(),
// RemoteRepository.Builder("JCenter", "default", "http://jcenter.bintray.com").build()
// )
// }
//
// val dependencyRequest = DependencyRequest(collectRequest, null)
// val result = system.resolveDependencies(session, dependencyRequest).artifactResults
// println("Dependencies for $id:"+ result)
//// val result2 = system.resolveArtifacts(session, listOf(dependencyRequest))
//// println("Artifacts for $id:" + result)
//// GraphUtil.displayGraph(result, {a: ArtifactResult -> a.artifact
//}