All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlinx.jupyter.dependencies.JupyterScriptDependenciesResolverImpl.kt Maven / Gradle / Ivy

There is a newer version: 0.12.0-356
Show newest version
package org.jetbrains.kotlinx.jupyter.dependencies

import jupyter.kotlin.DependsOn
import jupyter.kotlin.Repository
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.mainKts.impl.IvyResolver
import org.jetbrains.kotlinx.jupyter.config.getLogger
import java.io.File
import kotlin.script.dependencies.ScriptContents
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptDiagnostic
import kotlin.script.experimental.api.asSuccess
import kotlin.script.experimental.api.makeFailureResult
import kotlin.script.experimental.api.valueOrNull
import kotlin.script.experimental.dependencies.CompoundDependenciesResolver
import kotlin.script.experimental.dependencies.ExternalDependenciesResolver
import kotlin.script.experimental.dependencies.FileSystemDependenciesResolver
import kotlin.script.experimental.dependencies.RepositoryCoordinates
import kotlin.script.experimental.dependencies.impl.DependenciesResolverOptionsName
import kotlin.script.experimental.dependencies.impl.makeExternalDependenciesResolverOptions

open class JupyterScriptDependenciesResolverImpl(resolverConfig: ResolverConfig?) : JupyterScriptDependenciesResolver {

    private val log = getLogger("resolver")

    private val resolver: ExternalDependenciesResolver
    private val resolverOptions = makeExternalDependenciesResolverOptions(
        mapOf(
            DependenciesResolverOptionsName.SCOPE.key to "compile,runtime"
        )
    )

    private val repositories = arrayListOf()
    private val addedClasspath = arrayListOf()

    init {
        resolver = CompoundDependenciesResolver(
            FileSystemDependenciesResolver(),
            RemoteResolverWrapper(IvyResolver())
        )
        resolverConfig?.repositories?.forEach { addRepository(it) }
    }

    private fun addRepository(repository: RepositoryCoordinates): Boolean {
        val repoIndex = repositories.indexOfFirst { it.string == repository.string }
        if (repoIndex != -1) repositories.removeAt(repoIndex)
        repositories.add(repository)

        return resolver.addRepository(repository).valueOrNull() == true
    }

    fun popAddedClasspath(): List {
        val result = addedClasspath.toList()
        addedClasspath.clear()
        return result
    }

    override fun resolveFromAnnotations(script: ScriptContents): ResultWithDiagnostics> {
        val scriptDiagnostics = mutableListOf()
        val classpath = mutableListOf()
        var existingRepositories: List? = null

        script.annotations.forEach { annotation ->
            when (annotation) {
                is Repository -> {
                    log.info("Adding repository: ${annotation.value}")
                    if (existingRepositories == null) {
                        existingRepositories = ArrayList(repositories)
                    }

                    if (!addRepository(RepositoryCoordinates(annotation.value))) {
                        throw IllegalArgumentException("Illegal argument for Repository annotation: $annotation")
                    }

                    existingRepositories?.forEach { addRepository(it) }
                }
                is DependsOn -> {
                    log.info("Resolving ${annotation.value}")
                    try {
                        when (val result = runBlocking { resolver.resolve(annotation.value, resolverOptions) }) {
                            is ResultWithDiagnostics.Failure -> {
                                val diagnostics = ScriptDiagnostic(ScriptDiagnostic.unspecifiedError, "Failed to resolve ${annotation.value}:\n" + result.reports.joinToString("\n") { it.message })
                                log.warn(diagnostics.message, diagnostics.exception)
                                scriptDiagnostics.add(diagnostics)
                            }
                            is ResultWithDiagnostics.Success -> {
                                log.info("Resolved: " + result.value.joinToString())
                                addedClasspath.addAll(result.value)
                                classpath.addAll(result.value)
                            }
                        }
                    } catch (e: Exception) {
                        val diagnostic = ScriptDiagnostic(ScriptDiagnostic.unspecifiedError, "Unhandled exception during resolve", exception = e)
                        log.error(diagnostic.message, e)
                        scriptDiagnostics.add(diagnostic)
                    }
                    // Hack: after first resolution add "standard" Central repo to the end of the list, giving it the lowest priority
                    addRepository(CENTRAL_REPO_COORDINATES)
                }
                else -> throw Exception("Unknown annotation ${annotation.javaClass}")
            }
        }

        return if (scriptDiagnostics.isEmpty()) classpath.asSuccess()
        else makeFailureResult(scriptDiagnostics)
    }

    companion object {
        val CENTRAL_REPO_COORDINATES = RepositoryCoordinates("https://repo1.maven.org/maven2/")
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy