Refactor ivy resolver

add support for artifacts with type an classifier
use ibiblio resolver by default - it is designed for working with maven central
add test, but disable it - see comments for the reason and todos
This commit is contained in:
Ilya Chernikov
2019-03-18 18:02:44 +01:00
parent fc9a6dec7e
commit dd3ac74bd2
3 changed files with 60 additions and 27 deletions
@@ -44,6 +44,21 @@ class MainKtsTest {
)
}
// @Test
// this test is disabled: the resolving works fine, but ivy resolver is not processing "pom"-type dependencies correctly (
// as far as I can tell)
// TODO: 1. find non-default but non-pom dependency suitable for an example to test resolving
// TODO: 2. implement proper handling of pom-typed dependencies (e.g. consider to reimplement it on aether as in JarRepositoryManager (from IDEA))
fun testResolveWithArtifactType() {
val res = evalFile(File("testData/resolve-moneta.main.kts"))
Assert.assertTrue(
"test failed:\n ${res.reports.joinToString("\n ") { it.message + if (it.exception == null) "" else ": ${it.exception}" }}",
res is ResultWithDiagnostics.Success
)
}
@Test
fun testUnresolvedJunit() {
val res = evalFile(File("testData/hello-unresolved-junit.main.kts"))
@@ -60,10 +75,10 @@ class MainKtsTest {
val res = evalFile(File("testData/hello-resolve-error.main.kts"))
Assert.assertTrue(
"test failed - expecting a failure with the message \"Unknown set of arguments to maven resolver: abracadabra\" but received " +
"test failed - expecting a failure with the message \"Unrecognized set of arguments to maven resolver: abracadabra\" but received " +
(if (res is ResultWithDiagnostics.Failure) "failure" else "success") +
":\n ${res.reports.joinToString("\n ") { it.message + if (it.exception == null) "" else ": ${it.exception}" }}",
res is ResultWithDiagnostics.Failure && res.reports.any { it.message.contains("Unknown set of arguments to maven resolver: abracadabra") })
res is ResultWithDiagnostics.Failure && res.reports.any { it.message.contains("Unrecognized set of arguments to ivy resolver: abracadabra") })
}
@Test
@@ -0,0 +1,7 @@
@file:DependsOn("org.javamoney:moneta:1.3@pom")
import org.javamoney.moneta.spi.MoneyUtils
println("getBigDecimal(1L): " + MoneyUtils.getBigDecimal(1L))
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.mainKts.impl
import org.apache.ivy.Ivy
import org.apache.ivy.core.LogOptions
import org.apache.ivy.core.module.descriptor.DefaultDependencyArtifactDescriptor
import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor
import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor
import org.apache.ivy.core.module.id.ModuleRevisionId
@@ -14,6 +15,8 @@ import org.apache.ivy.core.resolve.ResolveOptions
import org.apache.ivy.core.settings.IvySettings
import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter
import org.apache.ivy.plugins.resolver.ChainResolver
import org.apache.ivy.plugins.resolver.IBiblioResolver
import org.apache.ivy.plugins.resolver.IBiblioResolver.DEFAULT_M2_ROOT
import org.apache.ivy.plugins.resolver.URLResolver
import org.apache.ivy.util.DefaultMessageLogger
import org.apache.ivy.util.Message
@@ -24,38 +27,41 @@ import org.jetbrains.kotlin.script.util.resolvers.experimental.GenericRepository
import org.jetbrains.kotlin.script.util.resolvers.experimental.GenericRepositoryWithBridge
import org.jetbrains.kotlin.script.util.resolvers.experimental.MavenArtifactCoordinates
import java.io.File
import java.net.MalformedURLException
import java.net.URL
class IvyResolver : GenericRepositoryWithBridge {
private fun String?.isValidParam() = this?.isNotBlank() ?: false
override fun tryResolve(artifactCoordinates: GenericArtifactCoordinates): Iterable<File>? = with (artifactCoordinates) {
val artifactId =
if (this is MavenArtifactCoordinates && (groupId.isValidParam() || artifactId.isValidParam())) {
listOf(groupId.orEmpty(), artifactId.orEmpty(), version.orEmpty())
if (this is MavenArtifactCoordinates && (groupId.isValidParam() || artifactId.isValidParam())) {
resolveArtifact(groupId.orEmpty(), artifactId.orEmpty(), version.orEmpty())
} else {
val artifactType = string.substringAfterLast('@', "").trim()
val stringCoordinates = if (artifactType.isNotEmpty()) string.removeSuffix("@$artifactType") else string
if (stringCoordinates.isValidParam() && stringCoordinates.count { it == ':' }.let { it == 2 || it == 3 }) {
val artifactId = stringCoordinates.split(':')
resolveArtifact(
artifactId[0], artifactId[1], artifactId[2],
if (artifactId.size > 3) artifactId[3] else null,
if (artifactType.isNotEmpty()) artifactType else null
)
} else {
val stringCoordinates = string
if (stringCoordinates.isValidParam() && stringCoordinates.count { it == ':' } == 2) {
stringCoordinates.split(':')
} else {
error("Unknown set of arguments to maven resolver: $stringCoordinates")
}
error("Unrecognized set of arguments to ivy resolver: $stringCoordinates")
}
resolveArtifact(artifactId)
}
}
private val ivyResolvers = arrayListOf<URLResolver>()
private fun resolveArtifact(artifactId: List<String>): List<File> {
private fun resolveArtifact(
groupId: String, artifactName: String, revision: String, conf: String? = null, type: String? = null
): List<File> {
if (ivyResolvers.isEmpty() || ivyResolvers.none { it.name == "central" }) {
ivyResolvers.add(
URLResolver().apply {
IBiblioResolver().apply {
isM2compatible = true
name = "central"
addArtifactPattern("https://repo1.maven.org/maven2/$DEFAULT_ARTIFACT_PATTERN")
}
)
}
@@ -73,23 +79,21 @@ class IvyResolver : GenericRepositoryWithBridge {
val ivy = Ivy.newInstance(ivySettings)
val ivyfile = File.createTempFile("ivy", ".xml")
ivyfile.deleteOnExit()
val moduleDescriptor = DefaultModuleDescriptor.newDefaultInstance(
ModuleRevisionId.newInstance(artifactId[0], artifactId[1] + "-caller", "working")
ModuleRevisionId.newInstance(groupId, "$artifactName-caller", "working")
)
val depsDescriptor = DefaultDependencyDescriptor(
moduleDescriptor,
ModuleRevisionId.newInstance(artifactId[0], artifactId[1], artifactId[2]),
ModuleRevisionId.newInstance(groupId, artifactName, conf, revision),
false, false, true
)
if (type != null) {
val depArtifact = DefaultDependencyArtifactDescriptor(depsDescriptor, artifactName, type, type, null, null)
depsDescriptor.addDependencyArtifact(conf, depArtifact)
}
moduleDescriptor.addDependency(depsDescriptor)
//creates an ivy configuration file
XmlModuleDescriptorWriter.write(moduleDescriptor, ivyfile)
val resolveOptions = ResolveOptions().apply {
confs = arrayOf("default")
log = LogOptions.LOG_QUIET
@@ -97,7 +101,14 @@ class IvyResolver : GenericRepositoryWithBridge {
}
//init resolve report
val report = ivy.resolve(ivyfile.toURI().toURL(), resolveOptions)
// TODO: find out why direct resolving doesn't work
// val report = ivy.resolve(moduleDescriptor, resolveOptions)
//creates an ivy configuration file
val ivyFile = createTempFile("ivy", ".xml").apply { deleteOnExit() }
XmlModuleDescriptorWriter.write(moduleDescriptor, ivyFile)
val report = ivy.resolve(ivyFile.toURI().toURL(), resolveOptions)
return report.allArtifactsReports.map { it.localFile }
}
@@ -118,7 +129,7 @@ class IvyResolver : GenericRepositoryWithBridge {
}
companion object {
const val DEFAULT_ARTIFACT_PATTERN = "[organisation]/[module]/[revision]/[artifact](-[revision]).[ext]"
const val DEFAULT_ARTIFACT_PATTERN = "[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]"
init {
Message.setDefaultLogger(DefaultMessageLogger(1))