Skip to content

Commit 0f909b5

Browse files
committed
Implement a new trait Inputs, that aggregates ModuleInputs
1 parent 8181ed1 commit 0f909b5

File tree

15 files changed

+149
-83
lines changed

15 files changed

+149
-83
lines changed

modules/build/src/main/scala/scala/build/bsp/BloopSession.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@ import java.util.concurrent.atomic.AtomicReference
66

77
import scala.build.Build
88
import scala.build.compiler.BloopCompiler
9-
import scala.build.input.{ModuleInputs, OnDisk, SingleFile, Virtual}
9+
import scala.build.input.{ModuleInputs, OnDisk, SingleFile, Virtual, compose}
1010

1111
final class BloopSession(
12-
val inputs: Seq[ModuleInputs],
12+
val inputs: compose.Inputs,
1313
// val inputsHash: String, TODO Fix inputs hash comparing
1414
val remoteServer: BloopCompiler,
1515
val bspServer: BspServer,
1616
val watcher: Build.Watcher
1717
) {
1818
def resetDiagnostics(localClient: BspClient): Unit = for {
19-
moduleInputs <- inputs
20-
targetId <- bspServer.targetProjectIdOpt(moduleInputs.projectName)
19+
module <- inputs.modules
20+
targetId <- bspServer.targetProjectIdOpt(module.projectName)
2121
} do
22-
moduleInputs.flattened().foreach {
22+
module.flattened().foreach {
2323
case f: SingleFile =>
2424
localClient.resetDiagnostics(f.path, targetId)
2525
case _: Virtual =>
@@ -31,7 +31,7 @@ final class BloopSession(
3131
}
3232

3333
def registerWatchInputs(): Unit = for {
34-
module <- inputs
34+
module <- inputs.modules
3535
element <- module.elements
3636
} do
3737
element match {
@@ -65,7 +65,7 @@ final class BloopSession(
6565
object BloopSession {
6666

6767
def apply(
68-
inputs: Seq[ModuleInputs],
68+
inputs: compose.Inputs,
6969
remoteServer: BloopCompiler,
7070
bspServer: BspServer,
7171
watcher: Build.Watcher

modules/build/src/main/scala/scala/build/bsp/Bsp.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ package scala.build.bsp
33
import java.io.{InputStream, OutputStream}
44

55
import scala.build.errors.BuildException
6-
import scala.build.input.{ModuleInputs, ScalaCliInvokeData}
6+
import scala.build.input.{ModuleInputs, ScalaCliInvokeData, compose}
77
import scala.concurrent.Future
88

99
trait Bsp {
10-
def run(initialInputs: Seq[ModuleInputs], initialBspOptions: BspReloadableOptions): Future[Unit]
10+
def run(initialInputs: compose.Inputs, initialBspOptions: BspReloadableOptions): Future[Unit]
1111
def shutdown(): Unit
1212
}
1313

1414
object Bsp {
1515
def create(
16-
argsToInputs: Seq[String] => Either[BuildException, Seq[ModuleInputs]],
16+
argsToInputs: Seq[String] => Either[BuildException, compose.Inputs],
1717
bspReloadableOptionsReference: BspReloadableOptions.Reference,
1818
threads: BspThreads,
1919
in: InputStream,

modules/build/src/main/scala/scala/build/bsp/BspImpl.scala

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import scala.build.errors.{
2121
Diagnostic,
2222
ParsingInputsException
2323
}
24-
import scala.build.input.{ModuleInputs, ScalaCliInvokeData}
24+
import scala.build.input.{ModuleInputs, ScalaCliInvokeData, compose}
2525
import scala.build.internal.Constants
2626
import scala.build.options.{BuildOptions, Scope}
2727
import scala.collection.mutable.ListBuffer
@@ -44,7 +44,7 @@ import scala.util.{Failure, Success}
4444
* the output stream of bytes
4545
*/
4646
final class BspImpl(
47-
argsToInputs: Seq[String] => Either[BuildException, Seq[ModuleInputs]],
47+
argsToInputs: Seq[String] => Either[BuildException, compose.Inputs],
4848
bspReloadableOptionsReference: BspReloadableOptions.Reference,
4949
threads: BspThreads,
5050
in: InputStream,
@@ -107,7 +107,7 @@ final class BspImpl(
107107
val persistentLogger = new PersistentDiagnosticLogger(logger)
108108
val bspServer = currentBloopSession.bspServer
109109

110-
val prebuildModules = for (module <- currentBloopSession.inputs) yield {
110+
val prebuildModules = for (module <- currentBloopSession.inputs.modulesBuildOrder) yield {
111111
val mainProjectName = module.projectName
112112
val testProjectName = module.scopeProjectName(Scope.Test)
113113

@@ -392,7 +392,7 @@ final class BspImpl(
392392
inputs.generatedSrcRoot(scope),
393393
data.classesDir,
394394
reloadableOptions.logger,
395-
currentBloopSession.inputs.head.workspace, // FIXME .head, maybe add workspace to BloopSession
395+
currentBloopSession.inputs.workspace,
396396
updateSemanticDbs = true,
397397
scalaVersion = sv,
398398
buildOptions = data.buildOptions
@@ -440,21 +440,21 @@ final class BspImpl(
440440
* a new [[BloopSession]]
441441
*/
442442
private def newBloopSession(
443-
inputs: Seq[ModuleInputs],
443+
inputs: compose.Inputs,
444444
reloadableOptions: BspReloadableOptions,
445445
presetIntelliJ: Boolean = false
446446
): BloopSession = {
447447
val logger = reloadableOptions.logger
448448
val buildOptions = reloadableOptions.buildOptions
449-
val workspace = inputs.head.workspace
449+
val workspace = inputs.workspace
450450
val createBloopServer =
451451
() =>
452452
BloopServer.buildServer(
453453
reloadableOptions.bloopRifleConfig,
454454
"scala-cli",
455455
Constants.version,
456-
(workspace / Constants.workspaceDirName).toNIO, // FIXME .head, introduce better types for Seq[ModuleInputs] that will have a common workspace
457-
Build.classesRootDir(workspace, inputs.head.projectName).toNIO,
456+
(workspace / Constants.workspaceDirName).toNIO,
457+
Build.classesRootDir(workspace, inputs.targetModule.projectName).toNIO,
458458
localClient,
459459
threads.buildThreads.bloop,
460460
logger.bloopRifleLogger
@@ -493,7 +493,7 @@ final class BspImpl(
493493
* change on subsequent workspace/reload requests)
494494
*/
495495
override def run(
496-
initialInputs: Seq[ModuleInputs],
496+
initialInputs: compose.Inputs,
497497
initialBspOptions: BspReloadableOptions
498498
): Future[Unit] = {
499499
val logger = initialBspOptions.logger
@@ -597,8 +597,8 @@ final class BspImpl(
597597
*/
598598
private def reloadBsp(
599599
currentBloopSession: BloopSession,
600-
previousInputs: Seq[ModuleInputs],
601-
newInputs: Seq[ModuleInputs],
600+
previousInputs: compose.Inputs,
601+
newInputs: compose.Inputs,
602602
reloadableOptions: BspReloadableOptions
603603
): CompletableFuture[AnyRef] = {
604604
val previousTargetIds = currentBloopSession.bspServer.targetIds
@@ -653,10 +653,10 @@ final class BspImpl(
653653
}
654654
else newBloopSession0
655655

656-
val previousProjectNames = previousInputs.flatMap(m =>
656+
val previousProjectNames = previousInputs.modules.flatMap(m =>
657657
Seq(m.scopeProjectName(Scope.Main), m.scopeProjectName(Scope.Test))
658658
).toSet
659-
val newProjectNames = newInputs.flatMap(m =>
659+
val newProjectNames = newInputs.modules.flatMap(m =>
660660
Seq(m.scopeProjectName(Scope.Main), m.scopeProjectName(Scope.Test))
661661
).toSet
662662

@@ -688,7 +688,7 @@ final class BspImpl(
688688
actualLocalClient.logger = logger
689689
localClient = getLocalClient(verbosity)
690690
val ideInputsJsonPath =
691-
currentBloopSession.inputs.head.workspace / Constants.workspaceDirName / "ide-inputs.json"
691+
currentBloopSession.inputs.workspace / Constants.workspaceDirName / "ide-inputs.json"
692692
if (os.isFile(ideInputsJsonPath)) {
693693
val maybeResponse = either[BuildException] {
694694
val ideInputs = value {

modules/build/src/main/scala/scala/build/bsp/BspReloadableOptions.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import bloop.rifle.BloopRifleConfig
55
import scala.build.Logger
66
import scala.build.options.BuildOptions
77

8-
/** The options and configurations that may be picked up on a bsp workspace/reload request.
9-
* They don't take into account options from sources.
10-
* The only two exceptions are the initial options in BspImpl.run
11-
* and in options used to launch new bloop in BspImpl.reloadBsp, which have the [[bloopRifleConfig]] updated.
8+
/** The options and configurations that may be picked up on a bsp workspace/reload request. They
9+
* don't take into account options from sources. The only two exceptions are the initial options in
10+
* BspImpl.run and in options used to launch new bloop in BspImpl.reloadBsp, which have the
11+
* [[bloopRifleConfig]] updated.
1212
*
1313
* @param buildOptions
1414
* passed options for building sources

modules/build/src/main/scala/scala/build/bsp/BuildServerProxy.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import java.util.concurrent.CompletableFuture
66

77
import scala.build.GeneratedSource
88
import scala.build.bsp.buildtargets.{ManagesBuildTargets, ProjectName}
9-
import scala.build.input.ModuleInputs
9+
import scala.build.input.{ModuleInputs, compose}
1010
import scala.build.options.Scope
1111

1212
/** A wrapper for [[BspServer]], allowing to reload the workspace on the fly.
@@ -113,6 +113,6 @@ class BuildServerProxy(
113113
bspServer().addTarget(projectName, workspace, scope, generatedSources)
114114
def resetTargets(): Unit =
115115
bspServer().resetTargets()
116-
def newInputs(inputs: Seq[ModuleInputs]): Unit =
116+
def newInputs(inputs: compose.Inputs): Unit =
117117
bspServer().newInputs(inputs)
118118
}

modules/build/src/main/scala/scala/build/bsp/buildtargets/ManagesBuildTargets.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import ch.epfl.scala.bsp4j.BuildTargetIdentifier
44
import ch.epfl.scala.bsp4j as b
55

66
import scala.build.GeneratedSource
7-
import scala.build.input.ModuleInputs
7+
import scala.build.input.{ModuleInputs, compose}
88
import scala.build.internal.Constants
99
import scala.build.options.Scope
1010

@@ -18,7 +18,7 @@ trait ManagesBuildTargets {
1818
generatedSources: Seq[GeneratedSource] = Nil
1919
): Unit
2020
def resetTargets(): Unit
21-
def newInputs(inputs: Seq[ModuleInputs]): Unit
21+
def newInputs(inputs: compose.Inputs): Unit
2222
def setGeneratedSources(projectName: ProjectName, sources: Seq[GeneratedSource]): Unit
2323
}
2424

modules/build/src/main/scala/scala/build/bsp/buildtargets/ManagesBuildTargetsImpl.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import ch.epfl.scala.bsp4j as b
55
import scala.build.GeneratedSource
66
import scala.build.bsp.buildtargets.ManagesBuildTargets
77
import scala.build.errors.{BuildException, WorkspaceError}
8-
import scala.build.input.ModuleInputs
8+
import scala.build.input.{ModuleInputs, compose}
99
import scala.build.internal.Constants
1010
import scala.build.options.Scope
1111
import scala.collection.mutable
@@ -34,9 +34,9 @@ trait ManagesBuildTargetsImpl extends ManagesBuildTargets {
3434
): Unit =
3535
managedTargets.put(projectName, BuildTarget(projectName, workspace, scope, generatedSources))
3636

37-
override def newInputs(inputs: Seq[ModuleInputs]): Unit = {
37+
override def newInputs(inputs: compose.Inputs): Unit = {
3838
resetTargets()
39-
inputs.foreach { module =>
39+
inputs.modules.foreach { module =>
4040
addTarget(module.projectName, module.workspace, Scope.Main)
4141
addTarget(module.scopeProjectName(Scope.Test), module.workspace, Scope.Test)
4242
}
Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,53 @@
11
package scala.build.input.compose
22

3-
import scala.build.input.WorkspaceOrigin
4-
import scala.build.input.ModuleInputs
3+
import scala.build.bsp.buildtargets.ProjectName
4+
import scala.build.input.{ModuleInputs, WorkspaceOrigin}
55
import scala.build.options.BuildOptions
6+
import scala.collection.mutable
67

78
sealed trait Inputs {
8-
9+
910
def modules: Seq[ModuleInputs]
1011

11-
/** Module targeted by the user. If a command requires a target to be executed (e.g. run or compile), it should be executed on this module. */
12+
/** Module targeted by the user. If a command requires a target to be executed (e.g. run or
13+
* compile), it should be executed on this module.
14+
*/
1215
def targetModule: ModuleInputs
13-
/** Build order for modules to execute the command on the [[targetModule]] */
16+
17+
/** Order in which to build all modules */
1418
def modulesBuildOrder: Seq[ModuleInputs]
15-
def workspaceOrigin: WorkspaceOrigin
19+
20+
/** Order in which to build the target module with its dependencies, e.g. to execute a command on
21+
* [[targetModule]]
22+
*/
23+
def targetBuildOrder: Seq[ModuleInputs]
24+
def workspaceOrigin: Option[WorkspaceOrigin]
1625
def workspace: os.Path
1726

18-
def preprocessInputs(preprocess: ModuleInputs => (ModuleInputs, BuildOptions)): (Inputs, Seq[BuildOptions])
27+
def preprocessInputs(preprocess: ModuleInputs => (ModuleInputs, BuildOptions))
28+
: (Inputs, Seq[BuildOptions])
1929
}
2030

2131
/** Result of using [[InputsComposer]] with module config file present */
2232
case class ComposedInputs(
2333
modules: Seq[ModuleInputs],
2434
targetModule: ModuleInputs,
25-
workspace: os.Path,
35+
workspace: os.Path
2636
) extends Inputs {
2737

2838
// Forced to be the directory where module config file (modules.yaml) resides
29-
override val workspaceOrigin: WorkspaceOrigin = WorkspaceOrigin.Forced
39+
override val workspaceOrigin: Option[WorkspaceOrigin] = Some(WorkspaceOrigin.Forced)
3040

31-
lazy val modulesBuildOrder: Seq[ModuleInputs] = {
32-
val nameMap = modules.map(m => m.projectName -> m)
33-
val dependencyGraph = modules.map(m => m.projectName -> m.moduleDependencies)
41+
private val nameMap: Map[ProjectName, ModuleInputs] = modules.map(m => m.projectName -> m).toMap
42+
private val dependencyGraph = modules.map(m => m.projectName -> m.moduleDependencies).toMap
3443

35-
val visited = mutable.Set.empty[Name] // Track visited nodes
36-
val result = mutable.Stack.empty[Name] // Use a stack to build the result in reverse order
44+
private def buildOrderForModule(
45+
root: ModuleInputs,
46+
visitedPreviously: Set[ProjectName]
47+
): Seq[ProjectName] = {
48+
val visited = mutable.Set.from(visitedPreviously) // Track visited nodes
49+
val result =
50+
mutable.Stack.empty[ProjectName] // Use a stack to build the result in reverse order
3751

3852
def visit(node: ProjectName): Unit = {
3953
if (!visited.contains(node)) {
@@ -43,37 +57,53 @@ case class ComposedInputs(
4357
}
4458
}
4559

46-
dependencyGraph.keys.foreach(visit)
47-
48-
result.toSeq.reverse
60+
visit(root.projectName)
61+
result.reverse.toSeq
4962
}
5063

51-
def preprocessInputs(preprocess: ModuleInputs => (ModuleInputs, BuildOptions)): (ComposedInputs, Seq[BuildOptions]) = {
52-
val (preprocessedModules, buildOptions) =>
53-
modules.filter(_.projectName == targetModule.projectName)
64+
override lazy val modulesBuildOrder: Seq[ModuleInputs] =
65+
modules.foldLeft(Seq.empty[ProjectName]) { (acc, module) =>
66+
val buildOrder = buildOrderForModule(module, visitedPreviously = acc.toSet)
67+
acc.appendedAll(buildOrder)
68+
}.map(nameMap)
69+
70+
override lazy val targetBuildOrder: Seq[ModuleInputs] =
71+
buildOrderForModule(targetModule, Set.empty).map(nameMap)
72+
73+
def preprocessInputs(preprocess: ModuleInputs => (ModuleInputs, BuildOptions))
74+
: (ComposedInputs, Seq[BuildOptions]) = {
75+
val (preprocessedModules, buildOptions) =
76+
modules.filterNot(_.projectName == targetModule.projectName)
5477
.map(preprocess)
5578
.unzip
5679

57-
val preprocessedTargetModule = preprocess(targetModule)
80+
val (preprocessedTargetModule, targetBuildOptions) = preprocess(targetModule)
5881

59-
copy(modules = preprocessedModules ++ preprocessedTargetModule, targetModule = preprocessedTargetModule) -> buildOptions
82+
copy(
83+
modules = preprocessedModules.appended(preprocessedTargetModule),
84+
targetModule = preprocessedTargetModule
85+
) -> buildOptions.appended(targetBuildOptions)
6086
}
6187
}
6288

6389
/** Essentially a wrapper over a single module, no config file for modules involved */
6490
case class SimpleInputs(
65-
singleModule: ModuleInputs,
91+
singleModule: ModuleInputs
6692
) extends Inputs {
6793
override val modules: Seq[ModuleInputs] = Seq(singleModule)
6894

6995
override val targetModule: ModuleInputs = singleModule
7096

71-
override val modulesBuildOrder = modules
97+
override val modulesBuildOrder: Seq[ModuleInputs] = modules
98+
99+
override val targetBuildOrder: Seq[ModuleInputs] = modules
72100

73101
override val workspace: os.Path = singleModule.workspace
74102

75-
override val workspaceOrigin: WorkspaceOrigin = singleModule.workspaceOrigin
103+
override val workspaceOrigin: Option[WorkspaceOrigin] = singleModule.workspaceOrigin
76104

77-
def preprocessInputs(preprocess: ModuleInputs => (ModuleInputs, BuildOptions)): (ComposedInputs, Seq[BuildOptions]) =
78-
copy(singleModule = preprocess(singleModule)) -> buildOptions
105+
override def preprocessInputs(preprocess: ModuleInputs => (ModuleInputs, BuildOptions))
106+
: (SimpleInputs, Seq[BuildOptions]) =
107+
val (preprocessedModule, buildOptions) = preprocess(singleModule)
108+
copy(singleModule = preprocessedModule) -> Seq(buildOptions)
79109
}

0 commit comments

Comments
 (0)