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

Fix optional dependencies problem.

This commit is contained in:
Cedric Beust 2017-02-01 12:58:59 -08:00
parent 38bb53387e
commit ae450e4cbc
15 changed files with 323 additions and 127 deletions

View file

@ -26,7 +26,7 @@ object Versions {
val okio = "1.6.0" val okio = "1.6.0"
val retrofit = "2.1.0" val retrofit = "2.1.0"
val gson = "2.6.2" val gson = "2.6.2"
val aether = "1.1.0" val aether = "1.0.0.v20140518"
val sonatypeAether = "1.13.1" val sonatypeAether = "1.13.1"
val maven = "3.3.9" val maven = "3.3.9"
} }
@ -102,6 +102,7 @@ val kobaltPluginApi = project {
"org.slf4j:slf4j-nop:1.6.0", "org.slf4j:slf4j-nop:1.6.0",
"org.eclipse.aether:aether-spi:${Versions.aether}", "org.eclipse.aether:aether-spi:${Versions.aether}",
"org.eclipse.aether:aether-util:${Versions.aether}",
"org.eclipse.aether:aether-impl:${Versions.aether}", "org.eclipse.aether:aether-impl:${Versions.aether}",
"org.eclipse.aether:aether-connector-basic:${Versions.aether}", "org.eclipse.aether:aether-connector-basic:${Versions.aether}",
"org.eclipse.aether:aether-transport-file:${Versions.aether}", "org.eclipse.aether:aether-transport-file:${Versions.aether}",
@ -158,6 +159,7 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
"com.squareup.retrofit2:converter-gson:${Versions.retrofit}", "com.squareup.retrofit2:converter-gson:${Versions.retrofit}",
"com.squareup.okhttp3:okhttp-ws:${Versions.okhttp}", "com.squareup.okhttp3:okhttp-ws:${Versions.okhttp}",
"biz.aQute.bnd:bndlib:2.4.0", "biz.aQute.bnd:bndlib:2.4.0",
"org.sonatype.aether:aether-api:${Versions.sonatypeAether}",
"com.squareup.okhttp3:logging-interceptor:3.2.0", "com.squareup.okhttp3:logging-interceptor:3.2.0",
@ -176,7 +178,10 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
dependenciesTest { dependenciesTest {
compile("org.testng:testng:6.9.11", compile("org.testng:testng:6.9.11",
"org.assertj:assertj-core:3.4.1") "org.assertj:assertj-core:3.4.1",
"org.eclipse.aether:aether-spi:${Versions.aether}",
"org.eclipse.aether:aether-util:${Versions.aether}"
)
} }
assemble { assemble {

View file

@ -104,7 +104,7 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
context.variant.productFlavor.compileDependencies + context.variant.productFlavor.compileDependencies +
context.variant.productFlavor.compileRuntimeDependencies context.variant.productFlavor.compileRuntimeDependencies
val transitiveDependencies = dependencyManager.calculateDependencies(project, context, val transitiveDependencies = dependencyManager.calculateDependencies(project, context,
listOf(Scope.COMPILE), allDependencies) scopes = listOf(Scope.COMPILE), passedDependencies = allDependencies)
transitiveDependencies.map { transitiveDependencies.map {
it.jarFile.get() it.jarFile.get()
}.forEach { file : File -> }.forEach { file : File ->

View file

@ -1,6 +1,8 @@
package com.beust.kobalt.api package com.beust.kobalt.api
import com.beust.kobalt.maven.aether.Filters
import com.beust.kobalt.maven.aether.Scope import com.beust.kobalt.maven.aether.Scope
import org.eclipse.aether.graph.DependencyFilter
/** /**
* Manage the creation of dependencies and also provide dependencies for projects. * Manage the creation of dependencies and also provide dependencies for projects.
@ -36,6 +38,7 @@ interface IDependencyManager {
* allDependencies is typically either compileDependencies or testDependencies * allDependencies is typically either compileDependencies or testDependencies
*/ */
fun calculateDependencies(project: Project?, context: KobaltContext, fun calculateDependencies(project: Project?, context: KobaltContext,
scopeFilters: Collection<Scope> = listOf(Scope.COMPILE), dependencyFilter: DependencyFilter = Filters.EXCLUDE_OPTIONAL_FILTER,
scopes: List<Scope> = listOf(Scope.COMPILE),
vararg passedDependencies: List<IClasspathDependency>): List<IClasspathDependency> vararg passedDependencies: List<IClasspathDependency>): List<IClasspathDependency>
} }

View file

@ -2,12 +2,15 @@ package com.beust.kobalt.maven
import com.beust.kobalt.KobaltException 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.KobaltAether import com.beust.kobalt.maven.aether.KobaltAether
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
import com.beust.kobalt.misc.KobaltExecutors import com.beust.kobalt.misc.KobaltExecutors
import com.google.common.collect.ArrayListMultimap import com.google.common.collect.ArrayListMultimap
import org.eclipse.aether.graph.DependencyFilter
import org.eclipse.aether.util.filter.OrDependencyFilter
import java.io.File import java.io.File
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -92,7 +95,8 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
* are passed, they are calculated from the scope filters. * are passed, they are calculated from the scope filters.
*/ */
override fun calculateDependencies(project: Project?, context: KobaltContext, override fun calculateDependencies(project: Project?, context: KobaltContext,
scopeFilters: Collection<Scope>, dependencyFilter: DependencyFilter,
scopes: List<Scope>,
vararg passedDependencies: List<IClasspathDependency>): List<IClasspathDependency> { vararg passedDependencies: List<IClasspathDependency>): List<IClasspathDependency> {
val result = arrayListOf<IClasspathDependency>() val result = arrayListOf<IClasspathDependency>()
@ -100,7 +104,7 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
* Extract the correct dependencies from the project based on the scope filters. * Extract the correct dependencies from the project based on the scope filters.
*/ */
fun filtersToDependencies(project: Project, scopes: Collection<Scope>): List<IClasspathDependency> { fun filtersToDependencies(project: Project, scopes: Collection<Scope>): List<IClasspathDependency> {
return arrayListOf<IClasspathDependency>().apply { val result = arrayListOf<IClasspathDependency>().apply {
if (scopes.contains(Scope.COMPILE)) { if (scopes.contains(Scope.COMPILE)) {
addAll(project.compileDependencies) addAll(project.compileDependencies)
} }
@ -111,17 +115,18 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
addAll(project.testDependencies) addAll(project.testDependencies)
} }
} }
return result
} }
val allDependencies : Array<out List<IClasspathDependency>> = val allDependencies : Array<out List<IClasspathDependency>> =
if (project == null || passedDependencies.any()) passedDependencies if (project == null || passedDependencies.any()) passedDependencies
else arrayOf(filtersToDependencies(project, scopeFilters)) else arrayOf(filtersToDependencies(project, scopes))
allDependencies.forEach { dependencies -> allDependencies.forEach { dependencies ->
result.addAll(transitiveClosure(dependencies, scopeFilters, project?.name)) result.addAll(transitiveClosure(dependencies, dependencyFilter, project?.name))
} }
result.addAll(runClasspathContributors(project, context)) result.addAll(runClasspathContributors(project, context))
result.addAll(dependentProjectDependencies(project, context, scopeFilters)) result.addAll(dependentProjectDependencies(project, context, dependencyFilter, scopes.contains(Scope.TEST)))
// Dependencies get reordered by transitiveClosure() but since we just added a bunch of new ones, // Dependencies get reordered by transitiveClosure() but since we just added a bunch of new ones,
// we need to reorder them again in case we're adding dependencies that are already present // we need to reorder them again in case we're adding dependencies that are already present
@ -144,13 +149,13 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
* TODO: This should be private, everyone should be calling calculateDependencies(). * TODO: This should be private, everyone should be calling calculateDependencies().
*/ */
fun transitiveClosure(dependencies : List<IClasspathDependency>, fun transitiveClosure(dependencies : List<IClasspathDependency>,
scopeFilter: Collection<Scope> = emptyList(), dependencyFilter: DependencyFilter? = null,
requiredBy: String? = null): List<IClasspathDependency> { requiredBy: String? = null): List<IClasspathDependency> {
val result = arrayListOf<IClasspathDependency>() val result = arrayListOf<IClasspathDependency>()
dependencies.forEach { dependencies.forEach {
result.add(it) result.add(it)
if (it.isMaven) { if (it.isMaven) {
val resolved = aether.resolveAll(it.id, null, scopeFilter).map { it.toString() } val resolved = aether.resolveAll(it.id, null, dependencyFilter)
result.addAll(resolved.map { create(it) }) result.addAll(resolved.map { create(it) })
} }
} }
@ -183,7 +188,7 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
* their own dependencies * their own dependencies
*/ */
private fun dependentProjectDependencies(project: Project?, context: KobaltContext, private fun dependentProjectDependencies(project: Project?, context: KobaltContext,
scopeFilters: Collection<Scope>): List<IClasspathDependency> { dependencyFilter: DependencyFilter, isTest: Boolean): List<IClasspathDependency> {
if (project == null) { if (project == null) {
return emptyList() return emptyList()
} else { } else {
@ -199,8 +204,8 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
project.dependsOn.forEach { p -> project.dependsOn.forEach { p ->
maybeAddClassDir(KFiles.joinDir(p.directory, p.classesDir(context))) maybeAddClassDir(KFiles.joinDir(p.directory, p.classesDir(context)))
if (scopeFilters.contains(Scope.TEST)) maybeAddClassDir(KFiles.makeOutputTestDir(project).path) if (isTest) maybeAddClassDir(KFiles.makeOutputTestDir(project).path)
val otherDependencies = calculateDependencies(p, context, scopeFilters) val otherDependencies = calculateDependencies(p, context, dependencyFilter, Scope.toScopes(isTest))
result.addAll(otherDependencies) result.addAll(otherDependencies)
} }
@ -225,8 +230,13 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
deps.add(testProvidedDependencies) deps.add(testProvidedDependencies)
scopeFilters.add(Scope.TEST) scopeFilters.add(Scope.TEST)
} }
val filter =
if (isTest) OrDependencyFilter(Filters.COMPILE_FILTER, Filters.TEST_FILTER)
else Filters.COMPILE_FILTER
deps.filter { it.any() }.forEach { deps.filter { it.any() }.forEach {
transitive.addAll(calculateDependencies(project, context, scopeFilters, it)) transitive.addAll(calculateDependencies(project, context, filter,
scopes = Scope.toScopes(isTest),
passedDependencies = it))
} }
} }
} }

View file

@ -9,6 +9,7 @@ import com.beust.kobalt.maven.dependency.FileDependency
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.google.common.collect.ArrayListMultimap import com.google.common.collect.ArrayListMultimap
import com.google.inject.Inject import com.google.inject.Inject
import org.eclipse.aether.graph.DependencyFilter
import java.io.File import java.io.File
import java.util.* import java.util.*
@ -59,18 +60,18 @@ class DependencyManager2 @Inject constructor(val aether: KobaltAether) {
* Resolve the dependencies for the give project based on the scope filters. * Resolve the dependencies for the give project based on the scope filters.
*/ */
fun resolve(project: Project, context: KobaltContext, isTest: Boolean, fun resolve(project: Project, context: KobaltContext, isTest: Boolean,
passedScopeFilters : List<Scope> = emptyList(), passedScopes : List<Scope> = emptyList(),
passedIds: List<IClasspathDependency> = emptyList()): List<IClasspathDependency> { passedIds: List<IClasspathDependency> = emptyList()): List<IClasspathDependency> {
val result = hashSetOf<IClasspathDependency>() val result = hashSetOf<IClasspathDependency>()
val nonMavenDependencies = hashSetOf<IClasspathDependency>() val nonMavenDependencies = hashSetOf<IClasspathDependency>()
val scopeFilters = val actualScopes =
if (passedScopeFilters.isEmpty()) if (passedScopes.isEmpty())
if (isTest) listOf(Scope.TEST) if (isTest) listOf(Scope.TEST, Scope.COMPILE)
else listOf(Scope.COMPILE) else listOf(Scope.COMPILE)
else passedScopeFilters else passedScopes
val toDependencies = Scope.toDependencyLambda(scopeFilters) val toDependencies = Scope.toDependencyLambda(actualScopes)
// Make sure that classes/ and test-classes/ are always at the top of this classpath, // Make sure that classes/ and test-classes/ are always at the top of this classpath,
// so that older versions of that project on the classpath don't shadow them // so that older versions of that project on the classpath don't shadow them
@ -82,7 +83,7 @@ class DependencyManager2 @Inject constructor(val aether: KobaltAether) {
// Passed and direct ids // Passed and direct ids
val ids = hashSetOf<IClasspathDependency>().apply { val ids = hashSetOf<IClasspathDependency>().apply {
addAll(passedIds) addAll(passedIds)
addAll(toDependencies(project)) addAll(toDependencies(project).filter { ! it.optional })
} }
// Contributed id's // Contributed id's
@ -105,8 +106,9 @@ class DependencyManager2 @Inject constructor(val aether: KobaltAether) {
var i = 0 var i = 0
ids.forEach { ids.forEach {
if (it.isMaven) { if (it.isMaven) {
val resolved = aether.resolveAll(it.id, filterScopes = scopeFilters) result.add(it)
.map { create(it.toString(), false, project.directory) } val resolved = aether.resolveAll(it.id, dependencyFilter = scopesToDependencyFilter(actualScopes))
.map { create(it, false, project.directory) }
i++ i++
result.addAll(resolved) result.addAll(resolved)
} else { } else {
@ -119,6 +121,18 @@ class DependencyManager2 @Inject constructor(val aether: KobaltAether) {
return reorderDependencies(result) return reorderDependencies(result)
} }
private fun scopesToDependencyFilter(scopes: List<Scope>, includeOptional: Boolean = false): DependencyFilter {
return DependencyFilter { p0, p1 ->
if (p0.dependency.optional && ! includeOptional) return@DependencyFilter false
val result = scopes.any {
p0.dependency.scope == "" && scopes.contains(Scope.COMPILE) ||
p0.dependency.scope == it.scope
}
result
}
}
/** /**
* Reorder dependencies so that if an artifact appears several times, only the one with the higest version * Reorder dependencies so that if an artifact appears several times, only the one with the higest version
* is included. * is included.

View file

@ -5,7 +5,6 @@ import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.internal.KobaltSettings import com.beust.kobalt.internal.KobaltSettings
import com.beust.kobalt.internal.KobaltSettingsXml
import com.beust.kobalt.internal.getProxy import com.beust.kobalt.internal.getProxy
import com.beust.kobalt.maven.CompletedFuture import com.beust.kobalt.maven.CompletedFuture
import com.beust.kobalt.maven.LocalDep import com.beust.kobalt.maven.LocalDep
@ -23,7 +22,6 @@ import org.eclipse.aether.collection.CollectRequest
import org.eclipse.aether.collection.CollectResult import org.eclipse.aether.collection.CollectResult
import org.eclipse.aether.graph.Dependency import org.eclipse.aether.graph.Dependency
import org.eclipse.aether.graph.DependencyFilter import org.eclipse.aether.graph.DependencyFilter
import org.eclipse.aether.graph.DependencyNode
import org.eclipse.aether.repository.ArtifactRepository import org.eclipse.aether.repository.ArtifactRepository
import org.eclipse.aether.repository.RemoteRepository import org.eclipse.aether.repository.RemoteRepository
import org.eclipse.aether.resolution.DependencyRequest import org.eclipse.aether.resolution.DependencyRequest
@ -32,10 +30,7 @@ import org.eclipse.aether.resolution.VersionRangeRequest
import org.eclipse.aether.resolution.VersionRangeResult import org.eclipse.aether.resolution.VersionRangeResult
import org.eclipse.aether.transfer.ArtifactNotFoundException import org.eclipse.aether.transfer.ArtifactNotFoundException
import org.eclipse.aether.util.artifact.JavaScopes import org.eclipse.aether.util.artifact.JavaScopes
import org.eclipse.aether.util.filter.AndDependencyFilter
import org.eclipse.aether.util.filter.DependencyFilterUtils
import java.io.File import java.io.File
import java.util.*
import java.util.concurrent.Future import java.util.concurrent.Future
enum class Scope(val scope: String, val dependencyLambda: (Project) -> List<IClasspathDependency>) { enum class Scope(val scope: String, val dependencyLambda: (Project) -> List<IClasspathDependency>) {
@ -47,26 +42,22 @@ enum class Scope(val scope: String, val dependencyLambda: (Project) -> List<ICla
; ;
companion object { companion object {
/** fun toScopes(isTest: Boolean) = if (isTest) listOf(Scope.TEST, Scope.COMPILE) else listOf(Scope.COMPILE)
* @return a filter that excludes optional dependencies and allows all the scopes passed in parameter.
*/
fun toFilter(scopes: Collection<Scope>): DependencyFilter {
val javaScopes = scopes.map { DependencyFilterUtils.classpathFilter(it.scope) }.toTypedArray()
return AndDependencyFilter(KobaltAether.ExcludeOptionalDependencyFilter(), *javaScopes)
}
/** /**
* @return a lambda that extracts the correct dependencies from a project based on the scope * @return a lambda that extracts the correct dependencies from a project based on the scope
* filters passed. * filters passed (excludes optional dependencies).
*/ */
fun toDependencyLambda(scopes: Collection<Scope>) : (Project) -> List<IClasspathDependency> { fun toDependencyLambda(scopes: Collection<Scope>) : (Project) -> List<IClasspathDependency> {
val result = { project : Project -> val result = { project : Project ->
scopes.fold(arrayListOf<IClasspathDependency>(), val deps = scopes.fold(arrayListOf<IClasspathDependency>(),
{ list: ArrayList<IClasspathDependency>, scope: Scope -> { list: ArrayList<IClasspathDependency>, scope: Scope ->
list.addAll(scope.dependencyLambda(project)) list.addAll(scope.dependencyLambda(project).filter { ! it.optional })
list list
}) })
deps
} }
return result return result
} }
} }
@ -94,16 +85,16 @@ class KobaltAether @Inject constructor (val settings: KobaltSettings, val aether
DependencyResult(AetherDependency(it.artifact), it.repository.toString()) DependencyResult(AetherDependency(it.artifact), it.repository.toString())
} }
fun resolveAll(id: String, artifactScope: Scope? = null, filterScopes: Collection<Scope> = emptyList()) fun resolveAll(id: String, artifactScope: Scope? = null, dependencyFilter: DependencyFilter?)
: List<String> { : List<String> {
val results = aether.resolve(DefaultArtifact(id), artifactScope, filterScopes) val results = aether.resolve(DefaultArtifact(id), artifactScope, dependencyFilter)
return results.map { it.artifact.toString() } return results.map { it.artifact.toString() }
} }
fun resolve(id: String, artifactScope: Scope? = null, filterScopes: Collection<Scope> = emptyList()) fun resolve(id: String, artifactScope: Scope? = null, dependencyFilter: DependencyFilter = Filters.COMPILE_FILTER)
: DependencyResult { : DependencyResult {
kobaltLog(ConsoleRepositoryListener.LOG_LEVEL, "Resolving $id") kobaltLog(ConsoleRepositoryListener.LOG_LEVEL, "Resolving $id")
val result = resolveToArtifact(id, artifactScope, filterScopes) val result = resolveToArtifact(id, artifactScope, dependencyFilter)
if (result != null) { if (result != null) {
return DependencyResult(AetherDependency(result.artifact), result.repository.toString()) return DependencyResult(AetherDependency(result.artifact), result.repository.toString())
} else { } else {
@ -111,34 +102,23 @@ class KobaltAether @Inject constructor (val settings: KobaltSettings, val aether
} }
} }
fun resolveToArtifact(id: String, artifactScope: Scope? = null, filterScopes: Collection<Scope> = emptyList()) fun resolveToArtifact(id: String, artifactScope: Scope? = null,
dependencyFilter: DependencyFilter? = null)
: AetherResult? { : AetherResult? {
kobaltLog(ConsoleRepositoryListener.LOG_LEVEL, "Resolving $id") kobaltLog(ConsoleRepositoryListener.LOG_LEVEL, "Resolving $id")
val results = aether.resolve(DefaultArtifact(MavenId.toKobaltId(id)), artifactScope, filterScopes) val results = aether.resolve(DefaultArtifact(MavenId.toKobaltId(id)), artifactScope, dependencyFilter)
if (results.size > 0) { if (results.size > 0) {
return results[0] return results[0]
} else { } else {
return null return null
} }
} }
class ExcludeOptionalDependencyFilter : DependencyFilter {
override fun accept(node: DependencyNode?, p1: MutableList<DependencyNode>?): Boolean {
// val result = node != null && ! node.dependency.isOptional
val accept1 = node == null || node.artifact.artifactId != "srczip"
val accept2 = node != null && !node.dependency.isOptional
val result = accept1 && accept2
return result
}
}
} }
@Singleton @Singleton
class Aether(localRepo: File, val settings: KobaltSettings, eventBus: EventBus) { class Aether(localRepo: File, val settings: KobaltSettings, eventBus: EventBus) {
private val system = Booter.newRepositorySystem() private val system = Booter.newRepositorySystem()
private val session = Booter.newRepositorySystemSession(system, localRepo, settings, eventBus) private val session = Booter.newRepositorySystemSession(system, localRepo, settings, eventBus)
// private val classpathFilter = Scopes.toFilter(Scopes.COMPILE, Scopes.TEST)
// private val testClasspathFilter = Scopes.toFilter(Scopes.TEST)
private val kobaltRepositories: List<RemoteRepository> private val kobaltRepositories: List<RemoteRepository>
get() = Kobalt.repos.map { get() = Kobalt.repos.map {
@ -170,7 +150,7 @@ class Aether(localRepo: File, val settings: KobaltSettings, eventBus: EventBus)
if (resolved != null) { if (resolved != null) {
val newArtifact = DefaultArtifact(artifact.groupId, artifact.artifactId, artifact.extension, val newArtifact = DefaultArtifact(artifact.groupId, artifact.artifactId, artifact.extension,
resolved.highestVersion.toString()) resolved.highestVersion.toString())
val artifactResult = resolve(newArtifact, null, emptyList()) val artifactResult = resolve(newArtifact, null)
if (artifactResult.any()) { if (artifactResult.any()) {
return artifactResult[0] return artifactResult[0]
} else { } else {
@ -187,7 +167,9 @@ class Aether(localRepo: File, val settings: KobaltSettings, eventBus: EventBus)
return result return result
} }
fun resolve(artifact: Artifact, artifactScope: Scope?, filterScopes: Collection<Scope>): List<AetherResult> { fun resolve(artifact: Artifact, artifactScope: Scope?,
dependencyFilter: DependencyFilter? = null)
: List<AetherResult> {
fun manageException(ex: Exception, artifact: Artifact): List<AetherResult> { fun manageException(ex: Exception, artifact: Artifact): List<AetherResult> {
if (artifact.extension == "pom") { if (artifact.extension == "pom") {
// Only display a warning for .pom files. Not resolving a .jar or other artifact // Only display a warning for .pom files. Not resolving a .jar or other artifact
@ -198,7 +180,6 @@ class Aether(localRepo: File, val settings: KobaltSettings, eventBus: EventBus)
} }
try { try {
val scopeFilter = Scope.toFilter(filterScopes)
val result = val result =
if (KobaltAether.isRangeVersion(artifact.version)) { if (KobaltAether.isRangeVersion(artifact.version)) {
val request = rangeRequest(artifact) val request = rangeRequest(artifact)
@ -212,7 +193,8 @@ class Aether(localRepo: File, val settings: KobaltSettings, eventBus: EventBus)
throw KobaltException("Couldn't resolve range artifact " + artifact) throw KobaltException("Couldn't resolve range artifact " + artifact)
} }
} else { } else {
val dependencyRequest = DependencyRequest(collectRequest(artifact, artifactScope), scopeFilter) val dependencyRequest = DependencyRequest(collectRequest(artifact, artifactScope), dependencyFilter)
try { try {
system.resolveDependencies(session, dependencyRequest).artifactResults.map { system.resolveDependencies(session, dependencyRequest).artifactResults.map {
AetherResult(it.artifact, it.repository) AetherResult(it.artifact, it.repository)
@ -256,7 +238,7 @@ class AetherDependency(val artifact: Artifact, override val optional: Boolean =
if (file.exists()) { if (file.exists()) {
CompletedFuture(file) CompletedFuture(file)
} else { } else {
val td = aether.resolve(artifact, null, emptyList()) val td = aether.resolve(artifact, null)
if (td.any()) { if (td.any()) {
val newFile = td[0].artifact.file val newFile = td[0].artifact.file
if (newFile != null) { if (newFile != null) {
@ -318,21 +300,38 @@ class AetherDependency(val artifact: Artifact, override val optional: Boolean =
override fun toString() = id override fun toString() = id
} }
fun main(argv: Array<String>) { fun f(argv: Array<String>) {
val request = CollectRequest().apply { val collectRequest = CollectRequest().apply {
root = Dependency(DefaultArtifact("org.testng:testng:6.9.11"), JavaScopes.COMPILE) root = Dependency(DefaultArtifact("com.squareup.retrofit2:converter-jackson:jar:2.1.0"), JavaScopes.COMPILE)
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", "https://jcenter.bintray.com").build()) RemoteRepository.Builder("JCenter", "default", "https://jcenter.bintray.com").build()
} )
val dependencyRequest = DependencyRequest().apply {
collectRequest = request
} }
// val dependencyRequest = DependencyRequest().apply {
// collectRequest = request
// filter = object: DependencyFilter {
// override fun accept(p0: DependencyNode, p1: MutableList<DependencyNode>?): Boolean {
// if (p0.artifact.artifactId.contains("android")) {
// println("ANDROID")
// }
// return p0.dependency.scope == JavaScopes.COMPILE
// }
//
// }
// }
val dr2 = DependencyRequest(collectRequest, null).apply {}
// val system = ManualRepositorySystemFactory.newRepositorySystem()
// val session = DefaultRepositorySystemSession()
// val localRepo = LocalRepository(File("/Users/cedricbeust/t/localAether").absolutePath)
// session.localRepositoryManager = system.newLocalRepositoryManager(session, localRepo)
val system = Booter.newRepositorySystem() val system = Booter.newRepositorySystem()
val session = Booter.newRepositorySystemSession(system, File("/tmp"), KobaltSettings(KobaltSettingsXml()), val session = Booter.newRepositorySystemSession(system)
EventBus())
// val session = MavenRepositorySystemUtils.newSession(KobaltSettings(KobaltSettingsXml())) val result = system.resolveDependencies(session, dr2).artifactResults
val result = system.resolveDependencies(session, dependencyRequest).artifactResults
println("RESULT: " + result) println("RESULT: " + result)
// KobaltLogger.LOG_LEVEL = 1 // KobaltLogger.LOG_LEVEL = 1
@ -346,4 +345,36 @@ fun main(argv: Array<String>) {
// println("Artifact: " + d) // println("Artifact: " + d)
} }
fun f2() {
val system = Booter.newRepositorySystem()
val session = Booter.newRepositorySystemSession(system)
val artifact = DefaultArtifact("com.squareup.retrofit2:converter-jackson:jar:2.1.0")
// DependencyFilter classpathFlter = DependencyFilterUtils.classpathFilter( JavaScopes.COMPILE );
val f2 = DependencyFilter { dependencyNode, list ->
println("ACCEPTING " + dependencyNode)
true
}
val collectRequest = CollectRequest()
collectRequest.root = Dependency(artifact, JavaScopes.COMPILE)
collectRequest.repositories = listOf(
RemoteRepository.Builder("Maven", "default", "http://repo1.maven.org/maven2/").build()
)
val dependencyRequest = DependencyRequest(collectRequest, null)
val artifactResults = system.resolveDependencies(session, dependencyRequest).artifactResults
for (artifactResult in artifactResults) {
println(artifactResult.artifact.toString() + " resolved to " + artifactResult.artifact.file)
}
}
fun main(args: Array<String>) {
f2()
}

View file

@ -16,6 +16,21 @@ object Booter {
// return org.eclipse.aether.examples.plexus.PlexusRepositorySystemFactory.newRepositorySystem(); // return org.eclipse.aether.examples.plexus.PlexusRepositorySystemFactory.newRepositorySystem();
} }
fun newRepositorySystemSession(system: RepositorySystem): DefaultRepositorySystemSession {
val session = org.apache.maven.repository.internal.MavenRepositorySystemUtils.newSession()
val localRepo = LocalRepository("target/local-repo")
session.localRepositoryManager = system.newLocalRepositoryManager(session, localRepo)
session.transferListener = ConsoleTransferListener()
session.repositoryListener = ConsoleRepositoryListener(System.out, EventBus())
// uncomment to generate dirty trees
// session.setDependencyGraphTransformer( null );
return session
}
fun newRepositorySystemSession(system: RepositorySystem, repo: File, settings: KobaltSettings, fun newRepositorySystemSession(system: RepositorySystem, repo: File, settings: KobaltSettings,
eventBus: EventBus): DefaultRepositorySystemSession { eventBus: EventBus): DefaultRepositorySystemSession {
val session = MavenRepositorySystemUtils.newSession(settings) val session = MavenRepositorySystemUtils.newSession(settings)

View file

@ -0,0 +1,15 @@
package com.beust.kobalt.maven.aether
import org.eclipse.aether.graph.DependencyFilter
import org.eclipse.aether.util.artifact.JavaScopes
object Filters {
val COMPILE_FILTER = DependencyFilter { p0, p1 ->
p0.dependency.scope == "" || p0.dependency.scope == JavaScopes.COMPILE
}
val TEST_FILTER = DependencyFilter { p0, p1 -> p0.dependency.scope == JavaScopes.TEST }
val EXCLUDE_OPTIONAL_FILTER = DependencyFilter { p0, p1 ->
! p0.dependency.optional
}
}

View file

@ -46,7 +46,7 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
private val SCRIPT_JAR = "buildScript.jar" private val SCRIPT_JAR = "buildScript.jar"
fun compileBuildFiles(args: Args): FindProjectResult { fun compileBuildFiles(args: Args, forceRecompile: Boolean = false): FindProjectResult {
// //
// Create the KobaltContext // Create the KobaltContext
// Note: can't use apply{} here or each field will refer to itself instead of the constructor field // Note: can't use apply{} here or each field will refer to itself instead of the constructor field
@ -66,7 +66,7 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
// //
// Find all the projects in the build file, possibly compiling them // Find all the projects in the build file, possibly compiling them
// //
val projectResult = findProjects(context) val projectResult = findProjects(context, forceRecompile)
return projectResult return projectResult
} }
@ -76,7 +76,7 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
class FindProjectResult(val context: KobaltContext, val projects: List<Project>, val pluginUrls: List<URL>, class FindProjectResult(val context: KobaltContext, val projects: List<Project>, val pluginUrls: List<URL>,
val taskResult: TaskResult) val taskResult: TaskResult)
private fun findProjects(context: KobaltContext): FindProjectResult { private fun findProjects(context: KobaltContext, forceRecompile: Boolean): FindProjectResult {
var errorTaskResult: TaskResult? = null var errorTaskResult: TaskResult? = null
val projects = arrayListOf<Project>() val projects = arrayListOf<Project>()
buildFiles.forEach { buildFile -> buildFiles.forEach { buildFile ->
@ -105,7 +105,7 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
KFiles.saveFile(modifiedBuildFile, parsedBuildFile.buildScriptCode) KFiles.saveFile(modifiedBuildFile, parsedBuildFile.buildScriptCode)
val taskResult = maybeCompileBuildFile(context, BuildFile(Paths.get(modifiedBuildFile.path), val taskResult = maybeCompileBuildFile(context, BuildFile(Paths.get(modifiedBuildFile.path),
"Modified ${Constants.BUILD_FILE_NAME}", buildFile.realPath), "Modified ${Constants.BUILD_FILE_NAME}", buildFile.realPath),
buildScriptJarFile, pluginUrls) buildScriptJarFile, pluginUrls, forceRecompile)
if (taskResult.success) { if (taskResult.success) {
projects.addAll(buildScriptUtil.runBuildScriptJarFile(buildScriptJarFile, pluginUrls, context)) projects.addAll(buildScriptUtil.runBuildScriptJarFile(buildScriptJarFile, pluginUrls, context))
} else { } else {
@ -124,7 +124,7 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
} }
private fun maybeCompileBuildFile(context: KobaltContext, buildFile: BuildFile, buildScriptJarFile: File, private fun maybeCompileBuildFile(context: KobaltContext, buildFile: BuildFile, buildScriptJarFile: File,
pluginUrls: List<URL>) : TaskResult { pluginUrls: List<URL>, forceRecompile: Boolean) : TaskResult {
kobaltLog(2, "Running build file ${buildFile.name} jar: $buildScriptJarFile") kobaltLog(2, "Running build file ${buildFile.name} jar: $buildScriptJarFile")
// If the user specifed --profiles, always recompile the build file since we don't know if // If the user specifed --profiles, always recompile the build file since we don't know if
@ -135,8 +135,8 @@ class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFil
// compiled with. // compiled with.
val bs = BuildScriptJarFile(buildScriptJarFile) val bs = BuildScriptJarFile(buildScriptJarFile)
val same = bs.sameProfiles(args.profiles) val same = bs.sameProfiles(args.profiles)
if (same && buildScriptUtil.isUpToDate(buildFile, buildScriptJarFile)) { if (same && ! forceRecompile && buildScriptUtil.isUpToDate(buildFile, buildScriptJarFile)) {
kobaltLog(2, " Build file is up to date") kobaltLog(2, " Build file $buildScriptJarFile is up to date")
return TaskResult() return TaskResult()
} else { } else {
kobaltLog(2, " Need to recompile ${buildFile.name}") kobaltLog(2, " Need to recompile ${buildFile.name}")

View file

@ -13,6 +13,7 @@ import com.beust.kobalt.internal.build.BuildFile
import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.Topological import com.beust.kobalt.misc.Topological
import com.beust.kobalt.misc.kobaltLog import com.beust.kobalt.misc.kobaltLog
import com.beust.kobalt.misc.warn
import com.beust.kobalt.plugin.KobaltPlugin import com.beust.kobalt.plugin.KobaltPlugin
import com.google.inject.Inject import com.google.inject.Inject
import java.io.File import java.io.File
@ -63,12 +64,16 @@ class BuildScriptUtil @Inject constructor(val plugins: Plugins, val files: KFile
val name = entry.name; val name = entry.name;
if (name.endsWith(".class")) { if (name.endsWith(".class")) {
val className = name.substring(0, name.length - 6).replace("/", ".") val className = name.substring(0, name.length - 6).replace("/", ".")
try {
val cl: Class<*>? = classLoader.loadClass(className) val cl: Class<*>? = classLoader.loadClass(className)
if (cl != null) { if (cl != null) {
classes.add(cl) classes.add(cl)
} else { } else {
throw KobaltException("Couldn't instantiate $className") throw KobaltException("Couldn't instantiate $className")
} }
} catch(ex: ClassNotFoundException) {
warn("Couldn't find class $className")
}
} }
entry = stream.nextJarEntry; entry = stream.nextJarEntry;
} }

View file

@ -162,8 +162,8 @@ class ParsedBuildFile(val buildFile: BuildFile, val context: KobaltContext, val
// //
// Compile the jar file // Compile the jar file
// //
val kotlintDeps = dependencyManager.calculateDependencies(null, context) val kotlinDeps = dependencyManager.calculateDependencies(null, context)
val deps: List<String> = kotlintDeps.map { it.jarFile.get().absolutePath } val deps: List<String> = kotlinDeps.map { it.jarFile.get().absolutePath }
val outputJar = File(buildScriptJarFile.absolutePath) val outputJar = File(buildScriptJarFile.absolutePath)
val result = kotlinCompilePrivate { val result = kotlinCompilePrivate {
classpath(files.kobaltJar) classpath(files.kobaltJar)

View file

@ -112,7 +112,7 @@ class ApplicationPlugin @Inject constructor(val configActor: ConfigActor<Applica
val allDependencies = project.compileDependencies + project.compileRuntimeDependencies val allDependencies = project.compileDependencies + project.compileRuntimeDependencies
val allTheDependencies = val allTheDependencies =
dependencyManager.calculateDependencies(project, context, dependencyManager.calculateDependencies(project, context,
listOf(Scope.COMPILE, Scope.RUNTIME), scopes = listOf(Scope.COMPILE, Scope.RUNTIME),
passedDependencies = allDependencies) passedDependencies = allDependencies)
.map { it.jarFile.get().path } .map { it.jarFile.get().path }
allDeps.addAll(allTheDependencies) allDeps.addAll(allTheDependencies)

View file

@ -6,9 +6,11 @@ import com.beust.kobalt.TestModule
import com.beust.kobalt.api.IClasspathDependency import com.beust.kobalt.api.IClasspathDependency
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.app.BuildFileCompiler import com.beust.kobalt.app.BuildFileCompiler
import com.beust.kobalt.maven.aether.Filters
import com.beust.kobalt.maven.aether.Scope import com.beust.kobalt.maven.aether.Scope
import com.google.inject.Inject import com.google.inject.Inject
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.eclipse.aether.util.filter.AndDependencyFilter
import org.testng.annotations.Guice import org.testng.annotations.Guice
import org.testng.annotations.Test import org.testng.annotations.Test
@ -19,7 +21,17 @@ class DependencyManagerTest @Inject constructor(val dependencyManager: Dependenc
private fun assertContains(dependencies: List<IClasspathDependency>, vararg ids: String) { private fun assertContains(dependencies: List<IClasspathDependency>, vararg ids: String) {
ids.forEach { id -> ids.forEach { id ->
assertThat(dependencies.any { it.id.contains(id) }).isTrue() if (! dependencies.any { it.id.contains(id) }) {
throw AssertionError("Couldn't find $id in $dependencies")
}
}
}
private fun assertDoesNotContain(dependencies: List<IClasspathDependency>, vararg ids: String) {
ids.forEach { id ->
if (dependencies.any { it.id.contains(id) }) {
throw AssertionError("$id should not be found in $dependencies")
}
} }
} }
@ -27,87 +39,118 @@ class DependencyManagerTest @Inject constructor(val dependencyManager: Dependenc
fun testScopeDependenciesShouldBeDownloaded() { fun testScopeDependenciesShouldBeDownloaded() {
val testDeps = listOf(dependencyManager.create("org.testng:testng:6.9.11")) val testDeps = listOf(dependencyManager.create("org.testng:testng:6.9.11"))
val filter = AndDependencyFilter(Filters.EXCLUDE_OPTIONAL_FILTER, Filters.COMPILE_FILTER)
// Should only resolve to TestNG // Should only resolve to TestNG
dependencyManager.transitiveClosure(testDeps, listOf(Scope.COMPILE)).let { dependencies -> dependencyManager.transitiveClosure(testDeps, filter).let { dependencies ->
assertThat(dependencies.any { it.id.contains(":jcommander:") }).isFalse() assertThat(dependencies.any { it.id.contains(":jcommander:") }).isFalse()
assertContains(dependencies, ":testng:") assertContains(dependencies, ":testng:")
} }
// Should resolve to TestNG and its dependencies // Should resolve to TestNG and its dependencies
dependencyManager.transitiveClosure(testDeps, listOf(Scope.TEST)).let { dependencies -> dependencyManager.transitiveClosure(testDeps).let { dependencies ->
assertContains(dependencies, ":jcommander:") assertContains(dependencies, ":jcommander:")
assertContains(dependencies, ":bsh:") assertContains(dependencies, ":bsh:")
assertContains(dependencies, ":ant:") assertContains(dependencies, ":ant:")
assertContains(dependencies, ":ant-launcher:") assertContains(dependencies, ":ant-launcher:")
assertContains(dependencies, ":testng:") assertContains(dependencies, ":testng:")
} }
} }
@Test @Test
fun honorRuntimeDependenciesBetweenProjects() { fun honorRuntimeDependenciesBetweenProjects() {
Kobalt.context = null
val buildFileString = """ val buildFileString = """
import com.beust.kobalt.* import com.beust.kobalt.*
val lib = project { val lib1 = project {
name = "lib" name = "lib1"
dependencies { dependencies {
compile("org.testng:testng:6.9.11") compile("com.beust:klaxon:0.26",
runtime("com.beust:jcommander:1.48") "com.beust:jcommander:1.48")
} }
} }
val p = project(lib) { val p = project(lib1) {
name = "transitive" name = "transitive1"
} }
""" """
val compileResult = compileBuildFile(buildFileString, 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!!, val dependencies = dependencyManager.calculateDependencies(project2, Kobalt.context!!, Filters.COMPILE_FILTER)
listOf(Scope.COMPILE, Scope.RUNTIME)) assertContains(dependencies, ":klaxon:")
assertContains(dependencies, ":testng:") assertContains(dependencies, ":guice:")
assertContains(dependencies, ":jcommander:") assertDoesNotContain(dependencies, ":guave:")
} }
val sharedBuildFile = """
import com.beust.kobalt.*
val lib2 = project {
name = "lib2"
dependencies {
// pick dependencies that don't have dependencies themselves, to avoid interferences
compile("com.beust:klaxon:0.27",
"com.google.inject:guice:4.0")
runtime("com.beust:jcommander:1.48")
compileOptional("junit:junit:4.12")
}
}
val p = project(lib2) {
name = "transitive2"
}
"""
@Test @Test
fun honorRuntimeDependenciesBetweenProjects2() { fun honorRuntimeDependenciesBetweenProjects2() {
val buildFileString = """ val buildFileString = """
import com.beust.kobalt.* import com.beust.kobalt.*
val lib = project { val lib2 = project {
name = "lib" name = "lib2"
dependencies { dependencies {
compile("org.testng:testng:6.9.11") // pick dependencies that don't have dependencies themselves, to avoid interferences
compile("com.beust:klaxon:0.27",
"com.google.inject:guice:4.0)
runtime("com.beust:jcommander:1.48") runtime("com.beust:jcommander:1.48")
} }
} }
val p = project(lib) { val p = project(lib2) {
name = "transitive" name = "transitive2"
} }
""" """
val compileResult = compileBuildFile(buildFileString, Args(), compilerFactory) val compileResult = compileBuildFile(sharedBuildFile, Args(), compilerFactory)
val project2 = compileResult.projects[1] val project2 = compileResult.projects[1]
dependencyManager2.resolve(project2, Kobalt.context!!, isTest = false, Kobalt.context!!.let { context ->
passedScopeFilters = listOf(Scope.COMPILE, Scope.RUNTIME)).let { dependencies -> dependencyManager2.resolve(project2, context, isTest = false,
assertThat(dependencies.size).isEqualTo(4) passedScopes = listOf(Scope.COMPILE)).let { dependencies ->
assertContains(dependencies, ":testng:") assertContains(dependencies, ":klaxon:jar:0.27")
assertContains(dependencies, ":guice:")
assertDoesNotContain(dependencies, ":jcommander:")
assertDoesNotContain(dependencies, ":junit:")
}
dependencyManager2.resolve(project2, context, isTest = false,
passedScopes = listOf(Scope.RUNTIME)).let { dependencies ->
assertContains(dependencies, ":jcommander:") assertContains(dependencies, ":jcommander:")
assertDoesNotContain(dependencies, ":klaxon:jar:0.27")
assertDoesNotContain(dependencies, ":guice:")
assertDoesNotContain(dependencies, ":junit:")
} }
dependencyManager2.resolve(project2, Kobalt.context!!, isTest = false, dependencyManager2.resolve(project2, context, isTest = false,
passedScopeFilters = listOf(Scope.COMPILE)).let { dependencies -> passedScopes = listOf(Scope.COMPILE, Scope.RUNTIME)).let { dependencies ->
assertThat(dependencies.size).isEqualTo(3) assertContains(dependencies, ":klaxon:")
assertContains(dependencies, ":testng:")
}
dependencyManager2.resolve(project2, Kobalt.context!!, isTest = false,
passedScopeFilters = listOf(Scope.RUNTIME)).let { dependencies ->
assertThat(dependencies.size).isEqualTo(3)
assertContains(dependencies, ":jcommander:") assertContains(dependencies, ":jcommander:")
assertContains(dependencies, ":guice:")
assertDoesNotContain(dependencies, ":junit:")
}
} }
} }

View file

@ -147,7 +147,7 @@ class DownloadTest @Inject constructor(
@Test @Test
fun parentPomTest() { fun parentPomTest() {
// Resolve com.squareup.retrofit2:converter-moshi:2.0.0 // Resolve com.squareup.retrofit2:converter-moshi:1.1.0
// This id has a parent pom which defines moshi version to be 1.1.0. Make sure that this // This id has a parent pom which defines moshi version to be 1.1.0. Make sure that this
// version is being fetched instead of moshi:1.2.0-SNAPSHOT (which gets discarded anyway // version is being fetched instead of moshi:1.2.0-SNAPSHOT (which gets discarded anyway
// since snapshots are not allowed to be returned when looking up a versionless id) // since snapshots are not allowed to be returned when looking up a versionless id)

View file

@ -0,0 +1,55 @@
package com.beust.kobalt.misc
import com.beust.kobalt.TestModule
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.aether.Booter
import com.beust.kobalt.maven.aether.KobaltAether
import com.google.inject.Inject
import org.assertj.core.api.Assertions.assertThat
import org.eclipse.aether.artifact.DefaultArtifact
import org.eclipse.aether.collection.CollectRequest
import org.eclipse.aether.graph.Dependency
import org.eclipse.aether.repository.RemoteRepository
import org.eclipse.aether.resolution.DependencyRequest
import org.eclipse.aether.util.artifact.JavaScopes
import org.testng.annotations.Guice
import org.testng.annotations.Test
@Guice(modules = arrayOf(TestModule::class))
class AetherTest {
@Inject
lateinit var kobaltAether: KobaltAether
@Inject
lateinit var dependencyManager: DependencyManager
@Test
fun aetherShouldNotIncludeOptionalDependencies() {
val system = Booter.newRepositorySystem()
val session = Booter.newRepositorySystemSession(system)
val artifact = DefaultArtifact("com.squareup.retrofit2:converter-jackson:jar:2.1.0")
val collectRequest = CollectRequest().apply {
root = Dependency(artifact, JavaScopes.COMPILE)
repositories = listOf(
RemoteRepository.Builder("Maven", "default", "http://repo1.maven.org/maven2/").build()
)
}
val dependencyRequest = DependencyRequest(collectRequest, null)
val artifactResults = system.resolveDependencies(session, dependencyRequest).artifactResults
// Make sure that com.google.android is not included (it's an optional dependency of retrofit2)
assertThat(artifactResults.none { it.toString().contains("android") })
}
@Test
fun kobaltAetherShouldNotIncludeOptionalDependencies() {
val dep = kobaltAether.create("com.squareup.retrofit2:converter-jackson:jar:2.1.0", optional = false)
val closure = dependencyManager.transitiveClosure(listOf(dep))
// Make sure that com.google.android is not included (it's an optional dependency of retrofit2)
assertThat(closure.none { it.toString().contains("android") })
}
}