Skip to content

Commit 2e4e025

Browse files
committed
Compose inputs in SetupIde, add fixes to Bsp initial configuration
1 parent dc7d94a commit 2e4e025

File tree

3 files changed

+69
-59
lines changed

3 files changed

+69
-59
lines changed

modules/build/src/main/scala/scala/build/input/InputsComposer.scala

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,36 @@ import scala.collection.mutable
1313

1414
object InputsComposer {
1515

16+
// TODO errors on corner cases
17+
def findModuleConfig(
18+
args: Seq[String],
19+
cwd: os.Path
20+
): Either[ModuleConfigurationError, Option[os.Path]] = {
21+
def moduleConfigDirectlyFromArgs = {
22+
val moduleConfigPathOpt = args
23+
.map(arg => os.Path(arg, cwd))
24+
.find(_.endsWith(os.RelPath(Constants.moduleConfigFileName)))
25+
26+
moduleConfigPathOpt match {
27+
case Some(path) if os.exists(path) => Right(Some(path))
28+
case Some(path) => Left(ModuleConfigurationError(
29+
s"""File does not exist:
30+
| - $path
31+
|""".stripMargin
32+
))
33+
case None => Right(None)
34+
}
35+
}
36+
37+
def moduleConfigFromCwd =
38+
Right(os.walk(cwd).find(p => p.endsWith(os.RelPath(Constants.moduleConfigFileName))))
39+
40+
for {
41+
fromArgs <- moduleConfigDirectlyFromArgs
42+
fromCwd <- moduleConfigFromCwd
43+
} yield fromArgs.orElse(fromCwd)
44+
}
45+
1646
private[input] object Keys {
1747
val modules = "modules"
1848
val roots = "roots"
@@ -107,7 +137,7 @@ final case class InputsComposer(
107137

108138
def getModuleInputs: Either[BuildException, Seq[ModuleInputs]] =
109139
if allowForbiddenFeatures then
110-
findModuleConfig match {
140+
findModuleConfig(args, cwd) match {
111141
case Right(Some(moduleConfigPath)) =>
112142
val configText = os.read(moduleConfigPath)
113143
for {
@@ -129,33 +159,6 @@ final case class InputsComposer(
129159
// case _ => Left("scalaVersion must be a string")
130160
// }
131161

132-
// TODO errors on corner cases
133-
private def findModuleConfig: Either[ModuleConfigurationError, Option[os.Path]] = {
134-
def moduleConfigDirectlyFromArgs = {
135-
val moduleConfigPathOpt = args
136-
.map(arg => os.Path(arg, cwd))
137-
.find(_.endsWith(os.RelPath(Constants.moduleConfigFileName)))
138-
139-
moduleConfigPathOpt match {
140-
case Some(path) if os.exists(path) => Right(Some(path))
141-
case Some(path) => Left(ModuleConfigurationError(
142-
s"""File does not exist:
143-
| - $path
144-
|""".stripMargin
145-
))
146-
case None => Right(None)
147-
}
148-
}
149-
150-
def moduleConfigFromCwd =
151-
Right(os.walk(cwd).find(p => p.endsWith(os.RelPath(Constants.moduleConfigFileName))))
152-
153-
for {
154-
fromArgs <- moduleConfigDirectlyFromArgs
155-
fromCwd <- moduleConfigFromCwd
156-
} yield fromArgs.orElse(fromCwd)
157-
}
158-
159162
private def checkForCycles(modules: Seq[ModuleDefinition])
160163
: Either[ModuleConfigurationError, Unit] = either {
161164
val lookup = Map.from(modules.map(module => module.name -> module))
@@ -195,10 +198,12 @@ final case class InputsComposer(
195198
modules: Seq[ModuleDefinition],
196199
moduleConfigPath: os.Path
197200
): Either[BuildException, Seq[ModuleInputs]] = either {
201+
val workspacePath = moduleConfigPath / os.up
198202
val moduleInputsInfo = modules.map { m =>
199-
val moduleName = ProjectName(m.name)
200-
val moduleInputs = inputsFromArgs(m.roots, Some(moduleName))
201-
m -> value(moduleInputs)
203+
val moduleName = ProjectName(m.name)
204+
val argsWithWorkspace = m.roots.map(r => os.Path(r, workspacePath).toString)
205+
val moduleInputs = inputsFromArgs(argsWithWorkspace, Some(moduleName))
206+
m -> value(moduleInputs).copy(mayAppendHash = false)
202207
}
203208

204209
val projectNameMap: Map[String, ProjectName] =
@@ -208,7 +213,8 @@ final case class InputsComposer(
208213
val moduleDeps: Seq[ProjectName] = moduleDef.dependsOn.map(projectNameMap)
209214

210215
inputs.dependsOn(moduleDeps)
211-
.withForcedWorkspace(moduleConfigPath / os.up)
216+
.withForcedWorkspace(workspacePath)
217+
.copy(mayAppendHash = false)
212218
}
213219

214220
moduleInputs

modules/cli/src/main/scala/scala/cli/commands/bsp/Bsp.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ object Bsp extends ScalaCommand[BspOptions] {
8585
val preprocessInputs: Seq[String] => Either[BuildException, Seq[(ModuleInputs, BuildOptions)]] =
8686
argsSeq =>
8787
either {
88-
val sharedOptions = getSharedOptions()
88+
val sharedOptions = getSharedOptions()
8989
val launcherOptions = getLauncherOptions()
9090
val envs = getEnvsFromFile()
9191

@@ -135,9 +135,13 @@ object Bsp extends ScalaCommand[BspOptions] {
135135
val inputsAndBuildOptions = preprocessInputs(args.all).orExit(logger)
136136

137137
// TODO reported override option values
138+
// FIXME Only some options need to be unified for the whole project, like scala version, JVM
138139
val finalBuildOptions = inputsAndBuildOptions.map(_._2).reduceLeft(_ orElse _)
139140
val inputs = inputsAndBuildOptions.map(_._1)
140141

142+
if (options.shared.logging.verbosity >= 3)
143+
pprint.err.log(finalBuildOptions)
144+
141145
/** values used for lauching the bsp, especially for launching a bloop server, they include
142146
* options extracted from sources
143147
*/

modules/cli/src/main/scala/scala/cli/commands/setupide/SetupIde.scala

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ import com.github.plokhotnyuk.jsoniter_scala.macros.JsonCodecMaker
77
import com.google.gson.GsonBuilder
88

99
import java.nio.charset.{Charset, StandardCharsets}
10-
1110
import scala.build.EitherCps.{either, value}
1211
import scala.build.*
1312
import scala.build.bsp.IdeInputs
1413
import scala.build.errors.{BuildException, WorkspaceError}
15-
import scala.build.input.{ModuleInputs, OnDisk, Virtual, WorkspaceOrigin}
14+
import scala.build.input.{InputsComposer, ModuleInputs, OnDisk, Virtual, WorkspaceOrigin}
1615
import scala.build.internal.Constants
1716
import scala.build.options.{BuildOptions, Scope}
1817
import scala.cli.CurrentParams
@@ -67,12 +66,12 @@ object SetupIde extends ScalaCommand[SetupIdeOptions] {
6766

6867
override def runCommand(options: SetupIdeOptions, args: RemainingArgs, logger: Logger): Unit = {
6968
val buildOptions = buildOptionsOrExit(options)
70-
val inputs = options.shared.inputs(args.all).orExit(logger)
71-
CurrentParams.workspaceOpt = Some(inputs.workspace)
69+
val moduleInputs = options.shared.composeInputs(args.all).orExit(logger)
70+
CurrentParams.workspaceOpt = Some(moduleInputs.head.workspace)
7271

7372
val bspPath = writeBspConfiguration(
7473
options,
75-
inputs,
74+
moduleInputs,
7675
buildOptions,
7776
previousCommandName = None,
7877
args = args.all
@@ -91,7 +90,7 @@ object SetupIde extends ScalaCommand[SetupIdeOptions] {
9190
): Unit =
9291
writeBspConfiguration(
9392
SetupIdeOptions(shared = options),
94-
inputs,
93+
Seq(inputs),
9594
buildOptions,
9695
previousCommandName,
9796
args
@@ -105,13 +104,13 @@ object SetupIde extends ScalaCommand[SetupIdeOptions] {
105104

106105
private def writeBspConfiguration(
107106
options: SetupIdeOptions,
108-
inputs: ModuleInputs,
107+
moduleInputs: Seq[ModuleInputs],
109108
buildOptions: BuildOptions,
110109
previousCommandName: Option[String],
111110
args: Seq[String]
112111
): Either[BuildException, Option[os.Path]] = either {
113112

114-
val virtualInputs = inputs.elements.collect {
113+
val virtualInputs = moduleInputs.flatMap(_.elements).collect {
115114
case v: Virtual => v
116115
}
117116
if (virtualInputs.nonEmpty)
@@ -124,23 +123,24 @@ object SetupIde extends ScalaCommand[SetupIdeOptions] {
124123
val logger = options.shared.logger
125124

126125
if (buildOptions.classPathOptions.allExtraDependencies.toSeq.nonEmpty)
127-
value(downloadDeps(
128-
inputs,
129-
buildOptions,
130-
logger
131-
))
132-
133-
val (bspName, bspJsonDestination) = bspDetails(inputs.workspace, options.bspFile)
134-
val scalaCliBspJsonDestination =
135-
inputs.workspace / Constants.workspaceDirName / "ide-options-v2.json"
136-
val scalaCliBspLauncherOptsJsonDestination =
137-
inputs.workspace / Constants.workspaceDirName / "ide-launcher-options.json"
138-
val scalaCliBspInputsJsonDestination =
139-
inputs.workspace / Constants.workspaceDirName / "ide-inputs.json"
140-
val scalaCliBspEnvsJsonDestination =
141-
inputs.workspace / Constants.workspaceDirName / "ide-envs.json"
142-
143-
val inputArgs = inputs.elements.collect { case d: OnDisk => d.path.toString }
126+
for (module <- moduleInputs) do value(downloadDeps(module, buildOptions, logger))
127+
128+
val workspace = moduleInputs.head.workspace
129+
130+
val (bspName, bspJsonDestination) = bspDetails(workspace, options.bspFile)
131+
val scalaCliBspJsonDestination = workspace / Constants.workspaceDirName / "ide-options-v2.json"
132+
val scalaCliBspLauncherOptsJsonDestination = workspace / Constants.workspaceDirName / "ide-launcher-options.json"
133+
val scalaCliBspInputsJsonDestination = workspace / Constants.workspaceDirName / "ide-inputs.json"
134+
val scalaCliBspEnvsJsonDestination = workspace / Constants.workspaceDirName / "ide-envs.json"
135+
136+
// FIXME single modules can also be defined with module config toml file
137+
val inputArgs = if moduleInputs.size > 1 then
138+
InputsComposer.findModuleConfig(args, Os.pwd)
139+
.orExit(logger)
140+
.fold(args)(p => Seq(p.toString))
141+
else
142+
moduleInputs.head.elements
143+
.collect { case d: OnDisk => d.path.toString }
144144

145145
val ideInputs = IdeInputs(
146146
options.shared.validateInputArgs(args)
@@ -187,7 +187,7 @@ object SetupIde extends ScalaCommand[SetupIdeOptions] {
187187
val scalaCliBspInputsJson = writeToArray(ideInputs)
188188
val scalaCliBspEnvsJson = writeToArray(sys.env)
189189

190-
if (inputs.workspaceOrigin.contains(WorkspaceOrigin.HomeDir))
190+
if (moduleInputs.head.workspaceOrigin.contains(WorkspaceOrigin.HomeDir))
191191
value(Left(new WorkspaceError(
192192
s"""$baseRunnerName can not determine where to write its BSP configuration.
193193
|Set an explicit BSP directory path via `--bsp-directory`.

0 commit comments

Comments
 (0)