Skip to content

Commit 26da6ca

Browse files
Allow users to disable some modules in BSP (#6065)
This adds a `def enableBsp: Boolean` method on `JavaModule` (via `BspModuleApi`). Users can override this method and make it return `false` to make the BSP server hide / ignore that module. Note that for consistency, if a module depends on another that has `enableBsp` set to false, it gets itself disabled too. Else, that might create situations where a module is loaded in BSP, but some of its dependencies would just be missing because they have `enableBsp` set to false.
1 parent 7de25d9 commit 26da6ca

File tree

6 files changed

+86
-16
lines changed

6 files changed

+86
-16
lines changed

core/api/daemon/src/mill/api/daemon/internal/bsp/BspModuleApi.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ trait BspModuleApi extends ModuleApi {
66
private[mill] def bspBuildTargetData: TaskApi[Option[(String, AnyRef)]]
77
private[mill] def bspBuildTarget: BspBuildTarget
88
private[mill] def bspDisplayName: String
9+
10+
/**
11+
* Set this to false to make the Mill BSP server hide / ignore that module
12+
*
13+
* Beware that if a module depends via `moduleDeps` or `compileModuleDeps` on modules
14+
* that have `enableBsp` set to false, it will be ignored by the Mill BSP server too
15+
*/
16+
def enableBsp: Boolean = true
917
}
1018

1119
object BspModuleApi {

integration/ide/bsp-server/resources/project/build.mill

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,14 @@ object sourcesNeedCompile extends scalalib.ScalaModule {
114114
super.sources()
115115
}
116116
}
117+
118+
object skipped extends scalalib.ScalaModule {
119+
def enableBsp = false
120+
def scalaVersion = Option(System.getenv("TEST_SCALA_2_13_VERSION")).getOrElse(???)
121+
}
122+
123+
// depends on skipped module, but doesn't set enableBsp to false - should be ignored from BSP anyway
124+
object dependsOnSkipped extends scalalib.ScalaModule {
125+
def moduleDeps = Seq(skipped)
126+
def scalaVersion = Option(System.getenv("TEST_SCALA_2_13_VERSION")).getOrElse(???)
127+
}

integration/ide/bsp-server/resources/snapshots/logging

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@
77
[bsp-init-mill-build/build.mill-59] [info] done compiling
88
[bsp-init-build.mill-59] [info] compiling * Scala sources to * ...
99
[bsp-init-build.mill-59] [info] done compiling
10-
[bsp-init-098] [info] compiling * Scala source to * ...
11-
[bsp-init-098] [info] done compiling
10+
[bsp-init-106] [info] compiling * Scala source to * ...
11+
[bsp-init-106] [info] done compiling
12+
[bsp-init] BSP disabled for target file:///workspace/dependsOnSkipped because of its dependencies file:///workspace/skipped
13+
[bsp-init] BSP disabled for target file:///workspace/skipped via BspModuleApi#enableBsp
1214
[bsp-init] SNAPSHOT
1315
[2-workspaceBuildTargets] Entered workspaceBuildTargets
16+
[bsp-init] BSP disabled for target file:///workspace/dependsOnSkipped because of its dependencies file:///workspace/skipped
17+
[bsp-init] BSP disabled for target file:///workspace/skipped via BspModuleApi#enableBsp
1418
[2-workspaceBuildTargets] Evaluating * tasks
1519
[2-workspaceBuildTargets] Done
1620
[2-workspaceBuildTargets] Evaluating 1 task

integration/ide/bsp-server/src/BspServerTests.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,11 @@ object BspServerTests extends UtestIntegrationTestSuite {
420420
delayedCompileFuture.get()
421421
}
422422

423+
val workspaceUri = tester.workspacePath.toURI.toASCIIString.stripSuffix("/") + "/"
423424
val logs = stderr.toString
424425
.linesWithSeparators
425426
.filter(_.startsWith("["))
427+
.map(_.replace(workspaceUri, "file:///workspace/"))
426428
.mkString
427429

428430
val expectedCancelledLine = "[7-compile] buildTargetCompile was cancelled"

libs/javalib/src/mill/javalib/JavaModule.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ trait JavaModule
8080
outer.repositoriesTask()
8181
}
8282

83+
override def enableBsp: Boolean = outer.enableBsp
84+
8385
override def resolutionCustomizer: Task[Option[coursier.Resolution => coursier.Resolution]] =
8486
outer.resolutionCustomizer
8587

