Add new script dependency resolvers

Changes in new API for dependency resolvers (GenericDependenciesResolver) comparing to an old one (GenericResolver:
- Add ability to fast check whether artifact or repository is suitable for current resolver to distinguish between unsuitable resolvers and resolution failures
- Return all artifact resolution failures in ResultWithDiagnostics
- Use single string for artifact coordinates
- Add compound resolver that combines several resolvers
- Merge Direct and FlatLib resolver into single FileSystemDependencyResolver
- Mark resolve() method as suspend to indicate long operation
- Add credentials support for maven resolver (https://youtrack.jetbrains.com/issue/KT-27701)
This commit is contained in:
Anatoly Nikitin
2019-09-27 14:01:02 +03:00
committed by Ilya Chernikov
parent 81e2e119e2
commit c7e9a6c5d9
12 changed files with 535 additions and 0 deletions
@@ -0,0 +1,49 @@
/*
* 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 kotlin.script.experimental.dependencies
import java.io.File
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptDiagnostic
import kotlin.script.experimental.dependencies.impl.makeResolveFailureResult
class CompoundDependenciesResolver(private val resolvers: List<ExternalDependenciesResolver>) : ExternalDependenciesResolver {
constructor(vararg resolvers: ExternalDependenciesResolver) : this(resolvers.toList())
override fun acceptsArtifact(artifactCoordinates: String): Boolean {
return resolvers.any { it.acceptsArtifact(artifactCoordinates) }
}
override fun acceptsRepository(repositoryCoordinates: RepositoryCoordinates): Boolean {
return resolvers.any { it.acceptsRepository(repositoryCoordinates) }
}
override fun addRepository(repositoryCoordinates: RepositoryCoordinates) {
if (resolvers.count { it.tryAddRepository(repositoryCoordinates) } == 0)
throw Exception("Failed to detect repository type: $repositoryCoordinates")
}
override suspend fun resolve(artifactCoordinates: String): ResultWithDiagnostics<List<File>> {
val reports = mutableListOf<ScriptDiagnostic>()
for (resolver in resolvers) {
if (resolver.acceptsArtifact(artifactCoordinates)) {
when (val resolveResult = resolver.resolve(artifactCoordinates)) {
is ResultWithDiagnostics.Failure -> reports.addAll(resolveResult.reports)
else -> return resolveResult
}
}
}
return if (reports.count() == 0) {
makeResolveFailureResult("No suitable dependency resolver found for artifact '$artifactCoordinates'")
} else {
ResultWithDiagnostics.Failure(reports)
}
}
}
@@ -0,0 +1,38 @@
/*
* 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 kotlin.script.experimental.dependencies
import java.io.File
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.valueOrNull
open class RepositoryCoordinates(val string: String)
interface ExternalDependenciesResolver {
fun acceptsRepository(repositoryCoordinates: RepositoryCoordinates): Boolean
fun acceptsArtifact(artifactCoordinates: String): Boolean
suspend fun resolve(artifactCoordinates: String): ResultWithDiagnostics<List<File>>
fun addRepository(repositoryCoordinates: RepositoryCoordinates)
}
fun ExternalDependenciesResolver.acceptsRepository(repositoryCoordinates: String): Boolean =
acceptsRepository(RepositoryCoordinates(repositoryCoordinates))
fun ExternalDependenciesResolver.addRepository(repositoryCoordinates: String) = addRepository(RepositoryCoordinates(repositoryCoordinates))
suspend fun ExternalDependenciesResolver.tryResolve(artifactCoordinates: String): List<File>? =
if (acceptsArtifact(artifactCoordinates)) resolve(artifactCoordinates).valueOrNull() else null
fun ExternalDependenciesResolver.tryAddRepository(repositoryCoordinates: String) =
tryAddRepository(RepositoryCoordinates(repositoryCoordinates))
fun ExternalDependenciesResolver.tryAddRepository(repositoryCoordinates: RepositoryCoordinates) =
if (acceptsRepository(repositoryCoordinates)) {
addRepository(repositoryCoordinates)
true
} else false
@@ -0,0 +1,57 @@
/*
* 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 kotlin.script.experimental.dependencies
import java.io.File
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.dependencies.impl.makeResolveFailureResult
import kotlin.script.experimental.dependencies.impl.toRepositoryUrlOrNull
class FileSystemDependenciesResolver(vararg paths: File) : ExternalDependenciesResolver {
private fun String.toRepositoryFileOrNull(): File? =
File(this).takeIf { it.exists() && it.isDirectory }
private fun RepositoryCoordinates.toFilePath() =
(this.toRepositoryUrlOrNull()?.takeIf { it.protocol == "file" }?.path ?: string).toRepositoryFileOrNull()
override fun addRepository(repositoryCoordinates: RepositoryCoordinates) {
val repoDir = repositoryCoordinates.toFilePath()
?: throw IllegalArgumentException("Invalid repository location: '${repositoryCoordinates}'")
localRepos.add(repoDir)
}
override suspend fun resolve(artifactCoordinates: String): ResultWithDiagnostics<List<File>> {
if (!acceptsArtifact(artifactCoordinates)) throw IllegalArgumentException("Path is invalid")
val messages = mutableListOf<String>()
for (repo in localRepos) {
// 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.isFile && !file.isDirectory -> messages.add("Path '$file' is neither file nor directory")
else -> return ResultWithDiagnostics.Success(listOf(file))
}
}
return makeResolveFailureResult(messages)
}
override fun acceptsArtifact(artifactCoordinates: String) =
!artifactCoordinates.isBlank() // TODO: make check stronger, e.g. using NIO's Path
override fun acceptsRepository(repositoryCoordinates: RepositoryCoordinates): Boolean = repositoryCoordinates.toFilePath() != null
private val localRepos = arrayListOf<File?>(null)
init {
for (path in paths) {
require(path.exists() && path.isDirectory) { "Invalid flat lib directory repository path '$path'" }
}
localRepos.addAll(paths)
}
}
@@ -0,0 +1,24 @@
/*
* 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 kotlin.script.experimental.dependencies.impl
import java.net.MalformedURLException
import java.net.URL
import kotlin.script.experimental.dependencies.RepositoryCoordinates
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptDiagnostic
fun makeResolveFailureResult(message: String) = makeResolveFailureResult(listOf(message))
fun makeResolveFailureResult(messages: Iterable<String>) =
ResultWithDiagnostics.Failure(messages.map { ScriptDiagnostic(it, ScriptDiagnostic.Severity.WARNING) })
fun RepositoryCoordinates.toRepositoryUrlOrNull(): URL? =
try {
URL(string)
} catch (_: MalformedURLException) {
null
}