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

Revamp the scopes and scope filters.

This commit is contained in:
Cedric Beust 2016-07-26 02:24:35 -08:00
parent f9c7e488d5
commit d18c8009c8
12 changed files with 183 additions and 86 deletions

View file

@ -102,7 +102,7 @@ class JarGenerator @Inject constructor(val dependencyManager: DependencyManager)
context.variant.buildType.compileRuntimeDependencies + context.variant.buildType.compileRuntimeDependencies +
context.variant.productFlavor.compileDependencies + context.variant.productFlavor.compileDependencies +
context.variant.productFlavor.compileRuntimeDependencies context.variant.productFlavor.compileRuntimeDependencies
val transitiveDependencies = dependencyManager.calculateDependencies(project, context, false, val transitiveDependencies = dependencyManager.calculateDependencies(project, context, emptyList(),
allDependencies) allDependencies)
transitiveDependencies.map { transitiveDependencies.map {
it.jarFile.get() it.jarFile.get()

View file

@ -1,5 +1,7 @@
package com.beust.kobalt.api package com.beust.kobalt.api
import com.beust.kobalt.maven.aether.Scope
/** /**
* Manage the creation of dependencies and also provide dependencies for projects. * Manage the creation of dependencies and also provide dependencies for projects.
*/ */
@ -33,6 +35,7 @@ interface IDependencyManager {
* @return the classpath for this project, including the IClasspathContributors. * @return the classpath for this project, including the IClasspathContributors.
* allDependencies is typically either compileDependencies or testDependencies * allDependencies is typically either compileDependencies or testDependencies
*/ */
fun calculateDependencies(project: Project?, context: KobaltContext, isTest: Boolean = false, fun calculateDependencies(project: Project?, context: KobaltContext,
vararg allDependencies: List<IClasspathDependency>): List<IClasspathDependency> scopeFilters: Collection<Scope> = emptyList(),
vararg passedDependencies: List<IClasspathDependency>): List<IClasspathDependency>
} }

View file

@ -25,7 +25,7 @@ class JvmCompiler @Inject constructor(val dependencyManager: DependencyManager)
// Dependencies // Dependencies
val allDependencies = (info.dependencies val allDependencies = (info.dependencies
+ dependencyManager.calculateDependencies(project, context!!, allDependencies = info.dependencies)) + dependencyManager.calculateDependencies(project, context!!, passedDependencies = info.dependencies))
.distinct() .distinct()
// Plugins that add flags to the compiler // Plugins that add flags to the compiler

View file

@ -3,6 +3,7 @@ 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.KobaltAether import com.beust.kobalt.maven.aether.KobaltAether
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
@ -82,16 +83,40 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
/** /**
* @return the classpath for this project, including the IClasspathContributors. * @return the classpath for this project, including the IClasspathContributors.
* allDependencies is typically either compileDependencies or testDependencies * allDependencies is typically either compileDependencies or testDependencies. If no dependencies
* are passed, they are calculated from the scope filters.
*/ */
override fun calculateDependencies(project: Project?, context: KobaltContext, isTest: Boolean, override fun calculateDependencies(project: Project?, context: KobaltContext,
vararg allDependencies: List<IClasspathDependency>): List<IClasspathDependency> { scopeFilters: Collection<Scope>,
vararg passedDependencies: List<IClasspathDependency>): List<IClasspathDependency> {
val result = arrayListOf<IClasspathDependency>() val result = arrayListOf<IClasspathDependency>()
/**
* Extract the correct dependencies from the project based on the scope filters.
*/
fun filtersToDependencies(project: Project, scopes: Collection<Scope>): List<IClasspathDependency> {
return arrayListOf<IClasspathDependency>().apply {
if (scopes.contains(Scope.COMPILE)) {
addAll(project.compileDependencies)
}
if (scopes.contains(Scope.RUNTIME)) {
addAll(project.compileRuntimeDependencies)
}
if (scopes.contains(Scope.TEST)) {
addAll(project.testDependencies)
}
}
}
val allDependencies : Array<out List<IClasspathDependency>> =
if (project == null || passedDependencies.any()) passedDependencies
else arrayOf(filtersToDependencies(project, scopeFilters))
allDependencies.forEach { dependencies -> allDependencies.forEach { dependencies ->
result.addAll(transitiveClosure(dependencies, isTest, project?.name)) result.addAll(transitiveClosure(dependencies, scopeFilters, project?.name))
} }
result.addAll(runClasspathContributors(project, context)) result.addAll(runClasspathContributors(project, context))
result.addAll(dependentProjectDependencies(project, context)) result.addAll(dependentProjectDependencies(project, context, scopeFilters))
// 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
@ -113,13 +138,14 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
* Return the transitive closure of the dependencies *without* running the classpath contributors. * Return the transitive closure of the dependencies *without* running the classpath contributors.
* 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>, isTest: Boolean = false, fun transitiveClosure(dependencies : List<IClasspathDependency>,
scopeFilter: Collection<Scope> = emptyList(),
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, isTest).map { it.toString() } val resolved = aether.resolveAll(it.id, null, scopeFilter).map { it.toString() }
result.addAll(resolved.map { create(it) }) result.addAll(resolved.map { create(it) })
} }
} }
@ -151,8 +177,8 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
* If this project depends on other projects, we need to include their jar file and also * If this project depends on other projects, we need to include their jar file and also
* their own dependencies * their own dependencies
*/ */
private fun dependentProjectDependencies( private fun dependentProjectDependencies(project: Project?, context: KobaltContext, scopeFilters: Collection<Scope>)
project: Project?, context: KobaltContext) : List<IClasspathDependency> { : List<IClasspathDependency> {
if (project == null) { if (project == null) {
return emptyList() return emptyList()
} else { } else {
@ -165,7 +191,7 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
result.add(FileDependency(KFiles.joinDir(p.directory, p.classesDir(context)))) result.add(FileDependency(KFiles.joinDir(p.directory, p.classesDir(context))))
} }
} }
val otherDependencies = calculateDependencies(p, context, false, p.compileDependencies) val otherDependencies = calculateDependencies(p, context, scopeFilters)
result.addAll(otherDependencies) result.addAll(otherDependencies)
} }
@ -177,6 +203,7 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
: List<IClasspathDependency> { : List<IClasspathDependency> {
val transitive = hashSetOf<IClasspathDependency>() val transitive = hashSetOf<IClasspathDependency>()
with(project) { with(project) {
val scopeFilters = arrayListOf(Scope.COMPILE)
context.variant.let { variant -> context.variant.let { variant ->
val deps = arrayListOf(compileDependencies, compileProvidedDependencies, val deps = arrayListOf(compileDependencies, compileProvidedDependencies,
variant.buildType.compileDependencies, variant.buildType.compileDependencies,
@ -187,9 +214,10 @@ class DependencyManager @Inject constructor(val executors: KobaltExecutors, val
if (isTest) { if (isTest) {
deps.add(testDependencies) deps.add(testDependencies)
deps.add(testProvidedDependencies) deps.add(testProvidedDependencies)
scopeFilters.add(Scope.TEST)
} }
deps.filter { it.any() }.forEach { deps.filter { it.any() }.forEach {
transitive.addAll(calculateDependencies(project, context, isTest, it)) transitive.addAll(calculateDependencies(project, context, scopeFilters, it))
} }
} }
} }

View file

@ -32,11 +32,28 @@ import org.eclipse.aether.util.filter.DependencyFilterUtils
import java.io.File import java.io.File
import java.util.concurrent.Future import java.util.concurrent.Future
enum class Scope(val scope: String) {
COMPILE(JavaScopes.COMPILE),
PROVIDED(JavaScopes.PROVIDED),
SYSTEM(JavaScopes.SYSTEM),
RUNTIME(JavaScopes.RUNTIME),
TEST(JavaScopes.TEST)
;
companion object {
/**
* @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)
}
}
}
class DependencyResult(val dependency: IClasspathDependency, val repoUrl: String) class DependencyResult(val dependency: IClasspathDependency, val repoUrl: String)
class KobaltAether @Inject constructor (val settings: KobaltSettings, val aether: Aether) { class KobaltAether @Inject constructor (val settings: KobaltSettings, val aether: Aether) {
val localRepo: File get() = settings.localCache
/** /**
* Create an IClasspathDependency from a Kobalt id. * Create an IClasspathDependency from a Kobalt id.
*/ */
@ -50,14 +67,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, isTest: Boolean): List<String> { fun resolveAll(id: String, artifactScope: Scope? = null, filterScopes: Collection<Scope> = emptyList())
val results = aether.resolve(DefaultArtifact(id), isTest) : List<String> {
val results = aether.resolve(DefaultArtifact(id), artifactScope, filterScopes)
return results.map { it.artifact.toString() } return results.map { it.artifact.toString() }
} }
fun resolve(id: String, isTest: Boolean = false): DependencyResult { fun resolve(id: String, artifactScope: Scope? = null, filterScopes: Collection<Scope> = emptyList())
: DependencyResult {
log(ConsoleRepositoryListener.LOG_LEVEL, "Resolving $id") log(ConsoleRepositoryListener.LOG_LEVEL, "Resolving $id")
val result = resolveToArtifact(id, isTest) val result = resolveToArtifact(id, artifactScope, filterScopes)
if (result != null) { if (result != null) {
return DependencyResult(AetherDependency(result.artifact), result.repository.toString()) return DependencyResult(AetherDependency(result.artifact), result.repository.toString())
} else { } else {
@ -65,9 +84,10 @@ class KobaltAether @Inject constructor (val settings: KobaltSettings, val aether
} }
} }
fun resolveToArtifact(id: String, isTest: Boolean = false): ArtifactResult? { fun resolveToArtifact(id: String, artifactScope: Scope? = null, filterScopes: Collection<Scope> = emptyList())
: ArtifactResult? {
log(ConsoleRepositoryListener.LOG_LEVEL, "Resolving $id") log(ConsoleRepositoryListener.LOG_LEVEL, "Resolving $id")
val results = aether.resolve(DefaultArtifact(MavenId.toKobaltId(id)), isTest) val results = aether.resolve(DefaultArtifact(MavenId.toKobaltId(id)), artifactScope, filterScopes)
if (results.size > 0) { if (results.size > 0) {
return results[0] return results[0]
} else { } else {
@ -87,17 +107,11 @@ class KobaltAether @Inject constructor (val settings: KobaltSettings, val aether
} }
@Singleton @Singleton
class Aether(val localRepo: File, val settings: KobaltSettings, val eventBus: EventBus) { class Aether(localRepo: File, val settings: KobaltSettings, val 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 = AndDependencyFilter( // private val classpathFilter = Scopes.toFilter(Scopes.COMPILE, Scopes.TEST)
KobaltAether.ExcludeOptionalDependencyFilter(), // private val testClasspathFilter = Scopes.toFilter(Scopes.TEST)
DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE),
DependencyFilterUtils.classpathFilter(JavaScopes.TEST))
private val testClasspathFilter = AndDependencyFilter(
KobaltAether.ExcludeOptionalDependencyFilter(),
DependencyFilterUtils.classpathFilter(JavaScopes.TEST))
private val kobaltRepositories: List<RemoteRepository> private val kobaltRepositories: List<RemoteRepository>
get() = Kobalt.repos.map { get() = Kobalt.repos.map {
@ -111,9 +125,9 @@ class Aether(val localRepo: File, val settings: KobaltSettings, val eventBus: Ev
} }
} }
private fun collectRequest(artifact: Artifact, isTest: Boolean): CollectRequest { private fun collectRequest(artifact: Artifact, scope: Scope?): CollectRequest {
with(CollectRequest()) { with(CollectRequest()) {
root = Dependency(artifact, if (isTest) JavaScopes.TEST else JavaScopes.COMPILE) root = Dependency(artifact, scope?.scope)
repositories = kobaltRepositories repositories = kobaltRepositories
return this return this
@ -126,8 +140,8 @@ class Aether(val localRepo: File, val settings: KobaltSettings, val eventBus: Ev
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) val artifactResult = resolve(newArtifact, null, emptyList())
if (artifactResult != null && artifactResult.size > 0) { if (artifactResult.any()) {
return artifactResult[0] return artifactResult[0]
} else { } else {
throw KobaltException("Couldn't find latest artifact for $group:$artifactId") throw KobaltException("Couldn't find latest artifact for $group:$artifactId")
@ -143,7 +157,7 @@ class Aether(val localRepo: File, val settings: KobaltSettings, val eventBus: Ev
return result return result
} }
fun resolve(artifact: Artifact, isTest: Boolean = false): List<ArtifactResult> { fun resolve(artifact: Artifact, artifactScope: Scope?, filterScopes: Collection<Scope>): List<ArtifactResult> {
fun manageException(ex: Exception, artifact: Artifact): List<ArtifactResult> { fun manageException(ex: Exception, artifact: Artifact): List<ArtifactResult> {
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
@ -154,8 +168,8 @@ class Aether(val localRepo: File, val settings: KobaltSettings, val eventBus: Ev
} }
try { try {
val dependencyRequest = DependencyRequest(collectRequest(artifact, isTest), val scopeFilter = Scope.toFilter(filterScopes)
if (isTest) testClasspathFilter else classpathFilter) val dependencyRequest = DependencyRequest(collectRequest(artifact, artifactScope), scopeFilter)
val result = system.resolveDependencies(session, dependencyRequest).artifactResults val result = system.resolveDependencies(session, dependencyRequest).artifactResults
return result return result
} catch(ex: ArtifactNotFoundException) { } catch(ex: ArtifactNotFoundException) {
@ -165,10 +179,10 @@ class Aether(val localRepo: File, val settings: KobaltSettings, val eventBus: Ev
} }
} }
fun transitiveDependencies(artifact: Artifact) = directDependencies(artifact) // fun transitiveDependencies(artifact: Artifact) = directDependencies(artifact)
fun directDependencies(artifact: Artifact, isTest: Boolean = false): CollectResult? fun directDependencies(artifact: Artifact, artifactScope: Scope? = null): CollectResult?
= system.collectDependencies(session, collectRequest(artifact, isTest)) = system.collectDependencies(session, collectRequest(artifact, artifactScope))
} }
class AetherDependency(val artifact: Artifact) : IClasspathDependency, Comparable<AetherDependency> { class AetherDependency(val artifact: Artifact) : IClasspathDependency, Comparable<AetherDependency> {
@ -194,12 +208,16 @@ class AetherDependency(val artifact: Artifact) : IClasspathDependency, Comparabl
if (file.exists()) { if (file.exists()) {
CompletedFuture(file) CompletedFuture(file)
} else { } else {
val td = aether.resolve(artifact) val td = aether.resolve(artifact, null, emptyList())
val newFile = td[0].artifact.file if (td.any()) {
if (newFile != null) { val newFile = td[0].artifact.file
CompletedFuture(newFile) if (newFile != null) {
CompletedFuture(newFile)
} else {
CompletedFuture(File("DOESNOTEXIST $id")) // will be filtered out
}
} else { } else {
CompletedFuture(File("DONOTEXIST")) // will be filtered out CompletedFuture(File("DOESNOTEXIST $id"))
} }
} }
} }
@ -277,3 +295,4 @@ fun main(argv: Array<String>) {
// println("Artifact: " + d) // println("Artifact: " + d)
} }

View file

@ -7,6 +7,7 @@ import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.archive.Archives import com.beust.kobalt.archive.Archives
import com.beust.kobalt.internal.ActorUtils import com.beust.kobalt.internal.ActorUtils
import com.beust.kobalt.maven.DependencyManager import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.maven.aether.Scope
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.beust.kobalt.misc.RunCommand import com.beust.kobalt.misc.RunCommand
@ -105,7 +106,9 @@ class ApplicationPlugin @Inject constructor(val configActor: ConfigActor<Applica
// on the classpath // on the classpath
val allDependencies = project.compileDependencies + project.compileRuntimeDependencies val allDependencies = project.compileDependencies + project.compileRuntimeDependencies
val allTheDependencies = val allTheDependencies =
dependencyManager.calculateDependencies(project, context, allDependencies = allDependencies) dependencyManager.calculateDependencies(project, context,
listOf(Scope.COMPILE, Scope.RUNTIME),
passedDependencies = allDependencies)
.map { it.jarFile.get().path } .map { it.jarFile.get().path }
allDeps.addAll(allTheDependencies) allDeps.addAll(allTheDependencies)
} }

View file

@ -121,7 +121,7 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana
val analyzer = Analyzer().apply { val analyzer = Analyzer().apply {
jar = aQute.bnd.osgi.Jar(project.projectProperties.get(Archives.JAR_NAME) as String) jar = aQute.bnd.osgi.Jar(project.projectProperties.get(Archives.JAR_NAME) as String)
val dependencies = project.compileDependencies + project.compileRuntimeDependencies val dependencies = project.compileDependencies + project.compileRuntimeDependencies
dependencyManager.calculateDependencies(project, context, allDependencies = dependencies).forEach { dependencyManager.calculateDependencies(project, context, passedDependencies = dependencies).forEach {
addClasspath(it.jarFile.get()) addClasspath(it.jarFile.get())
} }
setProperty(Analyzer.BUNDLE_VERSION, project.version) setProperty(Analyzer.BUNDLE_VERSION, project.version)

View file

@ -40,7 +40,7 @@ class WarGenerator @Inject constructor(val dependencyManager: DependencyManager)
// Copy them all in kobaltBuild/war/WEB-INF/libs and create one IncludedFile out of that directory // Copy them all in kobaltBuild/war/WEB-INF/libs and create one IncludedFile out of that directory
// //
val allDependencies = dependencyManager.calculateDependencies(project, context, val allDependencies = dependencyManager.calculateDependencies(project, context,
allDependencies = project.compileDependencies) passedDependencies = project.compileDependencies)
val outDir = project.buildDirectory + "/war" val outDir = project.buildDirectory + "/war"
val fullDir = outDir + "/" + LIB val fullDir = outDir + "/" + LIB

View file

@ -1,14 +1,38 @@
package com.beust.kobalt package com.beust.kobalt
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.app.BuildFileCompiler
import com.beust.kobalt.internal.JvmCompilerPlugin
import com.beust.kobalt.internal.KobaltPluginXml
import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.build.BuildFile
import com.beust.kobalt.maven.aether.KobaltAether import com.beust.kobalt.maven.aether.KobaltAether
import org.testng.annotations.BeforeClass import org.testng.annotations.BeforeClass
import java.io.File
import java.nio.file.Paths
open class BaseTest(open val aether: KobaltAether) { open class BaseTest(open val aether: KobaltAether) {
val context = KobaltContext(Args()) val context = KobaltContext(Args())
@BeforeClass @BeforeClass
fun bc() { fun bc() {
Kobalt.init(TestModule())
context.aether = aether context.aether = aether
} }
fun compileBuildFile(buildFileText: String, args: Args, compilerFactory: BuildFileCompiler.IFactory)
: BuildFileCompiler.FindProjectResult {
val tmpBuildFile = File.createTempFile("kobaltTest", "").apply {
deleteOnExit()
writeText(buildFileText)
}
val thisBuildFile = BuildFile(Paths.get(tmpBuildFile.absolutePath), "Build.kt")
args.buildFile = tmpBuildFile.absolutePath
val jvmCompilerPlugin = Kobalt.findPlugin("JvmCompiler") as JvmCompilerPlugin
val pluginInfo = PluginInfo(KobaltPluginXml(), null, null).apply {
projectContributors.add(jvmCompilerPlugin)
}
return compilerFactory.create(listOf(thisBuildFile), pluginInfo).compileBuildFiles(args)
}
} }

View file

@ -1,45 +1,30 @@
package com.beust.kobalt.internal package com.beust.kobalt.internal
import com.beust.kobalt.Args import com.beust.kobalt.Args
import com.beust.kobalt.BaseTest
import com.beust.kobalt.TestModule import com.beust.kobalt.TestModule
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.app.BuildFileCompiler import com.beust.kobalt.app.BuildFileCompiler
import com.beust.kobalt.internal.build.BuildFile import com.beust.kobalt.maven.aether.KobaltAether
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.testng.annotations.Guice import org.testng.annotations.Guice
import org.testng.annotations.Test import org.testng.annotations.Test
import java.io.File
import java.nio.file.Paths
@Guice(modules = arrayOf(TestModule::class)) @Guice(modules = arrayOf(TestModule::class))
class ProfileTest @Inject constructor(val compilerFactory: BuildFileCompiler.IFactory) { class ProfileTest @Inject constructor(val compilerFactory: BuildFileCompiler.IFactory,
override val aether: KobaltAether) : BaseTest(aether) {
private fun compileBuildFile(buildFileText: String, args: Args, compilerFactory: BuildFileCompiler.IFactory)
: BuildFileCompiler.FindProjectResult {
val tmpBuildFile = File.createTempFile("kobaltTest", "").apply {
deleteOnExit()
writeText(buildFileText)
}
val thisBuildFile = BuildFile(Paths.get(tmpBuildFile.absolutePath), "Build.kt")
args.buildFile = tmpBuildFile.absolutePath
val jvmCompilerPlugin = Kobalt.findPlugin("JvmCompiler") as JvmCompilerPlugin
val pluginInfo = PluginInfo(KobaltPluginXml(), null, null).apply {
projectContributors.add(jvmCompilerPlugin)
}
return compilerFactory.create(listOf(thisBuildFile), pluginInfo).compileBuildFiles(args)
}
private fun runTestWithProfile(enabled: Boolean) : Project { private fun runTestWithProfile(enabled: Boolean) : Project {
val buildFileString = """ val buildFileString = """
| import com.beust.kobalt.* import com.beust.kobalt.*
| import com.beust.kobalt.api.* import com.beust.kobalt.api.*
| val profile = false val profile = false
| val p = project { val p = project {
| name = if (profile) "profileOn" else "profileOff" name = if (profile) "profileOn" else "profileOff"
| } }
""".trimMargin() """
val args = Args() val args = Args()
if (enabled) args.profiles = "profile" if (enabled) args.profiles = "profile"

View file

@ -1,38 +1,73 @@
package com.beust.kobalt.maven package com.beust.kobalt.maven
import com.beust.kobalt.Args
import com.beust.kobalt.BaseTest
import com.beust.kobalt.TestModule 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.app.BuildFileCompiler
import com.beust.kobalt.maven.aether.KobaltAether
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.testng.annotations.Guice import org.testng.annotations.Guice
import org.testng.annotations.Test import org.testng.annotations.Test
@Guice(modules = arrayOf(TestModule::class)) @Guice(modules = arrayOf(TestModule::class))
class DependencyManagerTest @Inject constructor(val dependencyManager: DependencyManager) { class DependencyManagerTest @Inject constructor(val dependencyManager: DependencyManager,
val compilerFactory: BuildFileCompiler.IFactory, override val aether: KobaltAether) : BaseTest(aether) {
private fun assertContains(dependencies: List<IClasspathDependency>, vararg ids: String) {
ids.forEach { id ->
assertThat(dependencies.any { it.id.contains(id) }).isTrue()
}
}
@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.9.11"))
fun assertContains(dependencies: List<IClasspathDependency>, vararg ids: String) {
ids.forEach { id ->
assertThat(dependencies.any { it.id.contains(id) }).isTrue()
}
}
// Should only resolve to TestNG // Should only resolve to TestNG
dependencyManager.transitiveClosure(testDeps, isTest = false).let { dependencies -> dependencyManager.transitiveClosure(testDeps, listOf(Scope.COMPILE)).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, isTest = true).let { dependencies -> dependencyManager.transitiveClosure(testDeps, listOf(Scope.TEST)).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, ":testng:")
} }
} }
@Test
fun honorRuntimeDependenciesBetweenProjects() {
val buildFileString = """
import com.beust.kobalt.*
val lib = project {
name = "lib"
dependencies {
compile("org.testng:testng:6.9.11")
runtime("com.beust:jcommander:1.48")
}
}
val p = project(lib) {
name = "transitive"
}
"""
val compileResult = compileBuildFile(buildFileString, Args(), compilerFactory)
val project2 = compileResult.projects[1]
val dependencies = dependencyManager.calculateDependencies(project2, Kobalt.context!!,
listOf(Scope.COMPILE, Scope.RUNTIME),
project2.compileDependencies + project2.compileRuntimeDependencies)
assertContains(dependencies, ":testng:")
assertContains(dependencies, ":jcommander:")
}
} }

View file

@ -160,7 +160,7 @@ class DownloadTest @Inject constructor(
@Test @Test
fun variablesShouldBeExpanded() { fun variablesShouldBeExpanded() {
val dep = dependencyManager.createMaven("org.mapdb:mapdb:3.0.0-M3") val dep = dependencyManager.createMaven("org.mapdb:mapdb:3.0.0-M3")
val closure = dependencyManager.transitiveClosure(listOf(dep), false, "<testProject>") val closure = dependencyManager.transitiveClosure(listOf(dep), requiredBy = "<testProject>")
val d = closure.filter { it.id.contains("eclipse-collections-api")} val d = closure.filter { it.id.contains("eclipse-collections-api")}
Assert.assertEquals(d.size, 1) Assert.assertEquals(d.size, 1)
} }