[Scripting] Add transitive support for Maven Resolver
This commit is contained in:
+5
-8
@@ -49,8 +49,6 @@ class MavenDependenciesResolver : ExternalDependenciesResolver {
|
|||||||
|
|
||||||
private fun remoteRepositories() = if (repos.isEmpty()) arrayListOf(mavenCentral) else repos
|
private fun remoteRepositories() = if (repos.isEmpty()) arrayListOf(mavenCentral) else repos
|
||||||
|
|
||||||
private fun allRepositories() = remoteRepositories() + localRepo
|
|
||||||
|
|
||||||
private fun String.toMavenArtifact(): DefaultArtifact? =
|
private fun String.toMavenArtifact(): DefaultArtifact? =
|
||||||
if (this.isNotBlank() && this.count { it == ':' } >= 2) DefaultArtifact(this)
|
if (this.isNotBlank() && this.count { it == ':' } >= 2) DefaultArtifact(this)
|
||||||
else null
|
else null
|
||||||
@@ -63,19 +61,18 @@ class MavenDependenciesResolver : ExternalDependenciesResolver {
|
|||||||
|
|
||||||
val artifactId = artifactCoordinates.toMavenArtifact()!!
|
val artifactId = artifactCoordinates.toMavenArtifact()!!
|
||||||
|
|
||||||
try {
|
return try {
|
||||||
val dependencyScopes = options.dependencyScopes ?: listOf(JavaScopes.COMPILE, JavaScopes.RUNTIME)
|
val dependencyScopes = options.dependencyScopes ?: listOf(JavaScopes.COMPILE, JavaScopes.RUNTIME)
|
||||||
|
val transitive = options.transitive ?: true
|
||||||
val deps = AetherResolveSession(
|
val deps = AetherResolveSession(
|
||||||
localRepo, remoteRepositories()
|
localRepo, remoteRepositories()
|
||||||
).resolve(
|
).resolve(
|
||||||
artifactId, dependencyScopes.joinToString(",")
|
artifactId, dependencyScopes.joinToString(","), transitive, null
|
||||||
)
|
)
|
||||||
if (deps != null)
|
ResultWithDiagnostics.Success(deps.map { it.file })
|
||||||
return ResultWithDiagnostics.Success(deps.map { it.file })
|
|
||||||
} catch (e: DependencyResolutionException) {
|
} catch (e: DependencyResolutionException) {
|
||||||
return makeResolveFailureResult(e.message ?: "unknown error", sourceCodeLocation)
|
makeResolveFailureResult(e.message ?: "unknown error", sourceCodeLocation)
|
||||||
}
|
}
|
||||||
return makeResolveFailureResult(allRepositories().map { "$it: $artifactId not found" }, sourceCodeLocation)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryResolveEnvironmentVariable(str: String) =
|
private fun tryResolveEnvironmentVariable(str: String) =
|
||||||
|
|||||||
+46
-26
@@ -25,10 +25,7 @@ import org.eclipse.aether.internal.transport.wagon.PlexusWagonProvider
|
|||||||
import org.eclipse.aether.repository.LocalRepository
|
import org.eclipse.aether.repository.LocalRepository
|
||||||
import org.eclipse.aether.repository.Proxy
|
import org.eclipse.aether.repository.Proxy
|
||||||
import org.eclipse.aether.repository.RemoteRepository
|
import org.eclipse.aether.repository.RemoteRepository
|
||||||
import org.eclipse.aether.resolution.ArtifactResult
|
import org.eclipse.aether.resolution.*
|
||||||
import org.eclipse.aether.resolution.DependencyRequest
|
|
||||||
import org.eclipse.aether.resolution.DependencyResolutionException
|
|
||||||
import org.eclipse.aether.resolution.DependencyResult
|
|
||||||
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory
|
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory
|
||||||
import org.eclipse.aether.spi.connector.transport.TransporterFactory
|
import org.eclipse.aether.spi.connector.transport.TransporterFactory
|
||||||
import org.eclipse.aether.transport.file.FileTransporterFactory
|
import org.eclipse.aether.transport.file.FileTransporterFactory
|
||||||
@@ -123,22 +120,54 @@ class AetherResolveSession(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resolve(coordinates: String, scope: String, filter: DependencyFilter? = null): List<Artifact>? =
|
fun resolve(coordinates: String, scope: String, filter: DependencyFilter? = null): List<Artifact> =
|
||||||
resolve(DefaultArtifact(coordinates), scope, filter)
|
resolve(DefaultArtifact(coordinates), scope, filter)
|
||||||
|
|
||||||
fun resolve(root: Artifact, scope: String, filter: DependencyFilter? = null): List<Artifact>? {
|
fun resolve(root: Artifact, scope: String, transitive: Boolean, filter: DependencyFilter?): List<Artifact> {
|
||||||
|
return if (transitive) resolve(root, scope, filter)
|
||||||
|
else resolveArtifact(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resolve(root: Artifact, scope: String, filter: DependencyFilter? = null): List<Artifact> {
|
||||||
return fetch(
|
return fetch(
|
||||||
repositorySystem,
|
|
||||||
repositorySystemSession,
|
|
||||||
DependencyRequest(
|
DependencyRequest(
|
||||||
request(Dependency(root, scope)),
|
request(Dependency(root, scope)),
|
||||||
filter ?: DependencyFilterUtils.classpathFilter(scope)
|
filter ?: DependencyFilterUtils.classpathFilter(scope)
|
||||||
)
|
),
|
||||||
|
{ req -> repositorySystem.resolveDependencies(repositorySystemSession, req).artifactResults },
|
||||||
|
{ req, ex ->
|
||||||
|
DependencyResolutionException(
|
||||||
|
DependencyResult(req),
|
||||||
|
IllegalArgumentException( //Logger.format(
|
||||||
|
// "failed to load '%s' from %[list]s into %s",
|
||||||
|
// req.getCollectRequest().getRoot(),
|
||||||
|
// Aether.reps(req.getCollectRequest().getRepositories()),
|
||||||
|
// session.getLocalRepositoryManager()
|
||||||
|
// .getRepository()
|
||||||
|
// .getBasedir()
|
||||||
|
//),
|
||||||
|
ex
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun request(root: Dependency): CollectRequest? {
|
private fun resolveArtifact(artifact: Artifact): List<Artifact> {
|
||||||
|
val request = ArtifactRequest()
|
||||||
|
request.artifact = artifact
|
||||||
|
for (repo in remotes) {
|
||||||
|
request.addRepository(repo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(
|
||||||
|
request,
|
||||||
|
{ req -> listOf(repositorySystem.resolveArtifact(repositorySystemSession, req)) },
|
||||||
|
{ req, ex -> ArtifactResolutionException(listOf(ArtifactResult(req)), ex.message, IllegalArgumentException(ex)) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun request(root: Dependency): CollectRequest {
|
||||||
val request = CollectRequest()
|
val request = CollectRequest()
|
||||||
request.root = root
|
request.root = root
|
||||||
for (repo in remotes) {
|
for (repo in remotes) {
|
||||||
@@ -147,32 +176,23 @@ class AetherResolveSession(
|
|||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetch(system: RepositorySystem, session: RepositorySystemSession, dreq: DependencyRequest): List<Artifact>? {
|
private fun <RequestT> fetch(
|
||||||
|
request: RequestT,
|
||||||
|
fetchBody: (RequestT) -> Collection<ArtifactResult>,
|
||||||
|
wrapException: (RequestT, Exception) -> Exception
|
||||||
|
): List<Artifact> {
|
||||||
val deps: MutableList<Artifact> = LinkedList()
|
val deps: MutableList<Artifact> = LinkedList()
|
||||||
try {
|
try {
|
||||||
var results: Collection<ArtifactResult>
|
var results: Collection<ArtifactResult>
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
results = system.resolveDependencies(session, dreq)
|
results = fetchBody(request)
|
||||||
.artifactResults
|
|
||||||
}
|
}
|
||||||
for (res in results) {
|
for (res in results) {
|
||||||
deps.add(res.artifact)
|
deps.add(res.artifact)
|
||||||
}
|
}
|
||||||
// @checkstyle IllegalCatch (1 line)
|
// @checkstyle IllegalCatch (1 line)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
throw DependencyResolutionException(
|
throw wrapException(request, ex)
|
||||||
DependencyResult(dreq),
|
|
||||||
IllegalArgumentException( //Logger.format(
|
|
||||||
// "failed to load '%s' from %[list]s into %s",
|
|
||||||
// dreq.getCollectRequest().getRoot(),
|
|
||||||
// Aether.reps(dreq.getCollectRequest().getRepositories()),
|
|
||||||
// session.getLocalRepositoryManager()
|
|
||||||
// .getRepository()
|
|
||||||
// .getBasedir()
|
|
||||||
//),
|
|
||||||
ex
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return deps
|
return deps
|
||||||
}
|
}
|
||||||
|
|||||||
+31
@@ -10,12 +10,15 @@ import org.junit.Assert
|
|||||||
import org.junit.Ignore
|
import org.junit.Ignore
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
import kotlin.reflect.full.primaryConstructor
|
import kotlin.reflect.full.primaryConstructor
|
||||||
import kotlin.script.experimental.dependencies.maven.MavenDependenciesResolver
|
import kotlin.script.experimental.dependencies.maven.MavenDependenciesResolver
|
||||||
import kotlin.script.experimental.api.ResultWithDiagnostics
|
import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||||
import kotlin.script.experimental.api.valueOrThrow
|
import kotlin.script.experimental.api.valueOrThrow
|
||||||
import kotlin.script.experimental.dependencies.*
|
import kotlin.script.experimental.dependencies.*
|
||||||
import kotlin.script.experimental.dependencies.impl.DependenciesResolverOptionsName
|
import kotlin.script.experimental.dependencies.impl.DependenciesResolverOptionsName
|
||||||
|
import kotlin.script.experimental.dependencies.impl.SimpleExternalDependenciesResolverOptionsParser
|
||||||
import kotlin.script.experimental.dependencies.impl.makeExternalDependenciesResolverOptions
|
import kotlin.script.experimental.dependencies.impl.makeExternalDependenciesResolverOptions
|
||||||
import kotlin.script.experimental.dependencies.impl.set
|
import kotlin.script.experimental.dependencies.impl.set
|
||||||
|
|
||||||
@@ -27,6 +30,9 @@ class MavenResolverTest : ResolversTestBase() {
|
|||||||
options: ExternalDependenciesResolver.Options = ExternalDependenciesResolver.Options.Empty,
|
options: ExternalDependenciesResolver.Options = ExternalDependenciesResolver.Options.Empty,
|
||||||
checkBody: (Iterable<File>) -> Boolean = { true }
|
checkBody: (Iterable<File>) -> Boolean = { true }
|
||||||
) {
|
) {
|
||||||
|
contract {
|
||||||
|
callsInPlace(checkBody, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
val resolver = MavenDependenciesResolver()
|
val resolver = MavenDependenciesResolver()
|
||||||
val result = runBlocking { resolver.resolve(coordinates, options) }
|
val result = runBlocking { resolver.resolve(coordinates, options) }
|
||||||
if (result is ResultWithDiagnostics.Failure) {
|
if (result is ResultWithDiagnostics.Failure) {
|
||||||
@@ -74,6 +80,31 @@ class MavenResolverTest : ResolversTestBase() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testTransitiveOption() {
|
||||||
|
val dependency = "junit:junit:4.11"
|
||||||
|
|
||||||
|
var transitiveFiles: Iterable<File>
|
||||||
|
fun parseOptions(options: String) = SimpleExternalDependenciesResolverOptionsParser(options).valueOrThrow()
|
||||||
|
|
||||||
|
resolveAndCheck(dependency, options = parseOptions("transitive=true")) { files ->
|
||||||
|
transitiveFiles = files
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
var nonTransitiveFiles: Iterable<File>
|
||||||
|
resolveAndCheck(dependency, options = parseOptions("transitive=false")) { files ->
|
||||||
|
nonTransitiveFiles = files
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
val tCount = transitiveFiles.count()
|
||||||
|
val ntCount = nonTransitiveFiles.count()
|
||||||
|
val artifact = nonTransitiveFiles.single()
|
||||||
|
|
||||||
|
assertTrue(ntCount < tCount)
|
||||||
|
assertEquals("jar", artifact.extension)
|
||||||
|
}
|
||||||
|
|
||||||
fun testResolveVersionsRange() {
|
fun testResolveVersionsRange() {
|
||||||
resolveAndCheck("org.jetbrains.kotlin:kotlin-annotations-jvm:(1.3.40,1.3.60)")
|
resolveAndCheck("org.jetbrains.kotlin:kotlin-annotations-jvm:(1.3.40,1.3.60)")
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ private val equalsRegex = Regex("^[^\\S\\r\\n]*=")
|
|||||||
* And additionally supports flags without any equality statement:
|
* And additionally supports flags without any equality statement:
|
||||||
* `foo bar`
|
* `foo bar`
|
||||||
*/
|
*/
|
||||||
internal object SimpleExternalDependenciesResolverOptionsParser {
|
object SimpleExternalDependenciesResolverOptionsParser {
|
||||||
private sealed class Token {
|
private sealed class Token {
|
||||||
data class Name(val name: String) : Token()
|
data class Name(val name: String) : Token()
|
||||||
data class Value(val value: String) : Token()
|
data class Value(val value: String) : Token()
|
||||||
|
|||||||
Reference in New Issue
Block a user