From dd3ac74bd28dd118b083679e19403d1d3222a094 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Mon, 18 Mar 2019 18:02:44 +0100 Subject: [PATCH] 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 --- .../kotlin/mainKts/test/mainKtsTest.kt | 19 +++++- .../testData/resolve-moneta.main.kts | 7 +++ .../org/jetbrains/kotlin/mainKts/impl/ivy.kt | 61 +++++++++++-------- 3 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 libraries/tools/kotlin-main-kts-test/testData/resolve-moneta.main.kts diff --git a/libraries/tools/kotlin-main-kts-test/test/org/jetbrains/kotlin/mainKts/test/mainKtsTest.kt b/libraries/tools/kotlin-main-kts-test/test/org/jetbrains/kotlin/mainKts/test/mainKtsTest.kt index 3edd4b7dbba..3738aa3a8a1 100644 --- a/libraries/tools/kotlin-main-kts-test/test/org/jetbrains/kotlin/mainKts/test/mainKtsTest.kt +++ b/libraries/tools/kotlin-main-kts-test/test/org/jetbrains/kotlin/mainKts/test/mainKtsTest.kt @@ -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 diff --git a/libraries/tools/kotlin-main-kts-test/testData/resolve-moneta.main.kts b/libraries/tools/kotlin-main-kts-test/testData/resolve-moneta.main.kts new file mode 100644 index 00000000000..2248a89c0ca --- /dev/null +++ b/libraries/tools/kotlin-main-kts-test/testData/resolve-moneta.main.kts @@ -0,0 +1,7 @@ + +@file:DependsOn("org.javamoney:moneta:1.3@pom") + +import org.javamoney.moneta.spi.MoneyUtils + +println("getBigDecimal(1L): " + MoneyUtils.getBigDecimal(1L)) + diff --git a/libraries/tools/kotlin-main-kts/src/org/jetbrains/kotlin/mainKts/impl/ivy.kt b/libraries/tools/kotlin-main-kts/src/org/jetbrains/kotlin/mainKts/impl/ivy.kt index 2df353a5a6a..7bdd37b5170 100644 --- a/libraries/tools/kotlin-main-kts/src/org/jetbrains/kotlin/mainKts/impl/ivy.kt +++ b/libraries/tools/kotlin-main-kts/src/org/jetbrains/kotlin/mainKts/impl/ivy.kt @@ -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? = 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() - private fun resolveArtifact(artifactId: List): List { + private fun resolveArtifact( + groupId: String, artifactName: String, revision: String, conf: String? = null, type: String? = null + ): List { 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))