[Scripting] Allow transitive resolution of non-JAR artifacts
It allows to resolve libraries sources which is crucial for Kotlin Notebook plugin.
This commit is contained in:
+6
-5
@@ -5,14 +5,13 @@
|
|||||||
|
|
||||||
package kotlin.script.experimental.dependencies.maven
|
package kotlin.script.experimental.dependencies.maven
|
||||||
|
|
||||||
|
import org.eclipse.aether.RepositoryException
|
||||||
import org.eclipse.aether.artifact.DefaultArtifact
|
import org.eclipse.aether.artifact.DefaultArtifact
|
||||||
import org.eclipse.aether.repository.RemoteRepository
|
import org.eclipse.aether.repository.RemoteRepository
|
||||||
import org.eclipse.aether.resolution.ArtifactResolutionException
|
import org.eclipse.aether.resolution.ArtifactResolutionException
|
||||||
import org.eclipse.aether.resolution.DependencyResolutionException
|
|
||||||
import org.eclipse.aether.util.artifact.JavaScopes
|
import org.eclipse.aether.util.artifact.JavaScopes
|
||||||
import org.eclipse.aether.util.repository.AuthenticationBuilder
|
import org.eclipse.aether.util.repository.AuthenticationBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.dependencies.ExternalDependenciesResolver
|
import kotlin.script.experimental.dependencies.ExternalDependenciesResolver
|
||||||
import kotlin.script.experimental.dependencies.RepositoryCoordinates
|
import kotlin.script.experimental.dependencies.RepositoryCoordinates
|
||||||
@@ -63,13 +62,15 @@ class MavenDependenciesResolver : ExternalDependenciesResolver {
|
|||||||
return 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 transitive = options.transitive ?: true
|
||||||
|
val classifier = options.classifier
|
||||||
|
val extension = options.extension
|
||||||
val deps = AetherResolveSession(
|
val deps = AetherResolveSession(
|
||||||
localRepo, remoteRepositories()
|
localRepo, remoteRepositories()
|
||||||
).resolve(
|
).resolve(
|
||||||
artifactId, dependencyScopes.joinToString(","), transitive, null
|
artifactId, dependencyScopes.joinToString(","), transitive, null, classifier, extension
|
||||||
)
|
)
|
||||||
ResultWithDiagnostics.Success(deps.map { it.file })
|
ResultWithDiagnostics.Success(deps.map { it.file })
|
||||||
} catch (e: DependencyResolutionException) {
|
} catch (e: RepositoryException) {
|
||||||
makeResolveFailureResult(e, sourceCodeLocation)
|
makeResolveFailureResult(e, sourceCodeLocation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +161,7 @@ class MavenDependenciesResolver : ExternalDependenciesResolver {
|
|||||||
private val FORBIDDEN_CHARS = Regex("[/\\\\:<>\"|?*]")
|
private val FORBIDDEN_CHARS = Regex("[/\\\\:<>\"|?*]")
|
||||||
|
|
||||||
private fun makeResolveFailureResult(
|
private fun makeResolveFailureResult(
|
||||||
exception: DependencyResolutionException,
|
exception: Throwable,
|
||||||
location: SourceCode.LocationWithId?
|
location: SourceCode.LocationWithId?
|
||||||
): ResultWithDiagnostics.Failure {
|
): ResultWithDiagnostics.Failure {
|
||||||
val allCauses = generateSequence(exception) { e: Throwable -> e.cause }.toList()
|
val allCauses = generateSequence(exception) { e: Throwable -> e.cause }.toList()
|
||||||
|
|||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package kotlin.script.experimental.dependencies.maven.impl
|
||||||
|
|
||||||
|
import org.eclipse.aether.artifact.Artifact
|
||||||
|
import org.eclipse.aether.graph.DependencyNode
|
||||||
|
import org.eclipse.aether.graph.DependencyVisitor
|
||||||
|
import org.eclipse.aether.resolution.ArtifactRequest
|
||||||
|
import org.eclipse.aether.util.artifact.DelegatingArtifact
|
||||||
|
|
||||||
|
internal class ArtifactRequestBuilder(
|
||||||
|
private val classifier: String?,
|
||||||
|
private val extension: String?,
|
||||||
|
) : DependencyVisitor {
|
||||||
|
private val result: MutableList<ArtifactRequest> = ArrayList()
|
||||||
|
|
||||||
|
override fun visitEnter(node: DependencyNode): Boolean {
|
||||||
|
val dep = node.dependency
|
||||||
|
if (dep != null) {
|
||||||
|
val artifact = dep.artifact
|
||||||
|
result.add(
|
||||||
|
ArtifactRequest(
|
||||||
|
ArtifactWithAnotherKind(artifact, classifier, extension),
|
||||||
|
node.repositories,
|
||||||
|
node.requestContext
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLeave(node: DependencyNode): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val requests: List<ArtifactRequest>
|
||||||
|
get() = result
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ArtifactWithAnotherKind(
|
||||||
|
artifact: Artifact,
|
||||||
|
private val myClassifier: String?,
|
||||||
|
private val myExtension: String?,
|
||||||
|
) : DelegatingArtifact(artifact) {
|
||||||
|
override fun newInstance(artifact: Artifact): DelegatingArtifact {
|
||||||
|
return ArtifactWithAnotherKind(artifact, myClassifier, myExtension)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getClassifier(): String {
|
||||||
|
return myClassifier ?: super.getClassifier()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtension(): String {
|
||||||
|
return myExtension ?: super.getExtension()
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
-20
@@ -19,6 +19,8 @@ import org.eclipse.aether.RepositorySystem
|
|||||||
import org.eclipse.aether.RepositorySystemSession
|
import org.eclipse.aether.RepositorySystemSession
|
||||||
import org.eclipse.aether.artifact.Artifact
|
import org.eclipse.aether.artifact.Artifact
|
||||||
import org.eclipse.aether.collection.CollectRequest
|
import org.eclipse.aether.collection.CollectRequest
|
||||||
|
import org.eclipse.aether.collection.CollectResult
|
||||||
|
import org.eclipse.aether.collection.DependencyCollectionException
|
||||||
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory
|
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory
|
||||||
import org.eclipse.aether.graph.Dependency
|
import org.eclipse.aether.graph.Dependency
|
||||||
import org.eclipse.aether.graph.DependencyFilter
|
import org.eclipse.aether.graph.DependencyFilter
|
||||||
@@ -35,6 +37,8 @@ import org.eclipse.aether.transport.wagon.WagonConfigurator
|
|||||||
import org.eclipse.aether.transport.wagon.WagonProvider
|
import org.eclipse.aether.transport.wagon.WagonProvider
|
||||||
import org.eclipse.aether.transport.wagon.WagonTransporterFactory
|
import org.eclipse.aether.transport.wagon.WagonTransporterFactory
|
||||||
import org.eclipse.aether.util.filter.DependencyFilterUtils
|
import org.eclipse.aether.util.filter.DependencyFilterUtils
|
||||||
|
import org.eclipse.aether.util.graph.visitor.FilteringDependencyVisitor
|
||||||
|
import org.eclipse.aether.util.graph.visitor.TreeDependencyVisitor
|
||||||
import org.eclipse.aether.util.repository.AuthenticationBuilder
|
import org.eclipse.aether.util.repository.AuthenticationBuilder
|
||||||
import org.eclipse.aether.util.repository.DefaultMirrorSelector
|
import org.eclipse.aether.util.repository.DefaultMirrorSelector
|
||||||
import org.eclipse.aether.util.repository.DefaultProxySelector
|
import org.eclipse.aether.util.repository.DefaultProxySelector
|
||||||
@@ -127,32 +131,48 @@ internal class AetherResolveSession(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resolve(root: Artifact, scope: String, transitive: Boolean, filter: DependencyFilter?): List<Artifact> {
|
fun resolve(
|
||||||
return if (transitive) resolveDependencies(root, scope, filter)
|
root: Artifact,
|
||||||
|
scope: String,
|
||||||
|
transitive: Boolean,
|
||||||
|
filter: DependencyFilter?,
|
||||||
|
classifier: String? = null,
|
||||||
|
extension: String? = null,
|
||||||
|
): List<Artifact> {
|
||||||
|
return if (transitive) resolveDependencies(root, scope, filter, classifier, extension)
|
||||||
else resolveArtifact(root)
|
else resolveArtifact(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveDependencies(root: Artifact, scope: String, filter: DependencyFilter? = null): List<Artifact> {
|
private fun resolveDependencies(
|
||||||
|
root: Artifact,
|
||||||
|
scope: String,
|
||||||
|
filter: DependencyFilter?,
|
||||||
|
classifier: String?,
|
||||||
|
extension: String?,
|
||||||
|
): List<Artifact> {
|
||||||
return fetch(
|
return fetch(
|
||||||
DependencyRequest(
|
request(Dependency(root, scope)),
|
||||||
request(Dependency(root, scope)),
|
{ req ->
|
||||||
filter ?: DependencyFilterUtils.classpathFilter(scope)
|
val requestsBuilder = ArtifactRequestBuilder(classifier, extension)
|
||||||
),
|
val collectionResult = repositorySystem.collectDependencies(repositorySystemSession, req)
|
||||||
{ req -> repositorySystem.resolveDependencies(repositorySystemSession, req).artifactResults },
|
collectionResult.root.accept(
|
||||||
{ req, ex ->
|
TreeDependencyVisitor(
|
||||||
DependencyResolutionException(
|
FilteringDependencyVisitor(
|
||||||
DependencyResult(req),
|
requestsBuilder,
|
||||||
IllegalArgumentException( //Logger.format(
|
filter ?: DependencyFilterUtils.classpathFilter(scope)
|
||||||
// "failed to load '%s' from %[list]s into %s",
|
)
|
||||||
// req.getCollectRequest().getRoot(),
|
|
||||||
// Aether.reps(req.getCollectRequest().getRepositories()),
|
|
||||||
// session.getLocalRepositoryManager()
|
|
||||||
// .getRepository()
|
|
||||||
// .getBasedir()
|
|
||||||
//),
|
|
||||||
ex
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val requests = requestsBuilder.requests
|
||||||
|
repositorySystem.resolveArtifacts(repositorySystemSession, requests)
|
||||||
|
},
|
||||||
|
{ req, ex ->
|
||||||
|
DependencyCollectionException(
|
||||||
|
CollectResult(req),
|
||||||
|
ex.message,
|
||||||
|
ex
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -51,6 +51,8 @@ class MavenResolverTest : ResolversTestBase() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun parseOptions(options: String) = SimpleExternalDependenciesResolverOptionsParser(options).valueOrThrow()
|
||||||
|
|
||||||
private val resolvedKotlinVersion = "1.5.31"
|
private val resolvedKotlinVersion = "1.5.31"
|
||||||
|
|
||||||
fun testResolveSimple() {
|
fun testResolveSimple() {
|
||||||
@@ -77,7 +79,6 @@ class MavenResolverTest : ResolversTestBase() {
|
|||||||
val dependency = "junit:junit:4.11"
|
val dependency = "junit:junit:4.11"
|
||||||
|
|
||||||
var transitiveFiles: Iterable<File>
|
var transitiveFiles: Iterable<File>
|
||||||
fun parseOptions(options: String) = SimpleExternalDependenciesResolverOptionsParser(options).valueOrThrow()
|
|
||||||
|
|
||||||
resolveAndCheck(dependency, options = parseOptions("transitive=true")) { files ->
|
resolveAndCheck(dependency, options = parseOptions("transitive=true")) { files ->
|
||||||
transitiveFiles = files
|
transitiveFiles = files
|
||||||
@@ -98,6 +99,16 @@ class MavenResolverTest : ResolversTestBase() {
|
|||||||
assertEquals("jar", artifact.extension)
|
assertEquals("jar", artifact.extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testSourcesResolution() {
|
||||||
|
resolveAndCheck("junit:junit:4.11", options = parseOptions("classifier=sources extension=jar")) { files ->
|
||||||
|
assertEquals(2, files.count())
|
||||||
|
files.forEach {
|
||||||
|
assertTrue(it.name.endsWith("-sources.jar"))
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun testResolveVersionsRange() {
|
fun testResolveVersionsRange() {
|
||||||
resolveAndCheck("org.jetbrains.kotlin:kotlin-annotations-jvm:(1.3.40,$resolvedKotlinVersion)")
|
resolveAndCheck("org.jetbrains.kotlin:kotlin-annotations-jvm:(1.3.40,$resolvedKotlinVersion)")
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-1
@@ -27,7 +27,9 @@ enum class DependenciesResolverOptionsName(optionName: String? = null) {
|
|||||||
USERNAME,
|
USERNAME,
|
||||||
PASSWORD,
|
PASSWORD,
|
||||||
KEY_FILE,
|
KEY_FILE,
|
||||||
KEY_PASSPHRASE;
|
KEY_PASSPHRASE,
|
||||||
|
CLASSIFIER,
|
||||||
|
EXTENSION;
|
||||||
|
|
||||||
val key = optionName ?: name.lowercase()
|
val key = optionName ?: name.lowercase()
|
||||||
}
|
}
|
||||||
@@ -61,3 +63,15 @@ val ExternalDependenciesResolver.Options.privateKeyFile
|
|||||||
*/
|
*/
|
||||||
val ExternalDependenciesResolver.Options.privateKeyPassphrase
|
val ExternalDependenciesResolver.Options.privateKeyPassphrase
|
||||||
get() = value(DependenciesResolverOptionsName.KEY_PASSPHRASE)
|
get() = value(DependenciesResolverOptionsName.KEY_PASSPHRASE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classifier of all resolved artifacts
|
||||||
|
*/
|
||||||
|
val ExternalDependenciesResolver.Options.classifier
|
||||||
|
get() = value(DependenciesResolverOptionsName.CLASSIFIER)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension of all resolved artifacts
|
||||||
|
*/
|
||||||
|
val ExternalDependenciesResolver.Options.extension
|
||||||
|
get() = value(DependenciesResolverOptionsName.EXTENSION)
|
||||||
|
|||||||
Reference in New Issue
Block a user