Switch main-kts to the updated resolvers infrastructure
This commit is contained in:
@@ -123,15 +123,30 @@ inline fun <R1, R2> ResultWithDiagnostics<R1>.onSuccess(body: (R1) -> ResultWith
|
||||
* return failure with merged diagnostics after first failed transformation
|
||||
* and success with merged diagnostics and list of results if all transformations succeeded
|
||||
*/
|
||||
inline fun<T, R> Iterable<T>.mapSuccess(body: (T) -> ResultWithDiagnostics<R>): ResultWithDiagnostics<List<R>> {
|
||||
inline fun<T, R> Iterable<T>.mapSuccess(body: (T) -> ResultWithDiagnostics<R>): ResultWithDiagnostics<List<R>> =
|
||||
mapSuccessImpl(body) { results, r ->
|
||||
results.add(r)
|
||||
}
|
||||
|
||||
/**
|
||||
* maps transformation ([body]) over iterable merging diagnostics and flatten the results
|
||||
* return failure with merged diagnostics after first failed transformation
|
||||
* and success with merged diagnostics and list of results if all transformations succeeded
|
||||
*/
|
||||
inline fun<T, R> Iterable<T>.flatMapSuccess(body: (T) -> ResultWithDiagnostics<Collection<R>>): ResultWithDiagnostics<List<R>> =
|
||||
mapSuccessImpl(body) { results, r ->
|
||||
results.addAll(r)
|
||||
}
|
||||
|
||||
inline fun<T, R1, R2> Iterable<T>.mapSuccessImpl(body: (T) -> ResultWithDiagnostics<R1>, updateResults: (MutableList<R2>, R1) -> Unit): ResultWithDiagnostics<List<R2>> {
|
||||
val reports = ArrayList<ScriptDiagnostic>()
|
||||
val results = ArrayList<R>()
|
||||
val results = ArrayList<R2>()
|
||||
for (it in this) {
|
||||
val result = body(it)
|
||||
reports.addAll(result.reports)
|
||||
when (result) {
|
||||
is ResultWithDiagnostics.Success -> {
|
||||
results.add(result.value)
|
||||
updateResults(results, result.value)
|
||||
}
|
||||
else -> {
|
||||
return ResultWithDiagnostics.Failure(reports)
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ class FileSystemDependenciesResolver(vararg paths: File) : ExternalDependenciesR
|
||||
// TODO: add coordinates and wildcard matching
|
||||
val file = if (repo == null) File(artifactCoordinates) else File(repo, artifactCoordinates)
|
||||
when {
|
||||
!file.exists() -> messages.add("File '$file' does not exists")
|
||||
!file.exists() -> messages.add("File '$file' not found")
|
||||
!file.isFile && !file.isDirectory -> messages.add("Path '$file' is neither file nor directory")
|
||||
else -> return ResultWithDiagnostics.Success(listOf(file))
|
||||
}
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ class MainKtsTest {
|
||||
@Test
|
||||
fun testResolveError() {
|
||||
val res = evalFile(File("$TEST_DATA_ROOT/hello-resolve-error.main.kts"))
|
||||
assertFailed("Unrecognized set of arguments to ivy resolver: abracadabra", res)
|
||||
assertFailed("File 'abracadabra' not found", res)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,6 +16,7 @@ dependencies {
|
||||
compileOnly("org.apache.ivy:ivy:2.5.0")
|
||||
compileOnly(project(":compiler:cli-common"))
|
||||
compileOnly(project(":kotlin-scripting-jvm-host"))
|
||||
compileOnly(project(":kotlin-scripting-dependencies"))
|
||||
compileOnly(project(":kotlin-script-util"))
|
||||
testCompile(project(":kotlin-scripting-jvm-host"))
|
||||
testCompile(project(":kotlin-script-util"))
|
||||
@@ -26,6 +27,7 @@ dependencies {
|
||||
embedded(project(":kotlin-scripting-common")) { isTransitive = false }
|
||||
embedded(project(":kotlin-scripting-jvm")) { isTransitive = false }
|
||||
embedded(project(":kotlin-scripting-jvm-host")) { isTransitive = false }
|
||||
embedded(project(":kotlin-scripting-dependencies")) { isTransitive = false }
|
||||
embedded(project(":kotlin-script-util")) { isTransitive = false }
|
||||
embedded("org.apache.ivy:ivy:2.5.0")
|
||||
embedded(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false }
|
||||
|
||||
@@ -19,34 +19,40 @@ import org.apache.ivy.plugins.resolver.IBiblioResolver
|
||||
import org.apache.ivy.plugins.resolver.URLResolver
|
||||
import org.apache.ivy.util.DefaultMessageLogger
|
||||
import org.apache.ivy.util.Message
|
||||
import org.jetbrains.kotlin.script.util.KotlinAnnotatedScriptDependenciesResolver
|
||||
import org.jetbrains.kotlin.script.util.resolvers.DirectResolver
|
||||
import org.jetbrains.kotlin.script.util.resolvers.experimental.GenericArtifactCoordinates
|
||||
import org.jetbrains.kotlin.script.util.resolvers.experimental.GenericRepositoryCoordinates
|
||||
import org.jetbrains.kotlin.script.util.resolvers.experimental.GenericRepositoryWithBridge
|
||||
import org.jetbrains.kotlin.script.util.resolvers.experimental.MavenArtifactCoordinates
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.dependencies.ExternalDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.RepositoryCoordinates
|
||||
import kotlin.script.experimental.dependencies.impl.toRepositoryUrlOrNull
|
||||
|
||||
class IvyResolver : GenericRepositoryWithBridge {
|
||||
class IvyResolver : ExternalDependenciesResolver {
|
||||
|
||||
private fun String?.isValidParam() = this?.isNotBlank() ?: false
|
||||
|
||||
override fun tryResolve(artifactCoordinates: GenericArtifactCoordinates): Iterable<File>? = with (artifactCoordinates) {
|
||||
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(':')
|
||||
override fun acceptsArtifact(artifactCoordinates: String): Boolean = with(artifactCoordinates) {
|
||||
isValidParam() && count { it == ':' }.let { it == 2 || it == 3 }
|
||||
}
|
||||
|
||||
override fun acceptsRepository(repositoryCoordinates: RepositoryCoordinates): Boolean =
|
||||
repositoryCoordinates.toRepositoryUrlOrNull() != null
|
||||
|
||||
override suspend fun resolve(artifactCoordinates: String): ResultWithDiagnostics<List<File>> {
|
||||
|
||||
val artifactType = artifactCoordinates.substringAfterLast('@', "").trim()
|
||||
val stringCoordinates = if (artifactType.isNotEmpty()) artifactCoordinates.removeSuffix("@$artifactType") else artifactCoordinates
|
||||
return if (acceptsArtifact(stringCoordinates)) {
|
||||
val artifactId = stringCoordinates.split(':')
|
||||
try {
|
||||
resolveArtifact(
|
||||
artifactId[0], artifactId[1], artifactId[2],
|
||||
if (artifactId.size > 3) artifactId[3] else null,
|
||||
if (artifactType.isNotEmpty()) artifactType else null
|
||||
)
|
||||
} else {
|
||||
error("Unrecognized set of arguments to ivy resolver: $stringCoordinates")
|
||||
} catch (e: Exception) {
|
||||
makeFailureResult(e.asDiagnostics())
|
||||
}
|
||||
} else {
|
||||
makeFailureResult("Unrecognized set of arguments to ivy resolver: $stringCoordinates")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +60,7 @@ class IvyResolver : GenericRepositoryWithBridge {
|
||||
|
||||
private fun resolveArtifact(
|
||||
groupId: String, artifactName: String, revision: String, conf: String? = null, type: String? = null
|
||||
): List<File> {
|
||||
): ResultWithDiagnostics<List<File>> {
|
||||
|
||||
if (ivyResolvers.isEmpty() || ivyResolvers.none { it.name == "central" }) {
|
||||
ivyResolvers.add(
|
||||
@@ -111,22 +117,23 @@ class IvyResolver : GenericRepositoryWithBridge {
|
||||
XmlModuleDescriptorWriter.write(moduleDescriptor, ivyFile)
|
||||
val report = ivy.resolve(ivyFile.toURI().toURL(), resolveOptions)
|
||||
|
||||
return report.allArtifactsReports.map { it.localFile }
|
||||
val diagnostics = report.allProblemMessages.map { it.asErrorDiagnostics() }
|
||||
|
||||
return if (report.hasError()) makeFailureResult(diagnostics)
|
||||
else report.allArtifactsReports.map { it.localFile }.asSuccess(diagnostics)
|
||||
}
|
||||
|
||||
override fun tryAddRepository(repositoryCoordinates: GenericRepositoryCoordinates): Boolean {
|
||||
val url = repositoryCoordinates.url
|
||||
override fun addRepository(repositoryCoordinates: RepositoryCoordinates) {
|
||||
val url = repositoryCoordinates.toRepositoryUrlOrNull()
|
||||
if (url != null) {
|
||||
ivyResolvers.add(
|
||||
IBiblioResolver().apply {
|
||||
isM2compatible = true
|
||||
name = repositoryCoordinates.name.takeIf { it.isValidParam() } ?: url.host
|
||||
name = url.host
|
||||
root = url.toExternalForm()
|
||||
}
|
||||
)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -135,6 +142,3 @@ class IvyResolver : GenericRepositoryWithBridge {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FilesAndIvyResolver :
|
||||
KotlinAnnotatedScriptDependenciesResolver(emptyList(), arrayListOf(DirectResolver(), IvyResolver()).asIterable())
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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 org.jetbrains.kotlin.mainKts.impl
|
||||
|
||||
import org.jetbrains.kotlin.script.util.DependsOn
|
||||
import org.jetbrains.kotlin.script.util.Repository
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||
import kotlin.script.experimental.api.flatMapSuccess
|
||||
import kotlin.script.experimental.api.makeFailureResult
|
||||
import kotlin.script.experimental.dependencies.ExternalDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.tryAddRepository
|
||||
|
||||
suspend fun resolveFromAnnotations(resolver: ExternalDependenciesResolver, annotations: Iterable<Annotation>): ResultWithDiagnostics<List<File>> {
|
||||
annotations.forEach { annotation ->
|
||||
when (annotation) {
|
||||
is Repository -> {
|
||||
val repositoryCoordinates = with(annotation) { value.takeIf { it.isNotBlank() } ?: url }
|
||||
if (!resolver.tryAddRepository(repositoryCoordinates))
|
||||
return makeFailureResult("Unrecognized repository coordinates: $repositoryCoordinates")
|
||||
}
|
||||
is DependsOn -> {}
|
||||
else -> return makeFailureResult("Unknown annotation ${annotation.javaClass}")
|
||||
}
|
||||
}
|
||||
return annotations.filterIsInstance(DependsOn::class.java).flatMapSuccess { dep ->
|
||||
val artifactCoordinates =
|
||||
if (dep.value.isNotBlank()) dep.value
|
||||
else listOf(dep.groupId, dep.artifactId, dep.version).filter { it?.isNotBlank() ?: false }.joinToString(":")
|
||||
resolver.resolve(artifactCoordinates)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.mainKts
|
||||
|
||||
import org.jetbrains.kotlin.mainKts.impl.FilesAndIvyResolver
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.kotlin.mainKts.impl.IvyResolver
|
||||
import org.jetbrains.kotlin.mainKts.impl.resolveFromAnnotations
|
||||
import org.jetbrains.kotlin.script.util.CompilerOptions
|
||||
import org.jetbrains.kotlin.script.util.DependsOn
|
||||
import org.jetbrains.kotlin.script.util.Import
|
||||
@@ -15,6 +17,8 @@ import kotlin.script.dependencies.ScriptContents
|
||||
import kotlin.script.dependencies.ScriptDependenciesResolver
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.dependencies.CompoundDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.FileSystemDependenciesResolver
|
||||
import kotlin.script.experimental.host.FileBasedScriptSource
|
||||
import kotlin.script.experimental.host.FileScriptSource
|
||||
import kotlin.script.experimental.jvm.compat.mapLegacyDiagnosticSeverity
|
||||
@@ -60,7 +64,7 @@ object MainKtsEvaluationConfiguration : ScriptEvaluationConfiguration(
|
||||
)
|
||||
|
||||
class MainKtsConfigurator : RefineScriptCompilationConfigurationHandler {
|
||||
private val resolver = FilesAndIvyResolver()
|
||||
private val resolver = CompoundDependenciesResolver(FileSystemDependenciesResolver(), IvyResolver())
|
||||
|
||||
override operator fun invoke(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics<ScriptCompilationConfiguration> =
|
||||
processAnnotations(context)
|
||||
@@ -92,23 +96,21 @@ class MainKtsConfigurator : RefineScriptCompilationConfigurationHandler {
|
||||
(it as? CompilerOptions)?.options?.toList() ?: emptyList()
|
||||
}
|
||||
|
||||
val resolvedClassPath = try {
|
||||
val scriptContents = object : ScriptContents {
|
||||
override val annotations: Iterable<Annotation> = annotations.filter { it is DependsOn || it is Repository }
|
||||
override val file: File? = null
|
||||
override val text: CharSequence? = null
|
||||
val resolveResult = try {
|
||||
runBlocking {
|
||||
resolveFromAnnotations(resolver, annotations.filter { it is DependsOn || it is Repository })
|
||||
}
|
||||
resolver.resolve(scriptContents, emptyMap(), ::report, null).get()?.classpath?.toList()
|
||||
// TODO: add diagnostics
|
||||
} catch (e: Throwable) {
|
||||
return ResultWithDiagnostics.Failure(*diagnostics.toTypedArray(), e.asDiagnostics(path = context.script.locationId))
|
||||
ResultWithDiagnostics.Failure(*diagnostics.toTypedArray(), e.asDiagnostics(path = context.script.locationId))
|
||||
}
|
||||
|
||||
return ScriptCompilationConfiguration(context.compilationConfiguration) {
|
||||
if (resolvedClassPath != null) updateClasspath(resolvedClassPath)
|
||||
if (importedSources.isNotEmpty()) importScripts.append(importedSources)
|
||||
if (compileOptions.isNotEmpty()) compilerOptions.append(compileOptions)
|
||||
}.asSuccess(diagnostics)
|
||||
return resolveResult.onSuccess { resolvedClassPath ->
|
||||
ScriptCompilationConfiguration(context.compilationConfiguration) {
|
||||
if (resolvedClassPath != null) updateClasspath(resolvedClassPath)
|
||||
if (importedSources.isNotEmpty()) importScripts.append(importedSources)
|
||||
if (compileOptions.isNotEmpty()) compilerOptions.append(compileOptions)
|
||||
}.asSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user