Skip to content

Commit

Permalink
correctly fetch sbt plugins
Browse files Browse the repository at this point in the history
try resolving debug adapter plugin
  • Loading branch information
kasiaMarek committed Nov 24, 2023
1 parent 8778a34 commit 2c3950f
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 52 deletions.
5 changes: 3 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -487,8 +487,9 @@ lazy val metals = project
// For reading classpaths.
// for fetching ch.epfl.scala:bloop-frontend and other library dependencies
"io.get-coursier" % "interface" % V.coursierInterfaces,
// for comparing versions
"io.get-coursier" %% "versions" % "0.3.2",
// for comparing versions && fetching from sbt maven repository
"io.get-coursier" %% "coursier" % V.coursier,
"io.get-coursier" %% "coursier-sbt-maven-repository" % V.coursier,
// for logging
"com.outr" %% "scribe" % V.scribe,
"com.outr" %% "scribe-file" % V.scribe,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,23 @@ import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.semver.SemVer
import scala.meta.io.AbsolutePath

import coursierapi.Dependency
import coursierapi.Fetch
import coursierapi.error.CoursierError
import coursier.Fetch
import coursier.Repositories
import coursier.core.Classifier
import coursier.core.Dependency
import coursier.core.Module
import coursier.core.ModuleName
import coursier.core.Organization
import coursier.error.CoursierError
import coursier.maven.SbtMavenRepository

