Add API to get locations of collected script annotations

#KT-38404 fixed

also:
- Add wrapper class for the location combined with the location id
- Add source code location parameters to external dependency resolvers
- Add tests for locations in annotations
- Add tests for order of annotation resolution for dependencies resolvers
This commit is contained in:
Mathias Quintero
2020-05-20 13:42:08 +02:00
committed by Ilya Chernikov
parent 1539128c3f
commit 83087291df
19 changed files with 550 additions and 85 deletions
@@ -36,7 +36,10 @@ class IvyResolver : ExternalDependenciesResolver {
override fun acceptsRepository(repositoryCoordinates: RepositoryCoordinates): Boolean =
repositoryCoordinates.toRepositoryUrlOrNull() != null
override suspend fun resolve(artifactCoordinates: String): ResultWithDiagnostics<List<File>> {
override suspend fun resolve(
artifactCoordinates: String,
sourceCodeLocation: SourceCode.LocationWithId?
): ResultWithDiagnostics<List<File>> {
val artifactType = artifactCoordinates.substringAfterLast('@', "").trim()
val stringCoordinates = if (artifactType.isNotEmpty()) artifactCoordinates.removeSuffix("@$artifactType") else artifactCoordinates
@@ -46,20 +49,26 @@ class IvyResolver : ExternalDependenciesResolver {
resolveArtifact(
artifactId[0], artifactId[1], artifactId[2],
if (artifactId.size > 3) artifactId[3] else null,
if (artifactType.isNotEmpty()) artifactType else null
if (artifactType.isNotEmpty()) artifactType else null,
sourceCodeLocation
)
} catch (e: Exception) {
makeFailureResult(e.asDiagnostics())
makeFailureResult(e.asDiagnostics(locationWithId = sourceCodeLocation))
}
} else {
makeFailureResult("Unrecognized set of arguments to ivy resolver: $stringCoordinates")
makeFailureResult("Unrecognized set of arguments to ivy resolver: $stringCoordinates", sourceCodeLocation)
}
}
private val ivyResolvers = arrayListOf<URLResolver>()
private fun resolveArtifact(
groupId: String, artifactName: String, revision: String, conf: String? = null, type: String? = null
groupId: String,
artifactName: String,
revision: String,
conf: String? = null,
type: String? = null,
sourceCodeLocation: SourceCode.LocationWithId? = null
): ResultWithDiagnostics<List<File>> {
if (ivyResolvers.isEmpty() || ivyResolvers.none { it.name == "central" }) {
@@ -118,23 +127,27 @@ class IvyResolver : ExternalDependenciesResolver {
XmlModuleDescriptorWriter.write(moduleDescriptor, ivyFile)
val report = ivy.resolve(ivyFile.toURI().toURL(), resolveOptions)
val diagnostics = report.allProblemMessages.map { it.asErrorDiagnostics() }
val diagnostics = report.allProblemMessages.map { it.asErrorDiagnostics(locationWithId = sourceCodeLocation) }
return if (report.hasError()) makeFailureResult(diagnostics)
else report.allArtifactsReports.map { it.localFile }.asSuccess(diagnostics)
}
override fun addRepository(repositoryCoordinates: RepositoryCoordinates) {
override fun addRepository(
repositoryCoordinates: RepositoryCoordinates,
sourceCodeLocation: SourceCode.LocationWithId?
): ResultWithDiagnostics<Boolean> {
val url = repositoryCoordinates.toRepositoryUrlOrNull()
if (url != null) {
ivyResolvers.add(
IBiblioResolver().apply {
isM2compatible = true
name = url.host
root = url.toExternalForm()
}
)
}
?: return false.asSuccess()
ivyResolvers.add(
IBiblioResolver().apply {
isM2compatible = true
name = url.host
root = url.toExternalForm()
}
)
return true.asSuccess()
}
companion object {
@@ -26,6 +26,7 @@ import kotlin.script.experimental.jvmhost.CompiledScriptJarsCache
import kotlin.script.experimental.jvmhost.jsr223.configureProvidedPropertiesFromJsr223Context
import kotlin.script.experimental.jvmhost.jsr223.importAllBindings
import kotlin.script.experimental.jvmhost.jsr223.jsr223
import kotlin.script.experimental.util.filterByAnnotationType
@Suppress("unused")
@KotlinScript(
@@ -120,22 +121,22 @@ class MainKtsConfigurator : RefineScriptCompilationConfigurationHandler {
)
}
val annotations = context.collectedData?.get(ScriptCollectedData.foundAnnotations)?.takeIf { it.isNotEmpty() }
val annotations = context.collectedData?.get(ScriptCollectedData.collectedAnnotations)?.takeIf { it.isNotEmpty() }
?: return context.compilationConfiguration.asSuccess()
val scriptBaseDir = (context.script as? FileBasedScriptSource)?.file?.parentFile
val importedSources = annotations.flatMap {
(it as? Import)?.paths?.map { sourceName ->
val importedSources = annotations.filterByAnnotationType<Import>().flatMap {
it.annotation.paths.map { sourceName ->
FileScriptSource(scriptBaseDir?.resolve(sourceName) ?: File(sourceName))
} ?: emptyList()
}
}
val compileOptions = annotations.flatMap {
(it as? CompilerOptions)?.options?.toList() ?: emptyList()
val compileOptions = annotations.filterByAnnotationType<CompilerOptions>().flatMap {
it.annotation.options.toList()
}
val resolveResult = try {
runBlocking {
resolver.resolveFromAnnotations( annotations.filter { it is DependsOn || it is Repository })
resolver.resolveFromScriptSourceAnnotations(annotations.filter { it.annotation is DependsOn || it.annotation is Repository })
}
} catch (e: Throwable) {
ResultWithDiagnostics.Failure(*diagnostics.toTypedArray(), e.asDiagnostics(path = context.script.locationId))