Skip to content

Commit 89dd97b

Browse files
Merge commit '036583694'
2 parents eecb3b7 + 0365836 commit 89dd97b

File tree

4 files changed

+84
-48
lines changed

4 files changed

+84
-48
lines changed

frontend/src/main/scala/bloop/bsp/BloopBspServices.scala

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,52 +1064,49 @@ final class BloopBspServices(
10641064
projects: Seq[ProjectMapping],
10651065
state: State
10661066
): BspResult[bsp.SourcesResult] = {
1067-
val sourcesItems = projects.iterator.map {
1068-
case (target, project) =>
1069-
def sourceItem(s: AbsolutePath, isGenerated: Boolean): bsp.SourceItem = {
1070-
import bsp.SourceItemKind._
1071-
val uri = s.underlying.toUri()
1072-
val (bspUri, kind) = if (s.exists) {
1073-
(uri, if (s.isFile) File else Directory)
1074-
} else {
1075-
val fileMatcher = FileSystems.getDefault.getPathMatcher("glob:*.{scala, java}")
1076-
if (fileMatcher.matches(s.underlying.getFileName)) (uri, File)
1077-
// If path doesn't exist and its name doesn't look like a file, assume it's a dir
1078-
else (new URI(uri.toString + "/"), Directory)
1079-
}
1080-
bsp.SourceItem(bsp.Uri(bspUri), kind, isGenerated)
1081-
}
1067+
def sourceItem(s: AbsolutePath, isGenerated: Boolean): bsp.SourceItem = {
1068+
import bsp.SourceItemKind._
1069+
val uri = s.underlying.toUri()
1070+
val (bspUri, kind) = if (s.exists) {
1071+
(uri, if (s.isFile) File else Directory)
1072+
} else {
1073+
val fileMatcher = FileSystems.getDefault.getPathMatcher("glob:*.{scala, java}")
1074+
if (fileMatcher.matches(s.underlying.getFileName)) (uri, File)
1075+
// If path doesn't exist and its name doesn't look like a file, assume it's a dir
1076+
else (new URI(uri.toString + "/"), Directory)
1077+
}
1078+
bsp.SourceItem(bsp.Uri(bspUri), kind, isGenerated)
1079+
}
10821080

1083-
val unmanagedSources = project.allUnmanagedSourceFilesAndDirectories.map { sources =>
1084-
sources.map(sourceItem(_, isGenerated = false))
1085-
}
1081+
val dag = Aggregate(projects.map(p => state.build.getDagFor(p._2)).toList)
10861082

1087-
val parentGenerators = Dag.dfs(state.build.getDagFor(project))
1088-
val managedSources = Task
1089-
.sequence {
1090-
parentGenerators.reverse.map { project =>
1091-
val generators = project.sourceGenerators
1092-
val tasks = generators.map(
1093-
state.sourceGeneratorCache.update(_, state.logger, state.commonOptions)
1094-
)
1095-
Task.gatherUnordered(tasks)
1096-
}
1097-
}
1098-
.map {
1099-
// Take only the result of the last set of generators, since these are the generated
1100-
// sources of the project we're interested in.
1101-
_.lastOption.map(_.flatten.map(sourceItem(_, isGenerated = true))).getOrElse(Nil)
1102-
}
1103-
.executeOn(ioScheduler)
1083+
// Collect the projects' sources following the projects topological sorting, so that
1084+
// source generators that depend on other source generators' outputs can run correctly.
1085+
val collectSourcesTasks = Dag.topologicalSort(dag).map { project =>
1086+
val unmanagedSources = project.allUnmanagedSourceFilesAndDirectories.map { sources =>
1087+
sources.map(sourceItem(_, isGenerated = false))
1088+
}
1089+
1090+
val managedSources = {
1091+
val tasks = project.sourceGenerators
1092+
.map(state.sourceGeneratorCache.update(_, state.logger, state.commonOptions))
1093+
Task.gatherUnordered(tasks).map(_.flatten.map(sourceItem(_, isGenerated = true)))
1094+
}
11041095

1105-
val roots = project.sourceRoots.map(_.map(p => bsp.Uri(p.toBspUri)))
1106-
for {
1107-
unmanaged <- unmanagedSources
1108-
managed <- managedSources
1109-
} yield bsp.SourcesItem(target, unmanaged ++ managed, roots)
1110-
}.toList
1096+
for {
1097+
unmanaged <- unmanagedSources
1098+
managed <- managedSources
1099+
} yield (project, unmanaged ++ managed)
1100+
}
1101+
1102+
val projectToTarget = projects.map { case (target, project) => project -> target }.toMap
1103+
Task.sequence(collectSourcesTasks).map { results =>
1104+
val items = results.flatMap {
1105+
case (project, items) =>
1106+
val roots = project.sourceRoots.map(_.map(p => bsp.Uri(p.toBspUri)))
1107+
projectToTarget.get(project).map(bsp.SourcesItem(_, items, roots))
1108+
}
11111109

1112-
Task.sequence(sourcesItems).map { items =>
11131110
(state, Right(bsp.SourcesResult(items)))
11141111
}
11151112
}

frontend/src/main/scala/bloop/engine/BuildLoader.scala

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,9 @@ object BuildLoader {
205205
): Option[AbsolutePath] = {
206206
val (scalaVersion, scalaSemanticdbSettings) = scalaSemanticdbVersionAndSettings
207207
// Recognize 2.12.8-abdcddd as supported if 2.12.8 exists in supported versions
208-
val isUnsupportedVersion =
209-
!scalaSemanticdbSettings.supportedScalaVersions.exists(scalaVersion.startsWith(_))
210-
if (isUnsupportedVersion) {
211-
if (!scalaVersion.startsWith("3."))
212-
logger.debug(Feedback.skippedUnsupportedScalaMetals(scalaVersion))(DebugFilter.All)
208+
val isSupportedVersion =
209+
scalaSemanticdbSettings.supportedScalaVersions.exists(scalaVersion.startsWith(_))
210+
if (scalaVersion.startsWith("3.")) {
213211
None
214212
} else {
215213
SemanticDBCache.fetchScalaPlugin(
@@ -220,9 +218,13 @@ object BuildLoader {
220218
case Right(path) =>
221219
logger.debug(Feedback.configuredMetalsScalaProjects(projects))(DebugFilter.All)
222220
Some(path)
223-
case Left(cause) =>
221+
case Left(cause) if isSupportedVersion =>
224222
logger.displayWarningToUser(Feedback.failedMetalsScalaConfiguration(scalaVersion, cause))
225223
None
224+
225+
// We try to download anyway, but don't print the exception
226+
case _ =>
227+
None
226228
}
227229
}
228230
}

frontend/src/main/scala/bloop/engine/Dag.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import bloop.data.Project
88
import bloop.util.CacheHashCode
99

1010
import scalaz.Show
11+
import scala.collection.immutable.ListSet
1112

1213
/**
1314
* A [[Dag]] is a Directed Acyclic Graph where each node contains a value of T
@@ -365,4 +366,16 @@ object Dag {
365366
|${edges.mkString(" ", "\n ", "")}
366367
|}""".stripMargin
367368
}
369+
370+
def topologicalSort[T](dag: Dag[T]): List[T] = {
371+
def inner(buf: ListSet[T], dag: Dag[T]): ListSet[T] = dag match {
372+
case Leaf(value) =>
373+
buf + value
374+
case Parent(value, children) =>
375+
children.foldLeft(buf)(inner(_, _)) + value
376+
case Aggregate(dags) =>
377+
dags.foldLeft(buf)(inner(_, _))
378+
}
379+
inner(ListSet.empty, dag).toList
380+
}
368381
}

frontend/src/test/scala/bloop/DagSpec.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,17 @@ class DagSpec {
6262
case Leaf(f) => assert(f == p, s"$f is not $p")
6363
}
6464

65+
private def assertAppearsBefore[T](elems: List[T], ancestor: T, successor: T): Unit = {
66+
Assert.assertTrue(
67+
s"$ancestor doesnt appear before $successor in $elems",
68+
elems.indexOf(ancestor) < elems.indexOf(successor)
69+
)
70+
}
71+
72+
private def assertAppearsBefore[T](elems: List[T], ancestor: T, successors: List[T]): Unit = {
73+
successors.foreach(assertAppearsBefore(elems, ancestor, _))
74+
}
75+
6576
@Test def EmptyDAG(): Unit = {
6677
val dags = fromMap(Map())
6778
assert(dags.isEmpty)
@@ -269,4 +280,17 @@ class DagSpec {
269280
Assert.assertEquals("all case 8", Set(i, h), allInverseDeps(List(h)))
270281
Assert.assertEquals("all case 9", Set(i), allInverseDeps(List(i)))
271282
}
283+
284+
@Test
285+
def TestTopologicalSort(): Unit = {
286+
import ComplexDag._
287+
val allProjects = List(a, b, c, d, e, f, g, h, i)
288+
val dags = fromMap(allProjects.map(p => p.name -> p).toMap)
289+
val sorted = Dag.topologicalSort(Aggregate(dags))
290+
assertAppearsBefore(sorted, a, List(b, c, d, e))
291+
assertAppearsBefore(sorted, c, List(d, e))
292+
assertAppearsBefore(sorted, d, List(e))
293+
assertAppearsBefore(sorted, f, List(g, h, i))
294+
assertAppearsBefore(sorted, h, List(i))
295+
}
272296
}

0 commit comments

Comments
 (0)