Skip to content

Commit 56b33ee

Browse files
committed
sbt-dotty: don't pollute classpath with dotty-doc dependencies
This lead to runtime errors when running `scalatestTestDotty/test` in scalatest, because scalatest depends on a different version of flexmark. I'm not sure why these jars leaked into the runtime classpath (might be an sbt bug) but it seems better to limit the compiler classpath to the minimum needed anyway, so we now only add the dotty-doc dependencies when running the `doc` task.
1 parent 7dec935 commit 56b33ee

File tree

2 files changed

+57
-39
lines changed

2 files changed

+57
-39
lines changed

project/Build.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,9 @@ object Build {
294294
dottyCompiler,
295295
allJars
296296
)
297-
}
297+
},
298+
// sbt-dotty defines `scalaInstance in doc` so we need to override it manually
299+
scalaInstance in doc := scalaInstance.value,
298300
)
299301

300302
lazy val commonBenchmarkSettings = Seq(

sbt-dotty/src/dotty/tools/sbtplugin/DottyPlugin.scala

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dotty.tools.sbtplugin
22

33
import sbt._
4+
import sbt.Def.Initialize
45
import sbt.Keys._
56
import sbt.librarymanagement.{
67
ivy, DependencyResolution, ScalaModuleInfo, SemanticSelector, UpdateConfiguration, UnresolvedWarningConfiguration,
@@ -172,12 +173,13 @@ object DottyPlugin extends AutoPlugin {
172173
scalaCompilerBridgeBinaryJar := Def.settingDyn {
173174
if (isDotty.value) Def.task {
174175
val dottyBridgeArtifacts = fetchArtifactsOf(
176+
scalaOrganization.value % "dotty-sbt-bridge" % scalaVersion.value,
175177
dependencyResolution.value,
176178
scalaModuleInfo.value,
177179
updateConfiguration.value,
178180
(unresolvedWarningConfiguration in update).value,
179181
streams.value.log,
180-
scalaOrganization.value % "dotty-sbt-bridge" % scalaVersion.value).allFiles
182+
).allFiles
181183
val jars = dottyBridgeArtifacts.filter(art => art.getName.startsWith("dotty-sbt-bridge") && art.getName.endsWith(".jar")).toArray
182184
if (jars.size == 0)
183185
throw new MessageOnlyException("No jar found for dotty-sbt-bridge")
@@ -288,39 +290,7 @@ object DottyPlugin extends AutoPlugin {
288290
old
289291
},
290292
// ... instead, we'll fetch the compiler and its dependencies ourselves.
291-
scalaInstance := Def.taskDyn {
292-
if (isDotty.value) Def.task {
293-
val updateReport =
294-
fetchArtifactsOf(
295-
dependencyResolution.value,
296-
scalaModuleInfo.value,
297-
updateConfiguration.value,
298-
(unresolvedWarningConfiguration in update).value,
299-
streams.value.log,
300-
scalaOrganization.value %% "dotty-doc" % scalaVersion.value)
301-
val scalaLibraryJar = getJar(updateReport,
302-
"org.scala-lang", "scala-library", revision = AllPassFilter)
303-
val dottyLibraryJar = getJar(updateReport,
304-
scalaOrganization.value, s"dotty-library_${scalaBinaryVersion.value}", scalaVersion.value)
305-
val compilerJar = getJar(updateReport,
306-
scalaOrganization.value, s"dotty-compiler_${scalaBinaryVersion.value}", scalaVersion.value)
307-
val allJars =
308-
getJars(updateReport, AllPassFilter, AllPassFilter, AllPassFilter)
309-
310-
makeScalaInstance(
311-
state.value,
312-
scalaVersion.value,
313-
scalaLibraryJar,
314-
dottyLibraryJar,
315-
compilerJar,
316-
allJars
317-
)
318-
}
319-
else
320-
// This dereferences the Initialize graph, but keeps the Task unevaluated,
321-
// so its effect gets fired only when isDotty.value evaluates to false. yay monad.
322-
Def.valueStrict { scalaInstance.taskValue }
323-
}.value,
293+
scalaInstance := scalaInstanceTask("dotty-compiler").value,
324294

325295
// Because managedScalaInstance is false, sbt won't add the standard library to our dependencies for us
326296
libraryDependencies ++= {
@@ -344,6 +314,11 @@ object DottyPlugin extends AutoPlugin {
344314
}
345315

346316
private val docSettings = inTask(doc)(Seq(
317+
// Like scalaInstance in `projectSettings`, but with "dotty-compiler"
318+
// replaced by "dotty-doc" because we need more stuff on the classpath to
319+
// run the `doc` task.
320+
scalaInstance := scalaInstanceTask("dotty-doc").value,
321+
347322
sources := Def.taskDyn {
348323
val old = sources.value
349324

@@ -355,6 +330,7 @@ object DottyPlugin extends AutoPlugin {
355330
old
356331
}
357332
}.value,
333+
358334
scalacOptions ++= {
359335
if (isDotty.value) {
360336
val projectName =
@@ -369,17 +345,17 @@ object DottyPlugin extends AutoPlugin {
369345
}
370346
else
371347
Seq()
372-
}
348+
},
373349
))
374350

375351
/** Fetch artifacts for moduleID */
376352
def fetchArtifactsOf(
353+
moduleID: ModuleID,
377354
dependencyRes: DependencyResolution,
378355
scalaInfo: Option[ScalaModuleInfo],
379356
updateConfig: UpdateConfiguration,
380357
warningConfig: UnresolvedWarningConfiguration,
381-
log: Logger,
382-
moduleID: ModuleID): UpdateReport = {
358+
log: Logger): UpdateReport = {
383359
val descriptor = dependencyRes.wrapDependencyInModule(moduleID, scalaInfo)
384360

385361
dependencyRes.update(descriptor, updateConfig, warningConfig, log) match {
@@ -401,13 +377,53 @@ object DottyPlugin extends AutoPlugin {
401377
}
402378

403379
/** Get the single jar in updateReport that match the given filter.
404-
* If zero or more than one jar match, an exception will be thrown. */
380+
* If zero or more than one jar match, an exception will be thrown.
381+
*/
405382
def getJar(updateReport: UpdateReport, organization: NameFilter, name: NameFilter, revision: NameFilter): File = {
406383
val jars = getJars(updateReport, organization, name, revision)
407384
assert(jars.size == 1, s"There should only be one $name jar but found: $jars")
408385
jars.head
409386
}
410387

388+
/** If `isDotty` is true, create a scalaInstance task that uses Dotty based on
389+
* `moduleName`, otherwise return the default scalaInstance.
390+
*/
391+
def scalaInstanceTask(moduleName: String): Initialize[Task[ScalaInstance]] = Def.taskDyn {
392+
if (isDotty.value)
393+
dottyScalaInstanceTask(scalaOrganization.value %% moduleName % scalaVersion.value)
394+
else
395+
Def.valueStrict { scalaInstance.taskValue }
396+
}
397+
398+
/** Create a scalaInstance task that uses Dotty based on `moduleID`. */
399+
def dottyScalaInstanceTask(moduleID: ModuleID): Initialize[Task[ScalaInstance]] = Def.task {
400+
val updateReport =
401+
fetchArtifactsOf(
402+
moduleID,
403+
dependencyResolution.value,
404+
scalaModuleInfo.value,
405+
updateConfiguration.value,
406+
(unresolvedWarningConfiguration in update).value,
407+
streams.value.log)
408+
val scalaLibraryJar = getJar(updateReport,
409+
"org.scala-lang", "scala-library", revision = AllPassFilter)
410+
val dottyLibraryJar = getJar(updateReport,
411+
scalaOrganization.value, s"dotty-library_${scalaBinaryVersion.value}", scalaVersion.value)
412+
val compilerJar = getJar(updateReport,
413+
scalaOrganization.value, s"dotty-compiler_${scalaBinaryVersion.value}", scalaVersion.value)
414+
val allJars =
415+
getJars(updateReport, AllPassFilter, AllPassFilter, AllPassFilter)
416+
417+
makeScalaInstance(
418+
state.value,
419+
scalaVersion.value,
420+
scalaLibraryJar,
421+
dottyLibraryJar,
422+
compilerJar,
423+
allJars
424+
)
425+
}
426+
411427
def makeScalaInstance(
412428
state: State, dottyVersion: String, scalaLibrary: File, dottyLibrary: File, compiler: File, all: Seq[File]
413429
): ScalaInstance = {

0 commit comments

Comments
 (0)