runner/bsp/worker/src/mill/bsp/worker/BspEvaluators.scala

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import mill.api.daemon.internal.{BaseModuleApi, EvaluatorApi, JavaModuleApi, Mod
66
import mill.api.daemon.Watchable
77

88
import java.nio.file.Path
9+
import java.util.concurrent.ConcurrentHashMap
910

1011
private[mill] class BspEvaluators(
1112
workspaceDir: os.Path,
@@ -15,30 +16,72 @@ private[mill] class BspEvaluators(
1516
) {
1617

1718
/**
18-
* Compute all transitive modules from module children and via moduleDeps + compileModuleDeps
19+
* Compute all transitive modules from module children via moduleDirectChildren
1920
*/
2021
def transitiveModules(module: ModuleApi): Seq[ModuleApi] = {
2122
Seq(module) ++ module.moduleDirectChildren.flatMap(transitiveModules)
2223
}
2324

24-
lazy val bspModulesIdList0: Seq[(BuildTargetIdentifier, (BspModuleApi, EvaluatorApi))] = {
25-
val modules: Seq[(ModuleApi, Seq[ModuleApi], EvaluatorApi)] = evaluators
26-
.map(ev => (ev.rootModule, transitiveModules(ev.rootModule), ev))
25+
private val transitiveDependencyModules0 = new ConcurrentHashMap[ModuleApi, Seq[ModuleApi]]
26+
private val transitiveModulesEnableBsp0 =
27+
new ConcurrentHashMap[ModuleApi, Option[Seq[BspModuleApi]]]
2728

28-
val regularModules = modules
29-
.flatMap { case (rootModule, modules, eval) =>
30-
modules.collect {
31-
case m: BspModuleApi =>
32-
val uri = Utils.sanitizeUri(
33-
(os.Path(rootModule.moduleDirJava) / m.moduleSegments.parts).toNIO
34-
)
29+
// Compute all transitive dependency modules via moduleDeps + compileModuleDeps
30+
private def transitiveDependencyModules(module: ModuleApi): Seq[ModuleApi] = {
31+
if (!transitiveDependencyModules0.contains(module)) {
32+
val directDependencies = module match {
33+
case jm: JavaModuleApi => jm.recursiveModuleDeps ++ jm.compileModuleDepsChecked
34+
case _ => Nil
35+
}
36+
val value = Seq(module) ++ directDependencies.flatMap(transitiveDependencyModules)
37+
transitiveDependencyModules0.putIfAbsent(module, value)
38+
}
3539

36-
(new BuildTargetIdentifier(uri), (m, eval))
37-
}
40+
transitiveDependencyModules0.get(module)
41+
}
42+
43+
private def transitiveModulesEnableBsp(module: ModuleApi): Option[Seq[BspModuleApi]] = {
44+
if (!transitiveModulesEnableBsp0.contains(module)) {
45+
val disabledTransitiveModules = transitiveDependencyModules(module).collect {
46+
case b: BspModuleApi if !b.enableBsp => b
3847
}
39-
regularModules
48+
val value =
49+
if (disabledTransitiveModules.isEmpty) None
50+
else Some(disabledTransitiveModules)
51+
transitiveModulesEnableBsp0.putIfAbsent(module, value)
52+
}
53+
54+
transitiveModulesEnableBsp0.get(module)
4055
}
4156

57+
private def moduleUri(rootModule: ModuleApi, module: ModuleApi) = Utils.sanitizeUri(
58+
(os.Path(rootModule.moduleDirJava) / module.moduleSegments.parts).toNIO
59+
)
60+
61+
lazy val bspModulesIdList0: Seq[(BuildTargetIdentifier, (BspModuleApi, EvaluatorApi))] =
62+
for {
63+
eval <- evaluators
64+
bspModule <- transitiveModules(eval.rootModule).collect { case m: BspModuleApi => m }
65+
uri = moduleUri(eval.rootModule, bspModule)
66+
if {
67+
if (bspModule.enableBsp)
68+
transitiveModulesEnableBsp(bspModule) match {
69+
case Some(disabledTransitiveModules) =>
70+
val uris = disabledTransitiveModules.map(moduleUri(eval.rootModule, _))
71+
eval.baseLogger.warn(
72+
s"BSP disabled for target $uri because of its dependencies ${uris.mkString(", ")}"
73+
)
74+
false
75+
case None =>
76+
true
77+
}
78+
else {
79+
eval.baseLogger.info(s"BSP disabled for target $uri via BspModuleApi#enableBsp")
80+
false
81+
}
82+
}
83+
} yield (new BuildTargetIdentifier(uri), (bspModule, eval))
84+
4285
val nonScriptSources = evaluators.flatMap { ev =>
4386
val bspSourceTasks: Seq[TaskApi[(sources: Seq[Path], generatedSources: Seq[Path])]] =
4487
transitiveModules(ev.rootModule)

0 commit comments

Comments
 (0)