object JarSourcesProvider {

private val sbtRegex = "sbt-(.*)".r

def fetchSources(jars: Seq[String])(implicit ec: ExecutionContext): Future[Seq[String]] = {
def fetchSources(
jars: Seq[String]
)(implicit ec: ExecutionContext): Future[Seq[String]] = {
def sourcesPath(jar: String) = s"${jar.stripSuffix(".jar")}-sources.jar"

val (haveSources, toDownload) = jars.partition { jar =>
Expand All @@ -43,23 +51,27 @@ object JarSourcesProvider {
}.distinct

val fetchedSources =
Future.sequence {
dependencies.map{ dep =>
fetchDependencySources(dep)
.recover {
case error : CoursierError =>
scribe.warn(s"Could not fetch dependency sources for $dep, error: $error")
Nil
Future
.sequence {
dependencies.map { dep =>
fetchDependencySources(dep)
.recover { case error: CoursierError =>
scribe.warn(
s"Could not fetch dependency sources for $dep, error: $error"
)
Nil
}
}
}
}.recover {
case _: TimeoutException =>
scribe.warn(s"Timeout when fetching dependency sources.")
Nil
case NonFatal(e) =>
scribe.warn(s"Could not fetch dependency sources, error: $e.")
Nil
}.map(_.flatten.map(_.toUri().toString()))
.recover {
case _: TimeoutException =>
scribe.warn(s"Timeout when fetching dependency sources.")
Nil
case NonFatal(e) =>
scribe.warn(s"Could not fetch dependency sources, error: $e.")
Nil
}
.map(_.flatten.map(_.toUri().toString()))

val existingSources = haveSources.map(sourcesPath)
fetchedSources.map(_ ++ existingSources)
Expand All @@ -72,7 +84,12 @@ object JarSourcesProvider {
case sbtRegex(versionStr) =>
Try(SemVer.Version.fromString(versionStr)) match {
case Success(version) if version.toString == versionStr =>
Some(Dependency.of("org.scala-sbt", "sbt", versionStr))
val module = Module(
Organization("org.scala-sbt"),
ModuleName("sbt"),
Map.empty,
)
Some(Dependency(module, versionStr))
case _ => None
}
case _ => None
Expand All @@ -84,37 +101,39 @@ object JarSourcesProvider {
val groupId = (xml \ "groupId").text
val version = (xml \ "version").text
val artifactId = (xml \ "artifactId").text
Option
.when(groupId.nonEmpty && version.nonEmpty && artifactId.nonEmpty) {
Dependency.of(groupId, artifactId, version)
}
.filterNot(dep => isSbtDap(dep) || isMetalsPlugin(dep))
}

private def isSbtDap(dependency: Dependency) = {
dependency.getModule().getOrganization() == "ch.epfl.scala" &&
dependency.getModule().getName() == "sbt-debug-adapter" &&
dependency.getVersion() == BuildInfo.debugAdapterVersion
val properties = (xml \ "properties")

def getProperty(name: String) =
properties.map(node => (node \ name).text).find(_.nonEmpty).map(name -> _)

Option.when(groupId.nonEmpty && version.nonEmpty && artifactId.nonEmpty) {
val scalaVersion = getProperty("scalaVersion").toMap
val sbtVersion = getProperty("sbtVersion").toMap
val attributes = (scalaVersion ++ sbtVersion)
Dependency(
Module(Organization(groupId), ModuleName(artifactId), attributes),
version,
)
}
}

private def isMetalsPlugin(dependency: Dependency) = {
dependency.getModule().getOrganization() == "org.scalameta" &&
dependency.getModule().getName() == "sbt-metals" &&
dependency.getVersion() == BuildInfo.metalsVersion
}
private val sbtMaven = SbtMavenRepository(Repositories.central)
private val metalsPluginSnapshots = SbtMavenRepository(
Repositories.sonatype("public")
)

private def fetchDependencySources(
def fetchDependencySources(
dependency: Dependency
)(implicit ec: ExecutionContext): Future[List[Path]] = Future {
Fetch
.create()
.withDependencies(dependency)
.addClassifiers("sources")
.fetchResult()
.getFiles()
.asScala
.map(_.toPath())
.toList
}.withTimeout(5, TimeUnit.MINUTES)
)(implicit ec: ExecutionContext): Future[List[Path]] = {
val repositories =
List(Repositories.central, sbtMaven, metalsPluginSnapshots)
Fetch()
.withRepositories(repositories)
.withDependencies(Seq(dependency))
.addClassifiers(Classifier.sources)
.future()
.map(_.map(_.toPath()).toList)
.withTimeout(5, TimeUnit.MINUTES)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import scala.meta.internal.metals.clients.language.MetalsLanguageClient
import scala.meta.internal.process.SystemProcess
import scala.meta.io.AbsolutePath

import coursier.version.Version
import coursier.core.Version

// todo https://github.com/scalameta/metals/issues/4788
// clean () =>, use plain values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import scala.meta.internal.metals.codeactions.ImportMissingSymbol
import scala.meta.internal.mtags.BuildInfo.scalaCompilerVersion
import scala.meta.internal.mtags.CoursierComplete

import coursier.version.Version
import coursier.core.Version

class ScalaCliActionsSuite
extends BaseScalaCLIActionSuite("actionableDiagnostic") {
Expand Down
35 changes: 35 additions & 0 deletions tests/unit/src/test/scala/tests/JarSourcesProviderSuite.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package tests

import scala.concurrent.ExecutionContext
import scala.concurrent.Future

import scala.meta.internal.metals.JarSourcesProvider
import scala.meta.internal.metals.MetalsEnrichments._

import coursier.core.Dependency
import coursier.core.Module
import coursier.core.ModuleName
import coursier.core.Organization

class JarSourcesProviderSuite extends BaseSuite {

private implicit val ctx: ExecutionContext = this.munitExecutionContext
Expand All @@ -24,4 +30,33 @@ class JarSourcesProviderSuite extends BaseSuite {
}
}

private val sbtDap = {
val attributes = Map("scalaVersion" -> "2.12", "sbtVersion" -> "1.0")
val module = Module(
Organization("ch.epfl.scala"),
ModuleName("sbt-debug-adapter"),
attributes,
)
Dependency(module, "3.1.4")
}

private val metalsSbt = {
val attributes = Map("scalaVersion" -> "2.12", "sbtVersion" -> "1.0")
val module = Module(
Organization("org.scalameta"),
ModuleName("sbt-metals"),
attributes,
)
Dependency(module, "1.1.0")
}

test("download-sbt-plugins") {
for {
sources <- Future.sequence(
List(sbtDap, metalsSbt).map(JarSourcesProvider.fetchDependencySources)
)
_ = sources.foreach(sources => assert(sources.nonEmpty))
} yield ()
}

}

0 comments on commit 2c3950f

Please sign in to comment.