sbt/build.sbt

1559 lines
67 KiB
Plaintext
Raw Normal View History

2014-12-18 13:57:05 +01:00
import Dependencies._
2019-12-08 00:39:30 +01:00
import Util._
import com.typesafe.tools.mima.core.ProblemFilters._
import com.typesafe.tools.mima.core._
2018-07-31 02:28:42 +02:00
import local.Scripted
import java.nio.file.{ Files, Path => JPath }
2019-12-08 00:39:30 +01:00
import scala.util.Try
2014-12-18 05:38:10 +01:00
2019-05-13 19:59:58 +02:00
ThisBuild / version := {
2020-11-19 00:47:33 +01:00
val v = "1.5.0-SNAPSHOT"
2019-05-13 19:59:58 +02:00
nightlyVersion.getOrElse(v)
}
2020-10-04 06:09:15 +02:00
ThisBuild / versionScheme := Some("early-semver")
ThisBuild / scalafmtOnCompile := !(Global / insideCI).value
ThisBuild / Test / scalafmtOnCompile := !(Global / insideCI).value
2019-08-31 22:37:01 +02:00
ThisBuild / turbo := true
ThisBuild / usePipelining := false // !(Global / insideCI).value
2019-05-13 19:59:58 +02:00
val excludeLint = SettingKey[Set[Def.KeyedInitialize[_]]]("excludeLintKeys")
Global / excludeLint := (Global / excludeLint).?.value.getOrElse(Set.empty)
Global / excludeLint += componentID
Global / excludeLint += whitesourceIgnoredScopes
Global / excludeLint += scriptedBufferLog
Global / excludeLint += checkPluginCross
2015-02-06 19:48:12 +01:00
// ThisBuild settings take lower precedence,
// but can be shared across the multi projects.
2017-04-21 09:14:31 +02:00
def buildLevelSettings: Seq[Setting[_]] =
inThisBuild(
Seq(
organization := "org.scala-sbt",
description := "sbt is an interactive build tool",
2020-11-15 07:12:02 +01:00
bintrayPackage := sys.env.get("BINTRAY_PACKAGE").getOrElse("sbt"),
2019-11-23 08:09:13 +01:00
licenses := List("Apache-2.0" -> url("https://github.com/sbt/sbt/blob/develop/LICENSE")),
javacOptions ++= Seq("-source", "1.8", "-target", "1.8"),
Compile / doc / javacOptions := Nil,
2017-04-21 09:14:31 +02:00
developers := List(
Developer("harrah", "Mark Harrah", "@harrah", url("https://github.com/harrah")),
Developer("eed3si9n", "Eugene Yokota", "@eed3si9n", url("https://github.com/eed3si9n")),
Developer("jsuereth", "Josh Suereth", "@jsuereth", url("https://github.com/jsuereth")),
Developer("dwijnand", "Dale Wijnand", "@dwijnand", url("https://github.com/dwijnand")),
2019-03-22 20:14:52 +01:00
Developer("eatkins", "Ethan Atkins", "@eatkins", url("https://github.com/eatkins")),
2018-01-26 15:19:14 +01:00
Developer(
"gkossakowski",
"Grzegorz Kossakowski",
"@gkossakowski",
url("https://github.com/gkossakowski")
),
2017-04-21 09:14:31 +02:00
Developer("Duhemm", "Martin Duhem", "@Duhemm", url("https://github.com/Duhemm"))
),
homepage := Some(url("https://github.com/sbt/sbt")),
scmInfo := Some(ScmInfo(url("https://github.com/sbt/sbt"), "git@github.com:sbt/sbt.git")),
2017-06-16 22:11:33 +02:00
resolvers += Resolver.mavenLocal,
2019-05-11 09:42:06 +02:00
)
)
2017-04-21 09:14:31 +02:00
def commonBaseSettings: Seq[Setting[_]] = Def.settings(
2019-05-11 09:42:06 +02:00
headerLicense := Some(
HeaderLicense.Custom(
"""|sbt
|Copyright 2011 - 2018, Lightbend, Inc.
2018-02-01 15:53:05 +01:00
|Copyright 2008 - 2010, Mark Harrah
|Licensed under Apache License 2.0 (see LICENSE)
2018-02-01 15:53:05 +01:00
|""".stripMargin
2019-05-11 09:42:06 +02:00
)
),
2018-02-01 15:53:05 +01:00
scalaVersion := baseScalaVersion,
componentID := None,
resolvers += Resolver.typesafeIvyRepo("releases").withName("typesafe-sbt-build-ivy-releases"),
2018-02-01 15:53:05 +01:00
resolvers += Resolver.sonatypeRepo("snapshots"),
resolvers += "bintray-sbt-maven-releases" at "https://dl.bintray.com/sbt/maven-releases/",
resolvers += Resolver.url(
"bintray-scala-hedgehog",
url("https://dl.bintray.com/hedgehogqa/scala-hedgehog")
)(Resolver.ivyStylePatterns),
testFrameworks += TestFramework("hedgehog.sbt.Framework"),
testFrameworks += TestFramework("verify.runner.Framework"),
2018-02-01 15:53:05 +01:00
concurrentRestrictions in Global += Util.testExclusiveRestriction,
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-w", "1"),
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-verbosity", "2"),
javacOptions in compile ++= Seq("-Xlint", "-Xlint:-serial"),
2019-03-22 07:28:14 +01:00
Compile / doc / scalacOptions ++= {
import scala.sys.process._
val devnull = ProcessLogger(_ => ())
val tagOrSha = ("git describe --exact-match" #|| "git rev-parse HEAD").lineStream(devnull).head
2018-02-22 02:33:45 +01:00
Seq(
"-sourcepath",
(baseDirectory in LocalRootProject).value.getAbsolutePath,
"-doc-source-url",
2019-03-22 07:28:14 +01:00
s"https://github.com/sbt/sbt/tree/$tagOrSha€{FILE_PATH}.scala"
2018-02-22 02:33:45 +01:00
)
},
Compile / javafmtOnCompile := Def
.taskDyn(if ((scalafmtOnCompile).value) Compile / javafmt else Def.task(()))
.value,
Test / javafmtOnCompile := Def
.taskDyn(if ((Test / scalafmtOnCompile).value) Test / javafmt else Def.task(()))
.value,
Compile / unmanagedSources / inputFileStamps :=
(Compile / unmanagedSources / inputFileStamps).dependsOn(Compile / javafmtOnCompile).value,
Test / unmanagedSources / inputFileStamps :=
(Test / unmanagedSources / inputFileStamps).dependsOn(Test / javafmtOnCompile).value,
2018-02-01 15:53:05 +01:00
crossScalaVersions := Seq(baseScalaVersion),
publishArtifact in Test := false,
fork in run := true,
2018-02-01 15:53:05 +01:00
)
def commonSettings: Seq[Setting[_]] =
commonBaseSettings :+
2020-07-08 01:52:52 +02:00
addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.11.0" cross CrossVersion.full)
def utilCommonSettings: Seq[Setting[_]] =
commonBaseSettings :+ (crossScalaVersions := (scala212 :: scala213 :: Nil))
2014-12-18 05:38:10 +01:00
def minimalSettings: Seq[Setting[_]] =
commonSettings ++ customCommands ++
2017-04-21 09:14:31 +02:00
publishPomSettings ++ Release.javaVersionCheckSettings
2014-12-18 05:38:10 +01:00
def baseSettings: Seq[Setting[_]] =
2017-04-20 01:56:35 +02:00
minimalSettings ++ Seq(projectComponent) ++ baseScalacOptions ++ Licensed.settings
2014-12-18 05:38:10 +01:00
def testedBaseSettings: Seq[Setting[_]] =
baseSettings ++ testDependencies
val sbt13Plus = Seq("1.3.0")
val sbt10Plus =
2019-05-11 09:42:06 +02:00
Seq(
"1.0.0",
"1.0.1",
"1.0.2",
"1.0.3",
"1.0.4",
"1.1.0",
"1.1.1",
"1.1.2",
"1.1.3",
"1.1.4",
"1.1.5",
"1.1.6",
"1.2.0",
"1.2.1",
/*DOA,*/ "1.2.3",
"1.2.4",
/*DOA,*/ "1.2.6",
2019-05-11 09:42:06 +02:00
"1.2.7",
"1.2.8",
) ++ sbt13Plus
val noUtilVersion =
Set("1.0.4", "1.1.4", "1.1.5", "1.1.6", "1.2.3", "1.2.4", "1.2.6", "1.2.7", "1.2.8")
2019-04-18 09:14:04 +02:00
val mimaSettings = mimaSettingsSince(sbt10Plus)
val utilMimaSettings = mimaSettingsSince(sbt10Plus.filterNot(noUtilVersion))
def mimaSettingsSince(versions: Seq[String]): Seq[Def.Setting[_]] = Def settings (
mimaPreviousArtifacts := {
2019-04-18 09:14:04 +02:00
val crossVersion = if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled
versions.map(v => organization.value % moduleName.value % v cross crossVersion).toSet
2018-03-12 18:21:22 +01:00
},
mimaBinaryIssueFilters ++= Seq(
// Changes in the internal package
2018-03-12 18:21:22 +01:00
exclude[DirectMissingMethodProblem]("sbt.internal.*"),
exclude[FinalClassProblem]("sbt.internal.*"),
exclude[FinalMethodProblem]("sbt.internal.*"),
exclude[IncompatibleResultTypeProblem]("sbt.internal.*"),
2018-10-02 16:51:20 +02:00
exclude[ReversedMissingMethodProblem]("sbt.internal.*")
2018-03-12 18:21:22 +01:00
),
2017-07-20 18:31:39 +02:00
)
val scriptedSbtReduxMimaSettings = Def.settings(mimaPreviousArtifacts := Set())
2017-04-21 09:14:31 +02:00
lazy val sbtRoot: Project = (project in file("."))
Upgrade the build to sbt 1.0.0-M5 Some plugins remain commented out, for now. sbt-doge is no longer needed because a variant of it has been folded into sbt 1. For some reason scripted requires src/doc jars of sbt, so switch back to using `publishAll` rather than `publishLocalBinAll`. :( Also, the sys.prop change in scripted is to force log4j2 to not use a thread context classloader, and avoid the following: ERROR StatusLogger Unable to create custom ContextSelector. Falling back to default. java.lang.ClassCastException: Cannot cast org.apache.logging.log4j.core.async.AsyncLoggerContextSelector to org.apache.logging.log4j.core.selector.ContextSelector at java.lang.Class.cast(Class.java:3369) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOf(LoaderUtil.java:201) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOfProperty(LoaderUtil.java:226) at org.apache.logging.log4j.core.impl.Log4jContextFactory.createContextSelector(Log4jContextFactory.java:97) at org.apache.logging.log4j.core.impl.Log4jContextFactory.<init>(Log4jContextFactory.java:58) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at java.lang.Class.newInstance(Class.java:442) at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:94) at org.apache.logging.log4j.spi.ThreadContextMapFactory.createThreadContextMap(ThreadContextMapFactory.java:73) at org.apache.logging.log4j.ThreadContext.init(ThreadContext.java:223) at org.apache.logging.log4j.ThreadContext.<clinit>(ThreadContext.java:202) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createDefaultInjector(ContextDataInjectorFactory.java:83) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector(ContextDataInjectorFactory.java:67) at org.apache.logging.log4j.core.lookup.ContextMapLookup.<init>(ContextMapLookup.java:34) at org.apache.logging.log4j.core.lookup.Interpolator.<init>(Interpolator.java:117) at org.apache.logging.log4j.core.config.AbstractConfiguration.<init>(AbstractConfiguration.java:125) at org.apache.logging.log4j.core.config.DefaultConfiguration.<init>(DefaultConfiguration.java:46) at org.apache.logging.log4j.core.layout.PatternLayout$Builder.build(PatternLayout.java:650) at org.apache.logging.log4j.core.layout.PatternLayout.createDefaultLayout(PatternLayout.java:487) at sbt.internal.util.ConsoleAppender.<init>(ConsoleAppender.scala:245) at sbt.internal.util.ConsoleAppender$.apply(ConsoleAppender.scala:196) at sbt.internal.util.ConsoleLogger.<init>(ConsoleAppender.scala:42) at sbt.internal.util.ConsoleLogger$.apply(ConsoleAppender.scala:34) at sbt.test.ScriptedRunner.run(ScriptedTests.scala:221) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at Scripted$.doScripted(Scripted.scala:125) at $0483e89d182e9d240274$.$anonfun$scriptedTask$5(build.sbt:301)
2017-05-03 16:52:36 +02:00
.enablePlugins(ScriptedPlugin) // , SiteScaladocPlugin, GhpagesPlugin)
2017-07-20 04:00:42 +02:00
.aggregate(nonRoots: _*)
2017-04-21 09:14:31 +02:00
.settings(
buildLevelSettings,
minimalSettings,
2018-10-05 09:04:22 +02:00
onLoadMessage := {
val version = sys.props("java.specification.version")
2018-10-05 09:04:22 +02:00
""" __ __
| _____/ /_ / /_
| / ___/ __ \/ __/
| (__ ) /_/ / /_
| /____/_.___/\__/
|Welcome to the build for sbt.
|""".stripMargin +
2019-05-11 09:42:06 +02:00
(if (version != "1.8")
s"""!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
| Java version is $version. We recommend java 8.
2018-10-05 09:04:22 +02:00
|!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!""".stripMargin
2019-05-11 09:42:06 +02:00
else "")
2018-10-05 09:04:22 +02:00
},
2017-05-08 15:34:41 +02:00
Util.baseScalacOptions,
Docs.settings,
scalacOptions += "-Ymacro-expand:none", // for both sxr and doc
Util.publishPomSettings,
otherRootSettings,
Transform.conscriptSettings(bundledLauncherProj),
publish := {},
2017-05-30 08:44:13 +02:00
publishLocal := {},
2017-11-29 22:45:02 +01:00
skip in publish := true,
2019-05-11 09:42:06 +02:00
commands in Global += Command
.single("sbtOn")((state, dir) => s"sbtProj/test:runMain sbt.RunFromSourceMain $dir" :: state),
2019-10-17 23:27:43 +02:00
mimaSettings,
2019-10-20 06:41:53 +02:00
mimaPreviousArtifacts := Set.empty,
buildThinClient := (sbtClientProj / buildThinClient).evaluated,
buildNativeThinClient := (sbtClientProj / buildNativeThinClient).value,
installNativeThinClient := {
// nativeInstallDirectory can be set globally or in a gitignored local file
val dir = nativeInstallDirectory.?.value
val target = Def.spaceDelimited("").parsed.headOption match {
case Some(p) => file(p).toPath
case _ =>
dir match {
2020-08-14 04:56:02 +02:00
case Some(d) => d / "sbtn"
case _ =>
val msg = "Expected input parameter <path>: installNativeExecutable /usr/local/bin"
throw new IllegalStateException(msg)
}
}
val base = baseDirectory.value.toPath
val exec = (sbtClientProj / buildNativeThinClient).value
streams.value.log.info(s"installing thin client ${base.relativize(exec)} to ${target}")
Files.copy(exec, target, java.nio.file.StandardCopyOption.REPLACE_EXISTING)
}
)
// This is used to configure an sbt-launcher for this version of sbt.
lazy val bundledLauncherProj =
2017-04-21 09:14:31 +02:00
(project in file("launch"))
.settings(
minimalSettings,
inConfig(Compile)(Transform.configSettings),
Release.launcherSettings(sbtLaunchJar)
)
.enablePlugins(SbtLauncherPlugin)
.settings(
name := "sbt-launch",
moduleName := "sbt-launch",
description := "sbt application launcher",
autoScalaLibrary := false,
crossPaths := false,
2017-07-20 18:31:39 +02:00
// mimaSettings, // TODO: Configure MiMa, deal with Proguard
2017-04-21 09:14:31 +02:00
publish := Release.deployLauncher.value,
publishLauncher := Release.deployLauncher.value,
2019-10-17 23:27:43 +02:00
packageBin in Compile := sbtLaunchJar.value,
mimaSettings,
mimaPreviousArtifacts := Set()
2017-04-21 09:14:31 +02:00
)
2014-12-18 05:38:10 +01:00
/* ** subproject declarations ** */
2014-12-18 05:38:10 +01:00
val collectionProj = (project in file("internal") / "util-collection")
.settings(
testedBaseSettings,
2020-07-08 01:52:52 +02:00
utilCommonSettings,
Util.keywordsSettings,
name := "Collections",
2017-07-20 18:31:39 +02:00
libraryDependencies ++= Seq(sjsonNewScalaJson.value),
2020-07-08 01:52:52 +02:00
libraryDependencies ++= (CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, major)) if major <= 12 => Seq()
case _ => Seq("org.scala-lang.modules" %% "scala-parallel-collections" % "0.2.0")
}),
2017-07-20 18:31:39 +02:00
mimaSettings,
2017-09-22 05:05:48 +02:00
mimaBinaryIssueFilters ++= Seq(
// Added private[sbt] method to capture State attributes.
exclude[ReversedMissingMethodProblem]("sbt.internal.util.AttributeMap.setCond"),
2017-10-19 02:10:29 +02:00
// Dropped in favour of kind-projector's inline type lambda syntax
exclude[MissingClassProblem]("sbt.internal.util.TypeFunctions$P1of2"),
2017-10-20 00:19:16 +02:00
// Dropped in favour of kind-projector's polymorphic lambda literals
exclude[MissingClassProblem]("sbt.internal.util.Param"),
exclude[MissingClassProblem]("sbt.internal.util.Param$"),
2017-10-20 05:18:43 +02:00
// Dropped in favour of plain scala.Function, and its compose method
exclude[MissingClassProblem]("sbt.internal.util.Fn1"),
exclude[DirectMissingMethodProblem]("sbt.internal.util.TypeFunctions.toFn1"),
exclude[DirectMissingMethodProblem]("sbt.internal.util.Types.toFn1"),
// Instead of defining foldr in KList & overriding in KCons,
// it's now abstract in KList and defined in both KCons & KNil.
exclude[FinalMethodProblem]("sbt.internal.util.KNil.foldr"),
exclude[DirectAbstractMethodProblem]("sbt.internal.util.KList.foldr"),
2019-10-17 23:27:43 +02:00
exclude[IncompatibleSignatureProblem]("sbt.internal.util.Init*.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.util.Settings0.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.util.EvaluateSettings#INode.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.util.TypeFunctions.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.util.EvaluateSettings.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.util.Settings.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.util.EvaluateSettings#MixedNode.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.util.EvaluateSettings#BindNode.this"),
exclude[IncompatibleSignatureProblem](
"sbt.internal.util.EvaluateSettings#BindNode.dependsOn"
),
2019-10-17 23:27:43 +02:00
exclude[IncompatibleSignatureProblem]("sbt.internal.util.Types.some")
2017-09-22 05:05:48 +02:00
),
)
.dependsOn(utilPosition)
// Command line-related utilities.
val completeProj = (project in file("internal") / "util-complete")
.dependsOn(collectionProj, utilControl, utilLogging)
.settings(
testedBaseSettings,
name := "Completion",
2017-07-20 18:31:39 +02:00
libraryDependencies += jline,
Support scala 2.13 console in thin client In order to make the console task work with scala 2.13 and the thin client, we need to provide a way for the scala repl to use an sbt provided jline3 terminal instead of the default terminal typically built by the repl. We also need to put jline 3 higher up in the classloading hierarchy to ensure that two versions of jline 3 are not loaded (which makes it impossible to share the sbt terminal with the scala terminal). One impact of this change is the decoupling of the version of jline-terminal used by the in process scala console and the version of jline-terminal specified by the scala version itself. It is possible to override this by setting the `useScalaReplJLine` flag to true. When that is set, the scala REPL will run in a fully isolated classloader. That will ensure that the versions are consistent. It will, however, for sure break the thin client and may interfere with the embedded shell ui. As part of this work, I also discovered that jline 3 Terminal.getSize is very slow. In jline 2, the terminal attributes were automatically cached with a timeout of, I think, 1 second so it wasn't a big deal to call Terminal.getAttributes. The getSize method in jline 3 is not cached and it shells out to run a tty command. This caused a significant performance regression in sbt because when progress is enabled, we call Terminal.getSize whenever we log any messages. I added caching of getSize at the TerminalImpl level to address this. The timeout is 1 second, which seems responsive enough for most use cases. We could also move the calculation onto a background thread and have it periodically updated, but that seems like overkill.
2020-07-20 19:12:04 +02:00
libraryDependencies += jline3Reader,
libraryDependencies += jline3Builtins,
2017-07-20 18:31:39 +02:00
mimaSettings,
// Parser is used publicly, so we can't break bincompat.
mimaBinaryIssueFilters := Seq(
2019-10-17 23:27:43 +02:00
exclude[DirectMissingMethodProblem]("sbt.internal.util.complete.SoftInvalid.apply"),
exclude[DirectMissingMethodProblem]("sbt.internal.util.complete.Invalid.apply"),
exclude[DirectMissingMethodProblem]("sbt.internal.util.complete.Finite.apply"),
exclude[DirectMissingMethodProblem]("sbt.internal.util.complete.Infinite.decrement"),
exclude[DirectMissingMethodProblem]("sbt.internal.util.complete.History.this"),
2019-10-17 23:27:43 +02:00
exclude[IncompatibleMethTypeProblem]("sbt.internal.util.complete.Completion.suggestion"),
exclude[IncompatibleMethTypeProblem]("sbt.internal.util.complete.Completion.token"),
2019-11-22 20:37:07 +01:00
exclude[IncompatibleMethTypeProblem]("sbt.internal.util.complete.Completion.displayOnly"),
exclude[IncompatibleSignatureProblem]("sbt.internal.util.complete.*"),
2017-12-04 17:18:08 +01:00
),
)
.configure(addSbtIO)
// A logic with restricted negation as failure for a unique, stable model
val logicProj = (project in file("internal") / "util-logic")
.dependsOn(collectionProj, utilRelation)
.settings(
testedBaseSettings,
2017-07-20 18:31:39 +02:00
name := "Logic",
mimaSettings,
)
// defines Java structures used across Scala versions, such as the API structures and relationships extracted by
// the analysis compiler phases and passed back to sbt. The API structures are defined in a simple
// format from which Java sources are generated by the datatype generator Projproject
lazy val utilInterface = (project in file("internal") / "util-interface").settings(
utilCommonSettings,
2020-11-15 00:58:25 +01:00
crossScalaVersions := List(scala212),
javaOnlySettings,
crossPaths := false,
name := "Util Interface",
exportJars := true,
utilMimaSettings,
)
lazy val utilControl = (project in file("internal") / "util-control").settings(
utilCommonSettings,
name := "Util Control",
utilMimaSettings,
)
lazy val utilPosition = (project in file("internal") / "util-position")
.settings(
utilCommonSettings,
name := "Util Position",
scalacOptions += "-language:experimental.macros",
libraryDependencies ++= Seq(scalaReflect.value, scalatest % "test"),
utilMimaSettings,
)
lazy val utilLogging = (project in file("internal") / "util-logging")
.enablePlugins(ContrabandPlugin, JsonCodecPlugin)
.dependsOn(utilInterface, collectionProj, coreMacrosProj)
.settings(
utilCommonSettings,
name := "Util Logging",
libraryDependencies ++=
Upgrade LineReader to JLine3 This commit upgrades sbt to using jline3. The advantage to jline3 is that it has a significantly better tab completion engine that is more similar to what you get from zsh or fish. The diff is bigger than I'd hoped because there are a number of behaviors that are different in jline3 vs jline2 in how the library consumes input streams and implements various features. I also was unable to remove jline2 because we need it for older versions of the scala console to work correctly with the thin client. As a result, the changes are largely additive. A good amount of this commit was in adding more protocol so that the remote client can forward its jline3 terminal information to the server. There were a number of minor changes that I made that either fixed outstanding ui bugs from #5620 or regressions due to differences between jline3 and jline2. The number one thing that caused problems is that the jline3 LineReader insists on using a NonBlockingInputStream. The implementation ofo NonBlockingInputStream seems buggy. Moreover, sbt internally uses a non blocking input stream for system in so jline is adding non blocking to an already non blocking stream, which is frustrating. A long term solution might be to consider insourcing LineReader.java from jline3 and just adapting it to use an sbt terminal rather than fighting with the jline3 api. This would also have the advantage of not conflicting with other versions of jline3. Even if we don't, we may want to shade jline3 if that is possible.
2020-06-30 17:57:57 +02:00
Seq(
jline,
Support scala 2.13 console in thin client In order to make the console task work with scala 2.13 and the thin client, we need to provide a way for the scala repl to use an sbt provided jline3 terminal instead of the default terminal typically built by the repl. We also need to put jline 3 higher up in the classloading hierarchy to ensure that two versions of jline 3 are not loaded (which makes it impossible to share the sbt terminal with the scala terminal). One impact of this change is the decoupling of the version of jline-terminal used by the in process scala console and the version of jline-terminal specified by the scala version itself. It is possible to override this by setting the `useScalaReplJLine` flag to true. When that is set, the scala REPL will run in a fully isolated classloader. That will ensure that the versions are consistent. It will, however, for sure break the thin client and may interfere with the embedded shell ui. As part of this work, I also discovered that jline 3 Terminal.getSize is very slow. In jline 2, the terminal attributes were automatically cached with a timeout of, I think, 1 second so it wasn't a big deal to call Terminal.getAttributes. The getSize method in jline 3 is not cached and it shells out to run a tty command. This caused a significant performance regression in sbt because when progress is enabled, we call Terminal.getSize whenever we log any messages. I added caching of getSize at the TerminalImpl level to address this. The timeout is 1 second, which seems responsive enough for most use cases. We could also move the calculation onto a background thread and have it periodically updated, but that seems like overkill.
2020-07-20 19:12:04 +02:00
jline3Terminal,
jline3JNA,
Support scala 2.13 console in thin client In order to make the console task work with scala 2.13 and the thin client, we need to provide a way for the scala repl to use an sbt provided jline3 terminal instead of the default terminal typically built by the repl. We also need to put jline 3 higher up in the classloading hierarchy to ensure that two versions of jline 3 are not loaded (which makes it impossible to share the sbt terminal with the scala terminal). One impact of this change is the decoupling of the version of jline-terminal used by the in process scala console and the version of jline-terminal specified by the scala version itself. It is possible to override this by setting the `useScalaReplJLine` flag to true. When that is set, the scala REPL will run in a fully isolated classloader. That will ensure that the versions are consistent. It will, however, for sure break the thin client and may interfere with the embedded shell ui. As part of this work, I also discovered that jline 3 Terminal.getSize is very slow. In jline 2, the terminal attributes were automatically cached with a timeout of, I think, 1 second so it wasn't a big deal to call Terminal.getAttributes. The getSize method in jline 3 is not cached and it shells out to run a tty command. This caused a significant performance regression in sbt because when progress is enabled, we call Terminal.getSize whenever we log any messages. I added caching of getSize at the TerminalImpl level to address this. The timeout is 1 second, which seems responsive enough for most use cases. We could also move the calculation onto a background thread and have it periodically updated, but that seems like overkill.
2020-07-20 19:12:04 +02:00
jline3Jansi,
Upgrade LineReader to JLine3 This commit upgrades sbt to using jline3. The advantage to jline3 is that it has a significantly better tab completion engine that is more similar to what you get from zsh or fish. The diff is bigger than I'd hoped because there are a number of behaviors that are different in jline3 vs jline2 in how the library consumes input streams and implements various features. I also was unable to remove jline2 because we need it for older versions of the scala console to work correctly with the thin client. As a result, the changes are largely additive. A good amount of this commit was in adding more protocol so that the remote client can forward its jline3 terminal information to the server. There were a number of minor changes that I made that either fixed outstanding ui bugs from #5620 or regressions due to differences between jline3 and jline2. The number one thing that caused problems is that the jline3 LineReader insists on using a NonBlockingInputStream. The implementation ofo NonBlockingInputStream seems buggy. Moreover, sbt internally uses a non blocking input stream for system in so jline is adding non blocking to an already non blocking stream, which is frustrating. A long term solution might be to consider insourcing LineReader.java from jline3 and just adapting it to use an sbt terminal rather than fighting with the jline3 api. This would also have the advantage of not conflicting with other versions of jline3. Even if we don't, we may want to shade jline3 if that is possible.
2020-06-30 17:57:57 +02:00
log4jApi,
log4jCore,
disruptor,
sjsonNewScalaJson.value,
scalaReflect.value
),
libraryDependencies ++= Seq(scalacheck % "test", scalatest % "test"),
libraryDependencies ++= (scalaVersion.value match {
case v if v.startsWith("2.12.") => List(compilerPlugin(silencerPlugin))
case _ => List()
}),
Compile / scalacOptions ++= (scalaVersion.value match {
case v if v.startsWith("2.12.") => List("-Ywarn-unused:-locals,-explicits,-privates")
case _ => List()
}),
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
managedSourceDirectories in Compile +=
baseDirectory.value / "src" / "main" / "contraband-scala",
contrabandFormatsForType in generateContrabands in Compile := { tpe =>
val old = (contrabandFormatsForType in generateContrabands in Compile).value
val name = tpe.removeTypeParameters.name
if (name == "Throwable") Nil
else old(tpe)
},
utilMimaSettings,
mimaBinaryIssueFilters ++= Seq(
exclude[DirectMissingMethodProblem]("sbt.internal.util.SuccessEvent.copy*"),
exclude[DirectMissingMethodProblem]("sbt.internal.util.TraceEvent.copy*"),
exclude[DirectMissingMethodProblem]("sbt.internal.util.StringEvent.copy*"),
// Private final class constructors changed
exclude[DirectMissingMethodProblem]("sbt.util.InterfaceUtil#ConcretePosition.this"),
exclude[DirectMissingMethodProblem]("sbt.util.InterfaceUtil#ConcreteProblem.this"),
exclude[ReversedMissingMethodProblem]("sbt.internal.util.ConsoleOut.flush"),
// This affects Scala 2.11 only it seems, so it's ok?
exclude[InheritedNewAbstractMethodProblem](
"sbt.internal.util.codec.JsonProtocol.LogOptionFormat"
),
exclude[InheritedNewAbstractMethodProblem](
"sbt.internal.util.codec.JsonProtocol.ProgressItemFormat"
),
exclude[InheritedNewAbstractMethodProblem](
"sbt.internal.util.codec.JsonProtocol.ProgressEventFormat"
),
Add internal multi logger implementation Prior to these changes, sbt was leaking large amounts of memory via log4j appenders. sbt has an unusual use case for log4j because it creates many ephemeral loggers while also having a global logger that is supposed to work for the duration of the sbt session. There is a lot of shared global state in log4j and properly cleaning up the ephemeral task appenders would break global logging. This commit fixes the behavior by introducing an alternate logging implementation. Users can still use the old log4j logging implementation but it will be off by default. The internal implementation is very simple: it just blocks the current thread and writes to all of the appenders. Nevertheless, I found the performance to be roughly identical to that of log4j in my sample project. As an experiment, I did the appending on a thread pool and got a significant performance improvement but I'll defer that to a later PR since parallel io is harder to reason about. Background: I was testing sbt performance in https://github.com/jtjeferreira/sbt-multi-module-sample and noticed that performance rapidly degraded after I ran compile a few times. I took a heap dump and it became obvious that sbt was leaking console appenders. Further investigation revealed that all of the leaking appenders in the project were coming from task streams. This made me think that the fix would be to track what loggers were created during task evaluation and clear them out when task evaluation completed. That almost worked except that log4j has an internal append only data structure containing logger names. Since we create unique logger names for each run, that internal data structure grew without bound. It looked like this could be worked around by creating a new log4j Configuration (where that data structure was stored) but while creating new configurations with each task runs did fix the leak, it also broke global logging, which was using a different configuration. At this point, I decided to write an alternate implementation of the appender api where I could be sure that the appenders were cleaned up without breaking global logging. Implementation: I made ConsoleAppender a trait and made it no longer extends log4j AbstractAppender. To do this, I had to remove the one log4j specific method, append(LogEvent). ConsoleAppender now has a method toLog4J that, in most cases, will return a log4j Appender that is almost identical to the Appenders that we previously used. To manage the loggers created during task evaluation, I introduce a new class, LoggerContext. The LoggerContext determines which logging backend to use and keeps track of what appenders and loggers have been created. We can create a fresh LoggerContext before each task evaluation and clear it out, cleaning up all of its resources after task evaluation concludes. In order to make this work, there were many places where we need to either pass in a LoggerContext or create a new one. The main magic is happening in the `next(State)` method in Main. This is where we create a new LoggerContext prior to command evaluation and clean it up after the evaluation completes. Users can toggle log4j using the new useLog4J key. They also can set the system property, sbt.log.uselog4j. The global logger will use the sbt internal implementation unless the system property is set. There are a fairly significant number of mima issues since I changed the type of ConsoleAppender. All of the mima changes were in the sbt.internal package so I think this should be ok. Effects: the memory leaks are gone. I successfully ran 5000 no-op compiles in the sbt-multi-module-sample above with no degradation of performace. There was a noticeable degradation after 30 no-op compiles before. During the refactor, I had to work on TestLogger and in doing so I also fixed https://github.com/sbt/sbt/issues/4480. This also should fix https://github.com/sbt/sbt/issues/4773
2020-08-05 20:23:35 +02:00
exclude[DirectMissingMethodProblem]("sbt.internal.util.MainAppender.*"),
exclude[IncompatibleMethTypeProblem]("sbt.internal.util.BufferedAppender.*"),
exclude[IncompatibleMethTypeProblem]("sbt.internal.util.ManagedLogger.this"),
exclude[IncompatibleMethTypeProblem]("sbt.internal.util.ManagedLogger.this"),
exclude[IncompatibleMethTypeProblem]("sbt.internal.util.MainAppender*"),
exclude[IncompatibleMethTypeProblem]("sbt.internal.util.GlobalLogging.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.util.GlobalLogging.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.util.MainAppender*"),
exclude[MissingTypesProblem]("sbt.internal.util.ConsoleAppender"),
exclude[MissingTypesProblem]("sbt.internal.util.BufferedAppender"),
),
)
.configure(addSbtIO)
lazy val utilRelation = (project in file("internal") / "util-relation")
.settings(
utilCommonSettings,
name := "Util Relation",
libraryDependencies ++= Seq(scalacheck % "test"),
utilMimaSettings,
)
// Persisted caching based on sjson-new
lazy val utilCache = (project in file("util-cache"))
.settings(
utilCommonSettings,
name := "Util Cache",
libraryDependencies ++=
Seq(sjsonNewScalaJson.value, sjsonNewMurmurhash.value, scalaReflect.value),
libraryDependencies ++= Seq(scalatest % "test"),
utilMimaSettings,
mimaBinaryIssueFilters ++= Seq(
// Added a method to a sealed trait, technically not a problem for Scala
exclude[ReversedMissingMethodProblem]("sbt.util.HashFileInfo.hashArray"),
)
)
.configure(addSbtIO)
// Builds on cache to provide caching for filesystem-related operations
lazy val utilTracking = (project in file("util-tracking"))
.dependsOn(utilCache)
.settings(
utilCommonSettings,
name := "Util Tracking",
libraryDependencies ++= Seq(scalatest % "test"),
utilMimaSettings,
mimaBinaryIssueFilters ++= Seq(
// Private final class constructors changed
ProblemFilters.exclude[IncompatibleMethTypeProblem]("sbt.util.Tracked#CacheHelp.this"),
)
)
.configure(addSbtIO)
lazy val utilScripted = (project in file("internal") / "util-scripted")
.dependsOn(utilLogging, utilInterface)
.settings(
utilCommonSettings,
name := "Util Scripted",
2020-01-10 14:41:55 +01:00
libraryDependencies += scalaParsers,
utilMimaSettings,
)
.configure(addSbtIO)
2014-12-18 05:38:10 +01:00
/* **** Intermediate-level Modules **** */
// Runner for uniform test interface
2017-04-21 09:14:31 +02:00
lazy val testingProj = (project in file("testing"))
.enablePlugins(ContrabandPlugin, JsonCodecPlugin)
.dependsOn(testAgentProj, utilLogging)
2017-04-21 09:14:31 +02:00
.settings(
baseSettings,
2014-12-18 05:38:10 +01:00
name := "Testing",
2020-01-10 14:41:55 +01:00
libraryDependencies ++= Seq(
scalaXml,
2019-05-11 09:42:06 +02:00
testInterface,
launcherInterface,
sjsonNewScalaJson.value
),
2018-09-18 17:47:55 +02:00
Compile / scalacOptions += "-Ywarn-unused:-locals,-explicits,-privates",
managedSourceDirectories in Compile +=
baseDirectory.value / "src" / "main" / "contraband-scala",
2017-04-01 23:19:45 +02:00
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
2017-07-20 18:31:39 +02:00
contrabandFormatsForType in generateContrabands in Compile := ContrabandConfig.getFormats,
mimaSettings,
2018-03-07 21:31:24 +01:00
mimaBinaryIssueFilters ++= Seq(
// private[sbt]
exclude[IncompatibleMethTypeProblem]("sbt.TestStatus.write"),
exclude[IncompatibleResultTypeProblem]("sbt.TestStatus.read"),
2018-03-12 16:18:42 +01:00
// copy method was never meant to be public
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.EndTestGroupErrorEvent.copy"),
2019-05-11 09:42:06 +02:00
exclude[DirectMissingMethodProblem](
"sbt.protocol.testing.EndTestGroupErrorEvent.copy$default$*"
),
2018-03-12 16:18:42 +01:00
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.EndTestGroupEvent.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.EndTestGroupEvent.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.StartTestGroupEvent.copy"),
2019-05-11 09:42:06 +02:00
exclude[DirectMissingMethodProblem](
"sbt.protocol.testing.StartTestGroupEvent.copy$default$*"
),
2018-03-12 16:18:42 +01:00
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestCompleteEvent.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestCompleteEvent.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestInitEvent.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestItemDetail.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestItemDetail.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestItemEvent.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestItemEvent.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestStringEvent.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestStringEvent.copy$default$1"),
//no reason to use
exclude[DirectMissingMethodProblem]("sbt.JUnitXmlTestsListener.testSuite"),
2018-03-12 16:18:42 +01:00
)
2017-04-21 09:14:31 +02:00
)
.configure(addSbtIO, addSbtCompilerClasspath)
2014-12-18 05:38:10 +01:00
// Testing agent for running tests in a separate process.
Replace previous scalafmt plugin by neo-scalafmt The previous scalafmt plugin had two problems: * Caching with Coursier did not work correctly * It failed after the upgrade to 1.0 in my computer (from a clean fork): ``` [error] (testingProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (runProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (taskProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (stdTaskProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (actionsProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (protocolProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (commandProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (mainSettingsProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (mainProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (sbtProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (scriptedPluginProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (scriptedSbtProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] Total time: 19 s, completed May 24, 2017 10:44:56 AM ``` This commit replaces the previous scalafmt integration by the one created by Lucidsoftware, big shoutout! (/cc @pauldraper) https://github.com/lucidsoftware/neo-sbt-scalafmt
2017-05-24 11:15:22 +02:00
lazy val testAgentProj = (project in file("testing") / "agent")
.settings(
minimalSettings,
crossScalaVersions := Seq(baseScalaVersion),
crossPaths := false,
autoScalaLibrary := false,
name := "Test Agent",
2017-07-20 18:31:39 +02:00
libraryDependencies += testInterface,
mimaSettings,
Replace previous scalafmt plugin by neo-scalafmt The previous scalafmt plugin had two problems: * Caching with Coursier did not work correctly * It failed after the upgrade to 1.0 in my computer (from a clean fork): ``` [error] (testingProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (runProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (taskProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (stdTaskProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (actionsProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (protocolProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (commandProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (mainSettingsProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (mainProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (sbtProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (scriptedPluginProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] (scriptedSbtProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$ [error] Total time: 19 s, completed May 24, 2017 10:44:56 AM ``` This commit replaces the previous scalafmt integration by the one created by Lucidsoftware, big shoutout! (/cc @pauldraper) https://github.com/lucidsoftware/neo-sbt-scalafmt
2017-05-24 11:15:22 +02:00
)
2014-12-18 05:38:10 +01:00
// Basic task engine
2017-04-21 09:14:31 +02:00
lazy val taskProj = (project in file("tasks"))
.dependsOn(collectionProj, utilControl)
2017-04-21 09:14:31 +02:00
.settings(
testedBaseSettings,
2017-07-20 18:31:39 +02:00
name := "Tasks",
mimaSettings,
2019-03-08 21:26:15 +01:00
mimaBinaryIssueFilters ++= Seq(
2019-10-17 23:27:43 +02:00
exclude[IncompatibleSignatureProblem]("sbt.Triggers.this"),
exclude[IncompatibleSignatureProblem]("sbt.Triggers.runBefore"),
exclude[IncompatibleSignatureProblem]("sbt.Triggers.injectFor"),
exclude[IncompatibleSignatureProblem]("sbt.Triggers.onComplete"),
exclude[DirectMissingMethodProblem]("sbt.Inc.apply"),
// ok because sbt.ExecuteProgress has been under private[sbt]
exclude[IncompatibleResultTypeProblem]("sbt.ExecuteProgress.initial"),
exclude[DirectMissingMethodProblem]("sbt.ExecuteProgress.*"),
exclude[ReversedMissingMethodProblem]("sbt.ExecuteProgress.*"),
2019-10-17 23:27:43 +02:00
exclude[IncompatibleSignatureProblem]("sbt.ExecuteProgress.*"),
// ok because sbt.Execute has been under private[sbt]
exclude[IncompatibleSignatureProblem]("sbt.Execute.*"),
exclude[IncompatibleSignatureProblem]("sbt.Execute#CyclicException.*"),
exclude[IncompatibleSignatureProblem]("sbt.NodeView.*"),
2019-03-08 21:26:15 +01:00
)
2017-04-21 09:14:31 +02:00
)
2014-12-18 05:38:10 +01:00
// Standard task system. This provides map, flatMap, join, and more on top of the basic task model.
2017-04-21 09:14:31 +02:00
lazy val stdTaskProj = (project in file("tasks-standard"))
.dependsOn(collectionProj, utilLogging, utilCache)
2017-04-21 09:14:31 +02:00
.dependsOn(taskProj % "compile;test->test")
.settings(
testedBaseSettings,
2014-12-18 05:38:10 +01:00
name := "Task System",
2017-07-20 18:31:39 +02:00
testExclusive,
mimaSettings,
2019-05-29 15:43:14 +02:00
mimaBinaryIssueFilters ++= Seq(
// unused private[sbt]
exclude[DirectMissingMethodProblem]("sbt.Task.mapTask"),
),
2017-04-21 09:14:31 +02:00
)
.configure(addSbtIO)
2014-12-18 05:38:10 +01:00
// Embedded Scala code runner
2017-04-21 09:14:31 +02:00
lazy val runProj = (project in file("run"))
2017-06-16 22:11:33 +02:00
.enablePlugins(ContrabandPlugin)
.dependsOn(collectionProj, utilLogging, utilControl)
2017-04-21 09:14:31 +02:00
.settings(
testedBaseSettings,
2017-05-12 00:33:12 +02:00
name := "Run",
2018-09-18 17:47:55 +02:00
Compile / scalacOptions += "-Ywarn-unused:-locals,-explicits,-privates",
2017-05-12 00:33:12 +02:00
managedSourceDirectories in Compile +=
baseDirectory.value / "src" / "main" / "contraband-scala",
2017-07-20 18:31:39 +02:00
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
mimaSettings,
2018-03-12 16:18:42 +01:00
mimaBinaryIssueFilters ++= Seq(
// copy method was never meant to be public
exclude[DirectMissingMethodProblem]("sbt.ForkOptions.copy"),
exclude[DirectMissingMethodProblem]("sbt.ForkOptions.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.OutputStrategy#BufferedOutput.copy"),
exclude[DirectMissingMethodProblem]("sbt.OutputStrategy#BufferedOutput.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.OutputStrategy#CustomOutput.copy"),
exclude[DirectMissingMethodProblem]("sbt.OutputStrategy#CustomOutput.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.OutputStrategy#LoggedOutput.copy"),
exclude[DirectMissingMethodProblem]("sbt.OutputStrategy#LoggedOutput.copy$default$*"),
)
2017-04-21 09:14:31 +02:00
)
.configure(addSbtIO, addSbtCompilerClasspath)
2014-12-18 05:38:10 +01:00
2018-02-01 15:53:11 +01:00
val sbtProjDepsCompileScopeFilter =
2019-05-11 09:42:06 +02:00
ScopeFilter(
inDependencies(LocalProject("sbtProj"), includeRoot = false),
inConfigurations(Compile)
)
2018-02-01 15:53:11 +01:00
lazy val scriptedSbtReduxProj = (project in file("scripted-sbt-redux"))
Explicitly set scripted and server test classpath This commit makes it so that the scalaVersion, sbtVersion and classpath are always passed in as parameters to any method that creates an sbt server -- either for scripted or for the sbt server tests. By making that change, I was able to change the implementation of scripted in the sbt project to use publishLocalBin instead of publishLocal. This makes the scripted tests start much faster (doc alone can easily take 30 second) with messing with the build to exclude slow tasks from publishLocal. As part of this change, I removed the test dependency on scriptedSbtRedux for sbtProj and instead had scriptedSbtRedux depend on sbtProj. This allowed me to remove some messy LocalProject logic in the resourceGenerators for scriptedSbtReduxProj. I also had to remove a number of imports in the scriptedSbtReduxProj because the definitions available in the sbt package object became available. I also removed the dependency on sbt-buildinfo and instead pass the values from the build into test classes using scalatest properties. I ran into a number of minor issues with the build info plugin, namely that I couldn't get fullClasspathAsJars to reliably run as a BuildInfo key. It also is somewhat more clear to me to just rely on the built in scalatest functionality. The big drawback is that the scalatest properties can only be strings, but that restriction isn't really a problem here (strangely the TestData structure has a field configMap which is effectively Map[String, Any] but Any is actually always String given how the TestData is created as part of framework initialization. Since scripted no longer publishes, scriptedUnpublished is now effectively an alias for scripted. To get publishLocalBin working, I had to copy private code from IvyXml.scala into PublishBinPlugin. Once we publish a new version of sbt, we can remove the copied code and invoke IvyXml.makeIvyXmlBefore directly.
2020-01-12 04:52:36 +01:00
.dependsOn(sbtProj % "compile;test->test", commandProj, utilLogging, utilScripted)
2017-04-21 09:14:31 +02:00
.settings(
baseSettings,
name := "Scripted sbt Redux",
2017-07-20 18:31:39 +02:00
libraryDependencies ++= Seq(launcherInterface % "provided"),
mimaSettings,
scriptedSbtReduxMimaSettings,
)
.configure(addSbtIO, addSbtCompilerInterface, addSbtLmCore)
lazy val scriptedSbtOldProj = (project in file("scripted-sbt-old"))
.dependsOn(scriptedSbtReduxProj)
.settings(
baseSettings,
name := "Scripted sbt",
mimaSettings,
mimaBinaryIssueFilters ++= Seq(
// sbt.test package is renamed to sbt.scriptedtest.
exclude[MissingClassProblem]("sbt.test.*"),
exclude[DirectMissingMethodProblem]("sbt.test.*"),
exclude[IncompatibleMethTypeProblem]("sbt.test.*"),
2019-10-17 23:27:43 +02:00
exclude[IncompatibleSignatureProblem]("sbt.test.*"),
),
2017-04-21 09:14:31 +02:00
)
2014-12-18 05:38:10 +01:00
lazy val scriptedPluginProj = (project in file("scripted-plugin"))
2017-04-21 09:14:31 +02:00
.settings(
baseSettings,
2017-07-20 18:31:39 +02:00
name := "Scripted Plugin",
mimaSettings,
mimaBinaryIssueFilters ++= Seq(
// scripted plugin has moved into sbt mothership.
exclude[MissingClassProblem]("sbt.ScriptedPlugin*")
),
2017-04-21 09:14:31 +02:00
)
2014-12-18 05:38:10 +01:00
lazy val dependencyTreeProj = (project in file("dependency-tree"))
.dependsOn(sbtProj)
.settings(
sbtPlugin := true,
baseSettings,
name := "sbt-dependency-tree",
publishMavenStyle := true,
// mimaSettings,
2020-09-23 03:47:38 +02:00
mimaPreviousArtifacts := Set.empty,
)
2014-12-18 05:38:10 +01:00
// Implementation and support code for defining actions.
2017-04-21 09:14:31 +02:00
lazy val actionsProj = (project in file("main-actions"))
.dependsOn(
completeProj,
runProj,
stdTaskProj,
taskProj,
testingProj,
utilLogging,
utilRelation,
utilTracking,
)
2017-04-21 09:14:31 +02:00
.settings(
testedBaseSettings,
name := "Actions",
2017-07-20 18:31:39 +02:00
libraryDependencies += sjsonNewScalaJson.value,
Support scala 2.13 console in thin client In order to make the console task work with scala 2.13 and the thin client, we need to provide a way for the scala repl to use an sbt provided jline3 terminal instead of the default terminal typically built by the repl. We also need to put jline 3 higher up in the classloading hierarchy to ensure that two versions of jline 3 are not loaded (which makes it impossible to share the sbt terminal with the scala terminal). One impact of this change is the decoupling of the version of jline-terminal used by the in process scala console and the version of jline-terminal specified by the scala version itself. It is possible to override this by setting the `useScalaReplJLine` flag to true. When that is set, the scala REPL will run in a fully isolated classloader. That will ensure that the versions are consistent. It will, however, for sure break the thin client and may interfere with the embedded shell ui. As part of this work, I also discovered that jline 3 Terminal.getSize is very slow. In jline 2, the terminal attributes were automatically cached with a timeout of, I think, 1 second so it wasn't a big deal to call Terminal.getAttributes. The getSize method in jline 3 is not cached and it shells out to run a tty command. This caused a significant performance regression in sbt because when progress is enabled, we call Terminal.getSize whenever we log any messages. I added caching of getSize at the TerminalImpl level to address this. The timeout is 1 second, which seems responsive enough for most use cases. We could also move the calculation onto a background thread and have it periodically updated, but that seems like overkill.
2020-07-20 19:12:04 +02:00
libraryDependencies += jline3Terminal,
2017-07-20 18:31:39 +02:00
mimaSettings,
2017-12-05 17:16:26 +01:00
mimaBinaryIssueFilters ++= Seq(
// Removed unused private[sbt] nested class
exclude[MissingClassProblem]("sbt.Doc$Scaladoc"),
// Removed no longer used private[sbt] method
exclude[DirectMissingMethodProblem]("sbt.Doc.generate"),
exclude[DirectMissingMethodProblem]("sbt.compiler.Eval.filesModifiedBytes"),
exclude[DirectMissingMethodProblem]("sbt.compiler.Eval.fileModifiedBytes"),
2017-12-05 17:16:26 +01:00
),
2017-04-21 09:14:31 +02:00
)
.configure(
addSbtIO,
addSbtCompilerInterface,
addSbtCompilerClasspath,
addSbtCompilerApiInfo,
2017-07-16 00:09:40 +02:00
addSbtLmCore,
addSbtZinc
2017-04-21 09:14:31 +02:00
)
lazy val protocolProj = (project in file("protocol"))
2017-06-16 22:11:33 +02:00
.enablePlugins(ContrabandPlugin, JsonCodecPlugin)
.dependsOn(collectionProj, utilLogging)
2017-04-21 09:14:31 +02:00
.settings(
2016-12-01 09:14:07 +01:00
testedBaseSettings,
name := "Protocol",
2018-01-30 06:43:30 +01:00
libraryDependencies ++= Seq(sjsonNewScalaJson.value, ipcSocket),
2018-09-18 17:47:55 +02:00
Compile / scalacOptions += "-Ywarn-unused:-locals,-explicits,-privates",
managedSourceDirectories in Compile +=
baseDirectory.value / "src" / "main" / "contraband-scala",
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
2017-07-20 18:31:39 +02:00
contrabandFormatsForType in generateContrabands in Compile := ContrabandConfig.getFormats,
mimaSettings,
2018-03-12 16:18:42 +01:00
mimaBinaryIssueFilters ++= Seq(
// copy method was never meant to be public
exclude[DirectMissingMethodProblem]("sbt.protocol.ChannelAcceptedEvent.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.ChannelAcceptedEvent.copy$default$1"),
exclude[DirectMissingMethodProblem]("sbt.protocol.ExecCommand.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.ExecCommand.copy$default$1"),
exclude[DirectMissingMethodProblem]("sbt.protocol.ExecCommand.copy$default$2"),
exclude[DirectMissingMethodProblem]("sbt.protocol.ExecStatusEvent.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.ExecStatusEvent.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.protocol.ExecutionEvent.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.ExecutionEvent.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.protocol.InitCommand.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.InitCommand.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.protocol.LogEvent.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.LogEvent.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.protocol.SettingQuery.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.SettingQuery.copy$default$1"),
exclude[DirectMissingMethodProblem]("sbt.protocol.SettingQueryFailure.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.SettingQueryFailure.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.protocol.SettingQuerySuccess.copy"),
exclude[DirectMissingMethodProblem]("sbt.protocol.SettingQuerySuccess.copy$default$*"),
2020-05-12 17:34:34 +02:00
// ignore missing or incompatible methods in sbt.internal
exclude[IncompatibleMethTypeProblem]("sbt.internal.*"),
2018-03-12 16:18:42 +01:00
exclude[DirectMissingMethodProblem]("sbt.internal.*"),
exclude[MissingTypesProblem]("sbt.internal.protocol.JsonRpcResponseError"),
2018-03-12 16:18:42 +01:00
)
2017-04-21 09:14:31 +02:00
)
2016-12-01 09:14:07 +01:00
2014-12-18 05:38:10 +01:00
// General command support and core commands not specific to a build system
2017-04-21 09:14:31 +02:00
lazy val commandProj = (project in file("main-command"))
2017-06-16 22:11:33 +02:00
.enablePlugins(ContrabandPlugin, JsonCodecPlugin)
.dependsOn(protocolProj, completeProj, utilLogging)
2017-04-21 09:14:31 +02:00
.settings(
testedBaseSettings,
name := "Command",
libraryDependencies ++= Seq(launcherInterface, sjsonNewScalaJson.value, templateResolverApi),
2020-01-08 15:41:29 +01:00
libraryDependencies ++= (scalaVersion.value match {
case v if v.startsWith("2.12.") => List(compilerPlugin(silencerPlugin))
case _ => List()
}),
2018-09-18 17:47:55 +02:00
Compile / scalacOptions += "-Ywarn-unused:-locals,-explicits,-privates",
managedSourceDirectories in Compile +=
baseDirectory.value / "src" / "main" / "contraband-scala",
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
2017-07-20 18:31:39 +02:00
contrabandFormatsForType in generateContrabands in Compile := ContrabandConfig.getFormats,
mimaSettings,
mimaBinaryIssueFilters ++= Vector(
2019-10-17 23:27:43 +02:00
exclude[DirectMissingMethodProblem]("sbt.Exit.apply"),
exclude[DirectMissingMethodProblem]("sbt.Reboot.apply"),
exclude[DirectMissingMethodProblem]("sbt.TemplateResolverInfo.apply"),
// dropped private[sbt] method
exclude[DirectMissingMethodProblem]("sbt.BasicCommands.compatCommands"),
// dropped mainly internal command strings holder
exclude[MissingClassProblem]("sbt.BasicCommandStrings$Compat$"),
exclude[DirectMissingMethodProblem]("sbt.BasicCommands.rebootOptionParser"),
// Changed the signature of Server method. nacho cheese.
2017-09-22 05:05:48 +02:00
exclude[DirectMissingMethodProblem]("sbt.internal.server.Server.*"),
// Added method to ServerInstance. This is also internal.
exclude[ReversedMissingMethodProblem]("sbt.internal.server.ServerInstance.*"),
2017-10-02 21:52:02 +02:00
// Added method to CommandChannel. internal.
exclude[ReversedMissingMethodProblem]("sbt.internal.CommandChannel.*"),
// Added an overload to reboot. The overload is private[sbt].
exclude[ReversedMissingMethodProblem]("sbt.StateOps.reboot"),
2018-01-30 06:43:30 +01:00
// Replace nailgun socket stuff
exclude[MissingClassProblem]("sbt.internal.NG*"),
exclude[MissingClassProblem]("sbt.internal.ReferenceCountedFileDescriptor"),
2018-03-12 18:13:17 +01:00
// made private[sbt] method private[this]
exclude[DirectMissingMethodProblem]("sbt.State.handleException"),
2018-03-12 16:18:42 +01:00
// copy method was never meant to be public
exclude[DirectMissingMethodProblem]("sbt.CommandSource.copy"),
exclude[DirectMissingMethodProblem]("sbt.CommandSource.copy$default$*"),
exclude[DirectMissingMethodProblem]("sbt.Exec.copy"),
exclude[DirectMissingMethodProblem]("sbt.Exec.copy$default$*"),
2018-06-26 04:34:55 +02:00
// internal
exclude[ReversedMissingMethodProblem]("sbt.internal.client.ServerConnection.*"),
2020-05-22 14:39:45 +02:00
exclude[MissingTypesProblem]("sbt.internal.server.ServerConnection*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.server.ServerConnection.*")
),
unmanagedSources in (Compile, headerCreate) := {
val old = (unmanagedSources in (Compile, headerCreate)).value
2019-05-11 09:42:06 +02:00
old filterNot { x =>
(x.getName startsWith "NG") || (x.getName == "ReferenceCountedFileDescriptor.java")
}
},
2017-04-21 09:14:31 +02:00
)
2017-06-23 18:58:00 +02:00
.configure(
addSbtIO,
addSbtCompilerInterface,
2017-06-23 18:58:00 +02:00
addSbtCompilerClasspath,
Add global file repository task Every time that the compile task is run, there are potentially a large number of iops that must occur in order for sbt to generate the source file list as well as for zinc to check which files have changed since the last build. This can lead to a noticeable delay between when a build is started (either manually or by triggered execution) and when compilation actually begins. To reduce this latency, I am adding a global view of the file system that will be stored in BasicKeys.globalFileTreeView. To make this work, I introduce the StampedFile trait, which augments the java.io.File class with a stamp method that returns the zinc stamp for the file. For source files, this will be a hash of the file, while for binaries, it is just the last modified time. In order to gain access to the sbt.internal.inc.Stamper class, I had to append addSbtZinc to the commandProj configurations. This view may or may not use an in-memory cache of the file system tree to return the results. Because there is always the risk of the cache getting out of sync with the actual file system, I both make it optional to use a cache and provide a mechanism for flushing the cache. Moreover, the in-memory cache implementation in sbt.io, which is backed by a swoval FileTreeRepository, has the property that touching a monitored directory invalidates the entire directory within the cache, so the flush command isn't even strictly needed in general. Because caching is optional, the global is of a FileTreeDataView, which doesn't specify a caching strategy. Subsequent commits will make use of this to potentially speed up incremental compilation by caching the Stamps of the source files so that zinc does not need to compute the hashes itself and will allow for continuous builds to use the cache to monitor events instead of creating a new, standalone FileEventMonitor.
2018-08-26 01:43:48 +02:00
addSbtLmCore,
addSbtZinc
2017-06-23 18:58:00 +02:00
)
2014-12-18 05:38:10 +01:00
// The core macro project defines the main logic of the DSL, abstracted
2019-07-28 05:49:24 +02:00
// away from several sbt implementors (tasks, settings, et cetera).
2017-05-23 23:53:04 +02:00
lazy val coreMacrosProj = (project in file("core-macros"))
.dependsOn(collectionProj)
2017-05-23 23:53:04 +02:00
.settings(
baseSettings :+ (crossScalaVersions := (scala212 :: scala213 :: Nil)),
name := "Core Macros",
2017-07-20 18:31:39 +02:00
libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value,
SettingKey[Boolean]("exportPipelining") := false,
2017-07-20 18:31:39 +02:00
mimaSettings,
)
2014-12-18 05:38:10 +01:00
// Fixes scope=Scope for Setting (core defined in collectionProj) to define the settings system used in build definitions
2017-04-21 09:14:31 +02:00
lazy val mainSettingsProj = (project in file("main-settings"))
.dependsOn(
completeProj,
commandProj,
stdTaskProj,
coreMacrosProj,
utilLogging,
utilCache,
utilRelation,
)
2017-04-21 09:14:31 +02:00
.settings(
testedBaseSettings,
name := "Main Settings",
Explicitly set scripted and server test classpath This commit makes it so that the scalaVersion, sbtVersion and classpath are always passed in as parameters to any method that creates an sbt server -- either for scripted or for the sbt server tests. By making that change, I was able to change the implementation of scripted in the sbt project to use publishLocalBin instead of publishLocal. This makes the scripted tests start much faster (doc alone can easily take 30 second) with messing with the build to exclude slow tasks from publishLocal. As part of this change, I removed the test dependency on scriptedSbtRedux for sbtProj and instead had scriptedSbtRedux depend on sbtProj. This allowed me to remove some messy LocalProject logic in the resourceGenerators for scriptedSbtReduxProj. I also had to remove a number of imports in the scriptedSbtReduxProj because the definitions available in the sbt package object became available. I also removed the dependency on sbt-buildinfo and instead pass the values from the build into test classes using scalatest properties. I ran into a number of minor issues with the build info plugin, namely that I couldn't get fullClasspathAsJars to reliably run as a BuildInfo key. It also is somewhat more clear to me to just rely on the built in scalatest functionality. The big drawback is that the scalatest properties can only be strings, but that restriction isn't really a problem here (strangely the TestData structure has a field configMap which is effectively Map[String, Any] but Any is actually always String given how the TestData is created as part of framework initialization. Since scripted no longer publishes, scriptedUnpublished is now effectively an alias for scripted. To get publishLocalBin working, I had to copy private code from IvyXml.scala into PublishBinPlugin. Once we publish a new version of sbt, we can remove the copied code and invoke IvyXml.makeIvyXmlBefore directly.
2020-01-12 04:52:36 +01:00
testOptions in Test ++= {
val cp = (Test / fullClasspathAsJars).value.map(_.data).mkString(java.io.File.pathSeparator)
val framework = TestFrameworks.ScalaTest
Tests.Argument(framework, s"-Dsbt.server.classpath=$cp") ::
Tests.Argument(framework, s"-Dsbt.server.version=${version.value}") ::
Tests.Argument(framework, s"-Dsbt.server.scala.version=${scalaVersion.value}") :: Nil
},
2017-07-20 18:31:39 +02:00
mimaSettings,
mimaBinaryIssueFilters ++= Seq(
2019-10-17 23:27:43 +02:00
exclude[IncompatibleSignatureProblem]("sbt.Previous#References.getReferences"),
exclude[IncompatibleSignatureProblem]("sbt.Def.delegate"),
exclude[IncompatibleSignatureProblem]("sbt.Def.add"),
exclude[IncompatibleSignatureProblem]("sbt.Def.grouped"),
exclude[IncompatibleSignatureProblem]("sbt.Def.compile"),
exclude[IncompatibleSignatureProblem]("sbt.Def.asTransform"),
exclude[DirectMissingMethodProblem]("sbt.Def.StaticScopes"),
exclude[IncompatibleSignatureProblem]("sbt.Previous.this"),
exclude[DirectMissingMethodProblem]("sbt.BuildRef.apply"),
exclude[DirectMissingMethodProblem]("sbt.ScopeMask.apply"),
exclude[DirectMissingMethodProblem]("sbt.Def.intersect"),
exclude[DirectMissingMethodProblem]("sbt.LocalProject.apply"),
exclude[DirectMissingMethodProblem]("sbt.std.InitializeInstance.pure"),
exclude[DirectMissingMethodProblem]("sbt.std.InitializeInstance.flatten"),
exclude[DirectMissingMethodProblem]("sbt.std.InitializeInstance.map"),
exclude[DirectMissingMethodProblem]("sbt.std.InitializeInstance.app"),
exclude[DirectMissingMethodProblem]("sbt.std.ParserInstance.pure"),
exclude[DirectMissingMethodProblem]("sbt.std.ParserInstance.map"),
exclude[DirectMissingMethodProblem]("sbt.std.ParserInstance.app"),
exclude[DirectMissingMethodProblem]("sbt.std.ParserInstance.pure"),
exclude[DirectMissingMethodProblem]("sbt.std.TaskInstance.pure"),
exclude[DirectMissingMethodProblem]("sbt.std.TaskInstance.flatten"),
exclude[DirectMissingMethodProblem]("sbt.std.TaskInstance.map"),
exclude[DirectMissingMethodProblem]("sbt.std.TaskInstance.app"),
exclude[DirectMissingMethodProblem]("sbt.std.FullInstance.flatten"),
exclude[DirectMissingMethodProblem]("sbt.Scope.display012StyleMasked"),
// added a method to a sealed trait
exclude[InheritedNewAbstractMethodProblem]("sbt.Scoped.canEqual"),
exclude[InheritedNewAbstractMethodProblem]("sbt.ScopedTaskable.canEqual"),
2020-02-16 20:51:53 +01:00
// widened ScopedTaskable parameter to (new) supertype Taskable
exclude[IncompatibleSignatureProblem]("sbt.Scoped#RichTaskable*.this"),
exclude[IncompatibleSignatureProblem]("sbt.TupleSyntax.t*ToTable*"),
),
2017-04-21 09:14:31 +02:00
)
.configure(
addSbtIO,
addSbtCompilerInterface,
2017-04-21 09:14:31 +02:00
addSbtCompilerClasspath,
2017-07-16 00:09:40 +02:00
addSbtLmCore
2017-04-21 09:14:31 +02:00
)
2014-12-18 05:38:10 +01:00
2019-04-18 09:14:04 +02:00
lazy val zincLmIntegrationProj = (project in file("zinc-lm-integration"))
.settings(
name := "Zinc LM Integration",
testedBaseSettings,
Explicitly set scripted and server test classpath This commit makes it so that the scalaVersion, sbtVersion and classpath are always passed in as parameters to any method that creates an sbt server -- either for scripted or for the sbt server tests. By making that change, I was able to change the implementation of scripted in the sbt project to use publishLocalBin instead of publishLocal. This makes the scripted tests start much faster (doc alone can easily take 30 second) with messing with the build to exclude slow tasks from publishLocal. As part of this change, I removed the test dependency on scriptedSbtRedux for sbtProj and instead had scriptedSbtRedux depend on sbtProj. This allowed me to remove some messy LocalProject logic in the resourceGenerators for scriptedSbtReduxProj. I also had to remove a number of imports in the scriptedSbtReduxProj because the definitions available in the sbt package object became available. I also removed the dependency on sbt-buildinfo and instead pass the values from the build into test classes using scalatest properties. I ran into a number of minor issues with the build info plugin, namely that I couldn't get fullClasspathAsJars to reliably run as a BuildInfo key. It also is somewhat more clear to me to just rely on the built in scalatest functionality. The big drawback is that the scalatest properties can only be strings, but that restriction isn't really a problem here (strangely the TestData structure has a field configMap which is effectively Map[String, Any] but Any is actually always String given how the TestData is created as part of framework initialization. Since scripted no longer publishes, scriptedUnpublished is now effectively an alias for scripted. To get publishLocalBin working, I had to copy private code from IvyXml.scala into PublishBinPlugin. Once we publish a new version of sbt, we can remove the copied code and invoke IvyXml.makeIvyXmlBefore directly.
2020-01-12 04:52:36 +01:00
testOptions in Test +=
Tests.Argument(TestFrameworks.ScalaTest, s"-Dsbt.zinc.version=$zincVersion"),
2019-04-18 09:14:04 +02:00
mimaSettingsSince(sbt13Plus),
2020-04-24 23:43:07 +02:00
mimaBinaryIssueFilters ++= Seq(
exclude[IncompatibleMethTypeProblem]("sbt.internal.inc.ZincComponentCompiler*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.inc.ZincComponentCompiler*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.inc.ZincLMHelper.update"),
),
libraryDependencies += launcherInterface,
2019-04-18 09:14:04 +02:00
)
.configure(addSbtZincCompileCore, addSbtLmCore, addSbtLmIvyTest)
2016-11-23 16:17:34 +01:00
// The main integration project for sbt. It brings all of the projects together, configures them, and provides for overriding conventions.
2017-04-21 09:14:31 +02:00
lazy val mainProj = (project in file("main"))
2017-06-16 22:11:33 +02:00
.enablePlugins(ContrabandPlugin)
2019-05-11 09:42:06 +02:00
.dependsOn(
logicProj,
actionsProj,
mainSettingsProj,
runProj,
commandProj,
collectionProj,
scriptedPluginProj,
zincLmIntegrationProj,
utilLogging,
2019-05-11 09:42:06 +02:00
)
2017-04-21 09:14:31 +02:00
.settings(
testedBaseSettings,
2014-12-18 05:38:10 +01:00
name := "Main",
2018-10-05 19:32:40 +02:00
checkPluginCross := {
val sv = scalaVersion.value
2020-01-10 14:41:55 +01:00
val f = baseDirectory.value / "src" / "main" / "scala" / "sbt" / "PluginCross.scala"
if (!IO.readLines(f).exists(_.contains(s""""$sv"""")))
sys.error(s"PluginCross.scala does not match up with the scalaVersion $sv")
},
2020-01-10 14:41:55 +01:00
libraryDependencies ++=
(Seq(scalaXml, launcherInterface, caffeine, lmCoursierShaded) ++ log4jModules),
2020-01-08 15:41:29 +01:00
libraryDependencies ++= (scalaVersion.value match {
case v if v.startsWith("2.12.") => List(compilerPlugin(silencerPlugin))
case _ => List()
}),
managedSourceDirectories in Compile +=
baseDirectory.value / "src" / "main" / "contraband-scala",
2017-07-20 18:31:39 +02:00
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
2019-05-11 09:41:41 +02:00
testOptions in Test += Tests
2019-05-11 10:52:42 +02:00
.Argument(TestFrameworks.ScalaCheck, "-minSuccessfulTests", "1000"),
SettingKey[Boolean]("usePipelining") := false,
2017-07-20 18:31:39 +02:00
mimaSettings,
2017-09-22 05:05:48 +02:00
mimaBinaryIssueFilters ++= Vector(
Unified slash syntax Fixes sbt/sbt#1812 This adds unified slash syntax for both sbt shell and the build.sbt DSL. Instead of the current `<project-id>/config:intask::key`, this adds `<project-id>/<config-ident>/intask/key` where <config-ident> is the Scala identifier notation for the configurations like `Compile` and `Test`. This also adds a series of implicits called `SlashSyntax` that adds `/` operators to project refererences, configuration, and keys such that the same syntax works in build.sbt. These examples work for both from the shell and in build.sbt. Global / cancelable ThisBuild / scalaVersion Test / test root / Compile / compile / scalacOptions ProjectRef(uri("file:/xxx/helloworld/"),"root")/Compile/scalacOptions Zero / Zero / name The inspect command now outputs something that can be copy-pasted: > inspect compile [info] Task: sbt.inc.Analysis [info] Description: [info] Compiles sources. [info] Provided by: [info] ProjectRef(uri("file:/xxx/helloworld/"),"root")/Compile/compile [info] Defined at: [info] (sbt.Defaults) Defaults.scala:326 [info] Dependencies: [info] Compile/manipulateBytecode [info] Compile/incCompileSetup [info] Reverse dependencies: [info] Compile/printWarnings [info] Compile/products [info] Compile/discoveredSbtPlugins [info] Compile/discoveredMainClasses [info] Delegates: [info] Compile/compile [info] compile [info] ThisBuild/Compile/compile [info] ThisBuild/compile [info] Zero/Compile/compile [info] Global/compile [info] Related: [info] Test/compile
2017-09-27 08:21:56 +02:00
// New and changed methods on KeyIndex. internal.
exclude[ReversedMissingMethodProblem]("sbt.internal.KeyIndex.*"),
2019-01-04 15:55:28 +01:00
// internal
2020-05-12 17:34:34 +02:00
exclude[IncompatibleMethTypeProblem]("sbt.internal.*"),
2017-12-14 14:41:40 +01:00
// Changed signature or removed private[sbt] methods
exclude[DirectMissingMethodProblem]("sbt.Classpaths.unmanagedLibs0"),
exclude[DirectMissingMethodProblem]("sbt.Defaults.allTestGroupsTask"),
exclude[DirectMissingMethodProblem]("sbt.Plugins.topologicalSort"),
exclude[IncompatibleMethTypeProblem]("sbt.Defaults.allTestGroupsTask"),
exclude[DirectMissingMethodProblem]("sbt.StandardMain.shutdownHook"),
exclude[DirectMissingMethodProblem]("sbt.nio.Keys.compileBinaryFileInputs"),
exclude[DirectMissingMethodProblem]("sbt.nio.Keys.compileSourceFileInputs"),
exclude[MissingClassProblem]("sbt.internal.ResourceLoaderImpl"),
2019-10-17 23:27:43 +02:00
exclude[IncompatibleSignatureProblem]("sbt.internal.ConfigIndex.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.Inspect.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.ProjectIndex.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.BuildIndex.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.server.BuildServerReporter.*"),
2019-10-17 23:27:43 +02:00
exclude[VirtualStaticMemberProblem]("sbt.internal.server.LanguageServerProtocol.*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.librarymanagement.IvyXml.*"),
exclude[IncompatibleSignatureProblem]("sbt.ScriptedPlugin.*Settings"),
exclude[IncompatibleSignatureProblem]("sbt.plugins.SbtPlugin.*Settings"),
// Removed private internal classes
exclude[MissingClassProblem]("sbt.internal.ReverseLookupClassLoaderHolder$BottomClassLoader"),
exclude[MissingClassProblem](
"sbt.internal.ReverseLookupClassLoaderHolder$ReverseLookupClassLoader$ResourceLoader"
),
exclude[MissingClassProblem]("sbt.internal.ReverseLookupClassLoaderHolder$ClassLoadingLock"),
exclude[MissingClassProblem](
"sbt.internal.ReverseLookupClassLoaderHolder$ReverseLookupClassLoader"
),
exclude[MissingClassProblem]("sbt.internal.LayeredClassLoaderImpl"),
2020-05-05 23:39:22 +02:00
exclude[MissingClassProblem]("sbt.internal.FileManagement"),
exclude[MissingClassProblem]("sbt.internal.FileManagement$"),
exclude[MissingClassProblem]("sbt.internal.FileManagement$CopiedFileTreeRepository"),
2020-05-22 14:39:45 +02:00
exclude[MissingClassProblem]("sbt.internal.server.LanguageServerReporter*"),
exclude[MissingClassProblem]("sbt.internal.ExternalHooks"),
exclude[MissingClassProblem]("sbt.internal.ExternalHooks$"),
2019-10-17 23:27:43 +02:00
// false positives
exclude[DirectMissingMethodProblem]("sbt.plugins.IvyPlugin.requires"),
exclude[DirectMissingMethodProblem]("sbt.plugins.JUnitXmlReportPlugin.requires"),
exclude[DirectMissingMethodProblem]("sbt.plugins.Giter8TemplatePlugin.requires"),
exclude[DirectMissingMethodProblem]("sbt.plugins.JvmPlugin.requires"),
exclude[DirectMissingMethodProblem]("sbt.plugins.SbtPlugin.requires"),
exclude[DirectMissingMethodProblem]("sbt.ResolvedClasspathDependency.apply"),
exclude[DirectMissingMethodProblem]("sbt.ClasspathDependency.apply"),
2019-10-18 19:39:39 +02:00
exclude[IncompatibleSignatureProblem]("sbt.plugins.SemanticdbPlugin.globalSettings"),
2019-10-17 23:27:43 +02:00
// File -> Source
exclude[DirectMissingMethodProblem]("sbt.Defaults.cleanFilesTask"),
exclude[IncompatibleSignatureProblem]("sbt.Defaults.resourceConfigPaths"),
exclude[IncompatibleSignatureProblem]("sbt.Defaults.sourceConfigPaths"),
exclude[IncompatibleSignatureProblem]("sbt.Defaults.configPaths"),
exclude[IncompatibleSignatureProblem]("sbt.Defaults.paths"),
exclude[IncompatibleSignatureProblem]("sbt.Keys.csrPublications"),
exclude[IncompatibleSignatureProblem](
"sbt.coursierint.CoursierArtifactsTasks.coursierPublicationsTask"
),
exclude[IncompatibleSignatureProblem](
"sbt.coursierint.CoursierArtifactsTasks.coursierPublicationsTask"
),
2019-10-17 23:27:43 +02:00
exclude[IncompatibleSignatureProblem]("sbt.coursierint.LMCoursier.coursierConfiguration"),
exclude[IncompatibleSignatureProblem]("sbt.coursierint.LMCoursier.publicationsSetting"),
exclude[IncompatibleSignatureProblem]("sbt.Project.inThisBuild"),
exclude[IncompatibleSignatureProblem]("sbt.Project.inConfig"),
exclude[IncompatibleSignatureProblem]("sbt.Project.inTask"),
exclude[IncompatibleSignatureProblem]("sbt.Project.inScope"),
exclude[IncompatibleSignatureProblem]("sbt.ProjectExtra.inThisBuild"),
exclude[IncompatibleSignatureProblem]("sbt.ProjectExtra.inConfig"),
exclude[IncompatibleSignatureProblem]("sbt.ProjectExtra.inTask"),
exclude[IncompatibleSignatureProblem]("sbt.ProjectExtra.inScope"),
exclude[MissingTypesProblem]("sbt.internal.Load*"),
exclude[IncompatibleSignatureProblem]("sbt.internal.Load*"),
2020-05-22 14:39:45 +02:00
exclude[MissingTypesProblem]("sbt.internal.server.NetworkChannel"),
// IvyConfiguration was replaced by InlineIvyConfiguration in the generic
// signature, this does not break compatibility regardless of what
// cast a compiler might have inserted based on the old signature
// since we're returning the same values as before.
2020-04-24 23:43:07 +02:00
exclude[IncompatibleSignatureProblem]("sbt.Classpaths.mkIvyConfiguration"),
exclude[IncompatibleMethTypeProblem]("sbt.internal.server.Definition*"),
exclude[IncompatibleTemplateDefProblem]("sbt.internal.server.LanguageServerProtocol"),
exclude[DirectMissingMethodProblem]("sbt.Classpaths.warnInsecureProtocol"),
exclude[DirectMissingMethodProblem]("sbt.Classpaths.warnInsecureProtocolInModules"),
2020-06-14 21:55:37 +02:00
exclude[MissingClassProblem]("sbt.internal.ExternalHooks*"),
// This seems to be a mima problem. The older constructor still exists but
// mima seems to incorrectly miss the secondary constructor that provides
// the binary compatible version.
exclude[IncompatibleMethTypeProblem]("sbt.internal.server.NetworkChannel.this"),
Refactor watch The existing implementation of watch did not work with the thin client. In sbt 1.3.0, watch was changed to be a blocking command that performed manual task evaluation. This commit makes the implementation more similar to < 1.3.0 where watch modifies the state and after running the user specified command(s), it enters a blocking command. The new blocking command is very similar to the shell command. As part of this change, I also reworked some of the internals of watch so that a number of threads are spawned for reading file and input events. By using background threads that write to a single event queue, we are able to block on the file events and terminal input stream rather than polling. After this change, the cpu utilization as measured by ps drops from roughly 2% of a cpu to 0. To integrate with the network client, we introduce a new UITask that is similar to the AskUserTask but instead of reading lines and adding execs to the command queue, it reads characters and converts them into watch commands that we also append to the command queue. With this new implementation, the watch task that was added in 1.3.0 no longer works. My guess is that no one was really using it. It wasn't documented anywhere. The motivation for the task implementation was that it could be called within another task which would let users define a task that monitors for file changes before running. Since this had never been advertised and is only of limited utility anyway, I think it's fine to break it. I also had to disable the input-parser and symlinks tests. I'm not 100% sure why the symlinks test was failing. It would tend to work on my machine but fail in CI. I gave up on debugging it. The input-parser test also fails but would be a good candidate to be moved to the client test in the serverTestProj. At any rate, it was testing a code path that was only exercised if the user changed the watchInputStream method which is highly unlikely to have been done in any user builds. The WatchSpec had become a nuisance and wasn't really preventing from any regressions so I removed it. The scripted tests are how we test watch.
2020-06-22 02:10:20 +02:00
exclude[IncompatibleSignatureProblem]("sbt.internal.DeprecatedContinuous.taskDefinitions"),
exclude[MissingClassProblem]("sbt.internal.SettingsGraph*"),
// Tasks include non-Files, but it's ok
exclude[IncompatibleSignatureProblem]("sbt.Defaults.outputConfigPaths"),
// private[sbt]
exclude[DirectMissingMethodProblem]("sbt.Classpaths.trackedExportedProducts"),
exclude[DirectMissingMethodProblem]("sbt.Classpaths.trackedExportedJarProducts"),
exclude[DirectMissingMethodProblem]("sbt.Classpaths.unmanagedDependencies0"),
exclude[DirectMissingMethodProblem]("sbt.Classpaths.internalDependenciesImplTask"),
exclude[DirectMissingMethodProblem]("sbt.Classpaths.internalDependencyJarsImplTask"),
exclude[DirectMissingMethodProblem]("sbt.Classpaths.interDependencies"),
exclude[DirectMissingMethodProblem]("sbt.Classpaths.productsTask"),
exclude[DirectMissingMethodProblem]("sbt.Classpaths.jarProductsTask"),
exclude[DirectMissingMethodProblem]("sbt.StandardMain.cache"),
Add internal multi logger implementation Prior to these changes, sbt was leaking large amounts of memory via log4j appenders. sbt has an unusual use case for log4j because it creates many ephemeral loggers while also having a global logger that is supposed to work for the duration of the sbt session. There is a lot of shared global state in log4j and properly cleaning up the ephemeral task appenders would break global logging. This commit fixes the behavior by introducing an alternate logging implementation. Users can still use the old log4j logging implementation but it will be off by default. The internal implementation is very simple: it just blocks the current thread and writes to all of the appenders. Nevertheless, I found the performance to be roughly identical to that of log4j in my sample project. As an experiment, I did the appending on a thread pool and got a significant performance improvement but I'll defer that to a later PR since parallel io is harder to reason about. Background: I was testing sbt performance in https://github.com/jtjeferreira/sbt-multi-module-sample and noticed that performance rapidly degraded after I ran compile a few times. I took a heap dump and it became obvious that sbt was leaking console appenders. Further investigation revealed that all of the leaking appenders in the project were coming from task streams. This made me think that the fix would be to track what loggers were created during task evaluation and clear them out when task evaluation completed. That almost worked except that log4j has an internal append only data structure containing logger names. Since we create unique logger names for each run, that internal data structure grew without bound. It looked like this could be worked around by creating a new log4j Configuration (where that data structure was stored) but while creating new configurations with each task runs did fix the leak, it also broke global logging, which was using a different configuration. At this point, I decided to write an alternate implementation of the appender api where I could be sure that the appenders were cleaned up without breaking global logging. Implementation: I made ConsoleAppender a trait and made it no longer extends log4j AbstractAppender. To do this, I had to remove the one log4j specific method, append(LogEvent). ConsoleAppender now has a method toLog4J that, in most cases, will return a log4j Appender that is almost identical to the Appenders that we previously used. To manage the loggers created during task evaluation, I introduce a new class, LoggerContext. The LoggerContext determines which logging backend to use and keeps track of what appenders and loggers have been created. We can create a fresh LoggerContext before each task evaluation and clear it out, cleaning up all of its resources after task evaluation concludes. In order to make this work, there were many places where we need to either pass in a LoggerContext or create a new one. The main magic is happening in the `next(State)` method in Main. This is where we create a new LoggerContext prior to command evaluation and clean it up after the evaluation completes. Users can toggle log4j using the new useLog4J key. They also can set the system property, sbt.log.uselog4j. The global logger will use the sbt internal implementation unless the system property is set. There are a fairly significant number of mima issues since I changed the type of ConsoleAppender. All of the mima changes were in the sbt.internal package so I think this should be ok. Effects: the memory leaks are gone. I successfully ran 5000 no-op compiles in the sbt-multi-module-sample above with no degradation of performace. There was a noticeable degradation after 30 no-op compiles before. During the refactor, I had to work on TestLogger and in doing so I also fixed https://github.com/sbt/sbt/issues/4480. This also should fix https://github.com/sbt/sbt/issues/4773
2020-08-05 20:23:35 +02:00
// internal logging apis,
exclude[IncompatibleSignatureProblem]("sbt.internal.LogManager*"),
exclude[MissingTypesProblem]("sbt.internal.RelayAppender"),
exclude[MissingClassProblem]("sbt.internal.TaskProgress$ProgressThread"),
// internal implementation
exclude[MissingClassProblem](
"sbt.internal.XMainConfiguration$ModifiedConfiguration$ModifiedAppProvider$ModifiedScalaProvider$"
),
2017-09-22 05:05:48 +02:00
)
2017-04-21 09:14:31 +02:00
)
2017-06-23 18:58:00 +02:00
.configure(
addSbtIO,
2017-07-16 00:09:40 +02:00
addSbtLmCore,
2019-10-16 20:27:32 +02:00
addSbtLmIvy,
addSbtCompilerInterface,
addSbtZincCompile
)
2014-12-18 05:38:10 +01:00
// Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object
// technically, we need a dependency on all of mainProj's dependencies, but we don't do that since this is strictly an integration project
// with the sole purpose of providing certain identifiers without qualification (with a package object)
2017-04-21 09:14:31 +02:00
lazy val sbtProj = (project in file("sbt"))
Explicitly set scripted and server test classpath This commit makes it so that the scalaVersion, sbtVersion and classpath are always passed in as parameters to any method that creates an sbt server -- either for scripted or for the sbt server tests. By making that change, I was able to change the implementation of scripted in the sbt project to use publishLocalBin instead of publishLocal. This makes the scripted tests start much faster (doc alone can easily take 30 second) with messing with the build to exclude slow tasks from publishLocal. As part of this change, I removed the test dependency on scriptedSbtRedux for sbtProj and instead had scriptedSbtRedux depend on sbtProj. This allowed me to remove some messy LocalProject logic in the resourceGenerators for scriptedSbtReduxProj. I also had to remove a number of imports in the scriptedSbtReduxProj because the definitions available in the sbt package object became available. I also removed the dependency on sbt-buildinfo and instead pass the values from the build into test classes using scalatest properties. I ran into a number of minor issues with the build info plugin, namely that I couldn't get fullClasspathAsJars to reliably run as a BuildInfo key. It also is somewhat more clear to me to just rely on the built in scalatest functionality. The big drawback is that the scalatest properties can only be strings, but that restriction isn't really a problem here (strangely the TestData structure has a field configMap which is effectively Map[String, Any] but Any is actually always String given how the TestData is created as part of framework initialization. Since scripted no longer publishes, scriptedUnpublished is now effectively an alias for scripted. To get publishLocalBin working, I had to copy private code from IvyXml.scala into PublishBinPlugin. Once we publish a new version of sbt, we can remove the copied code and invoke IvyXml.makeIvyXmlBefore directly.
2020-01-12 04:52:36 +01:00
.dependsOn(mainProj)
2017-04-21 09:14:31 +02:00
.settings(
testedBaseSettings,
2014-12-18 05:38:10 +01:00
name := "sbt",
2015-09-14 09:27:22 +02:00
normalizedName := "sbt",
crossScalaVersions := Seq(baseScalaVersion),
2017-07-20 18:31:39 +02:00
crossPaths := false,
javaOptions ++= Seq("-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"),
2017-07-20 18:31:39 +02:00
mimaSettings,
mimaBinaryIssueFilters ++= sbtIgnoredProblems,
)
2020-02-14 15:01:11 +01:00
.settings(
Test / run / connectInput := true,
Test / run / outputStrategy := Some(StdoutOutput),
Test / run / fork := true,
testOptions in Test ++= {
val cp = (Test / fullClasspathAsJars).value.map(_.data).mkString(java.io.File.pathSeparator)
val framework = TestFrameworks.ScalaTest
Tests.Argument(framework, s"-Dsbt.server.classpath=$cp") ::
Tests.Argument(framework, s"-Dsbt.server.version=${version.value}") ::
Tests.Argument(framework, s"-Dsbt.server.scala.version=${scalaVersion.value}") :: Nil
},
)
.configure(addSbtIO, addSbtCompilerBridge)
lazy val serverTestProj = (project in file("server-test"))
.dependsOn(sbtProj % "compile->test", scriptedSbtReduxProj % "compile->test")
.settings(
testedBaseSettings,
crossScalaVersions := Seq(baseScalaVersion),
publish / skip := true,
// make server tests serial
Test / watchTriggers += baseDirectory.value.toGlob / "src" / "server-test" / **,
Test / parallelExecution := false,
2018-03-26 16:37:25 +02:00
Test / run / connectInput := true,
Test / run / outputStrategy := Some(StdoutOutput),
Test / run / fork := true,
Test / sourceGenerators += Def.task {
val rawClasspath =
(Compile / fullClasspathAsJars).value.map(_.data).mkString(java.io.File.pathSeparator)
val cp =
if (scala.util.Properties.isWin) rawClasspath.replaceAllLiterally("\\", "\\\\")
else rawClasspath
val content = {
s"""|
|package testpkg
|
|object TestProperties {
| val classpath = "$cp"
| val version = "${version.value}"
| val scalaVersion = "${scalaVersion.value}"
|}
""".stripMargin
}
val file = (Test / target).value / "generated" / "src" / "test" / "scala" / "testpkg" / "TestProperties.scala"
IO.write(file, content)
file :: Nil
Explicitly set scripted and server test classpath This commit makes it so that the scalaVersion, sbtVersion and classpath are always passed in as parameters to any method that creates an sbt server -- either for scripted or for the sbt server tests. By making that change, I was able to change the implementation of scripted in the sbt project to use publishLocalBin instead of publishLocal. This makes the scripted tests start much faster (doc alone can easily take 30 second) with messing with the build to exclude slow tasks from publishLocal. As part of this change, I removed the test dependency on scriptedSbtRedux for sbtProj and instead had scriptedSbtRedux depend on sbtProj. This allowed me to remove some messy LocalProject logic in the resourceGenerators for scriptedSbtReduxProj. I also had to remove a number of imports in the scriptedSbtReduxProj because the definitions available in the sbt package object became available. I also removed the dependency on sbt-buildinfo and instead pass the values from the build into test classes using scalatest properties. I ran into a number of minor issues with the build info plugin, namely that I couldn't get fullClasspathAsJars to reliably run as a BuildInfo key. It also is somewhat more clear to me to just rely on the built in scalatest functionality. The big drawback is that the scalatest properties can only be strings, but that restriction isn't really a problem here (strangely the TestData structure has a field configMap which is effectively Map[String, Any] but Any is actually always String given how the TestData is created as part of framework initialization. Since scripted no longer publishes, scriptedUnpublished is now effectively an alias for scripted. To get publishLocalBin working, I had to copy private code from IvyXml.scala into PublishBinPlugin. Once we publish a new version of sbt, we can remove the copied code and invoke IvyXml.makeIvyXmlBefore directly.
2020-01-12 04:52:36 +01:00
},
2017-04-21 09:14:31 +02:00
)
2017-10-20 05:18:43 +02:00
val isWin = scala.util.Properties.isWin
val buildThinClient =
inputKey[JPath]("generate a java implementation of the thin client")
val thinClientClasspath =
taskKey[Seq[JPath]]("Generate the classpath for thin client (compacted for windows)")
val thinClientNativeImageCommand = taskKey[String]("The native image command")
val thinClientNativeImageOptions = settingKey[Seq[String]]("The native image options")
val thinClientNativeImageClass = settingKey[String]("The class for the native image")
val buildNativeThinClient = taskKey[JPath]("Generate a native executable")
// Use a TaskKey rather than SettingKey for nativeInstallDirectory so it can left unset by default
val nativeInstallDirectory = taskKey[JPath]("The install directory for the native executable")
val installNativeThinClient = inputKey[JPath]("Install the native executable")
val nativeThinClientPath = settingKey[JPath]("The location of the native executable")
lazy val sbtClientProj = (project in file("client"))
.dependsOn(commandProj)
.settings(
commonBaseSettings,
scalaVersion := "2.12.11", // The thin client does not build with 2.12.12
publish / skip := true,
name := "sbt-client",
mimaPreviousArtifacts := Set.empty,
crossPaths := false,
exportJars := true,
libraryDependencies += jansi,
libraryDependencies += scalatest % "test",
/*
* On windows, the raw classpath is too large to be a command argument to an
* external process so we create symbolic links with short names to get the
* classpath length under the limit.
*/
thinClientClasspath := {
val original = (Compile / fullClasspathAsJars).value.map(_.data)
val outputDir = target.value / "thinclientcp"
IO.createDirectory(outputDir)
Files.walk(outputDir.toPath).forEach {
case f if f.getFileName.toString.endsWith(".jar") => Files.deleteIfExists(f)
case _ =>
}
original.zipWithIndex.map {
case (f, i) => Files.createSymbolicLink(outputDir.toPath / s"$i.jar", f.toPath)
}
},
thinClientNativeImageCommand := System.getProperty("sbt.native-image", "native-image").toString,
2020-08-14 04:56:02 +02:00
buildNativeThinClient / name := s"sbtn${if (isWin) ".exe" else ""}",
nativeThinClientPath := target.value.toPath / "bin" / (buildNativeThinClient / name).value,
thinClientNativeImageClass := "sbt.client.Client",
buildNativeThinClient := {
val hasChanges = thinClientClasspath.outputFileChanges.hasChanges
val cpString =
thinClientClasspath.value.map(_.getFileName).mkString(java.io.File.pathSeparator)
val prefix = Seq(thinClientNativeImageCommand.value, "-cp", cpString)
val full = prefix ++ thinClientNativeImageOptions.value :+ thinClientNativeImageClass.value
val dir = target.value
if (hasChanges || !Files.exists(nativeThinClientPath.value)) {
val pb = new java.lang.ProcessBuilder(full: _*)
pb.directory(dir / "thinclientcp")
val proc = pb.start()
val thread = new Thread {
setDaemon(true)
val is = proc.getInputStream
val es = proc.getErrorStream
override def run(): Unit = {
Thread.sleep(100)
while (proc.isAlive) {
if (is.available > 0 || es.available > 0) {
while (is.available > 0) System.out.print(is.read.toChar)
while (es.available > 0) System.err.print(es.read.toChar)
}
if (proc.isAlive) Thread.sleep(10)
}
}
}
thread.start()
proc.waitFor(5, java.util.concurrent.TimeUnit.MINUTES)
assert(proc.exitValue == 0, s"Exit value ${proc.exitValue} was nonzero")
}
nativeThinClientPath.value
},
thinClientNativeImageOptions := Seq(
"--no-fallback",
s"--initialize-at-run-time=sbt.client",
"--verbose",
"-H:IncludeResourceBundles=jline.console.completer.CandidateListCompletionHandler",
"-H:+ReportExceptionStackTraces",
"-H:-ParseRuntimeOptions",
2020-08-14 04:56:02 +02:00
s"-H:Name=${target.value / "bin" / "sbtn"}",
),
buildThinClient := {
val isFish = Def.spaceDelimited("").parsed.headOption.fold(false)(_ == "--fish")
val ext = if (isWin) ".bat" else if (isFish) ".fish" else ".sh"
val output = target.value.toPath / "bin" / s"${if (isFish) "fish-" else ""}client$ext"
java.nio.file.Files.createDirectories(output.getParent)
val cp = (Compile / fullClasspathAsJars).value.map(_.data)
val args =
if (isWin) "%*" else if (isFish) s"$$argv" else s"$$*"
java.nio.file.Files.write(
output,
s"""
|${if (isWin) "@echo off" else s"#!/usr/bin/env ${if (isFish) "fish" else "sh"}"}
|
|java -cp ${cp.mkString(java.io.File.pathSeparator)} sbt.client.Client --jna $args
""".stripMargin.linesIterator.toSeq.tail.mkString("\n").getBytes
)
output.toFile.setExecutable(true)
output
},
)
/*
lazy val sbtBig = (project in file(".big"))
.dependsOn(sbtProj)
.settings(
name := "sbt-big",
normalizedName := "sbt-big",
crossPaths := false,
assemblyShadeRules.in(assembly) := {
val packagesToBeShaded = Seq(
"fastparse",
"jawn",
"scalapb",
)
packagesToBeShaded.map( prefix => {
ShadeRule.rename(s"$prefix.**" -> s"sbt.internal.$prefix.@1").inAll
})
},
assemblyMergeStrategy in assembly := {
case "LICENSE" | "NOTICE" => MergeStrategy.first
case x => (assemblyMergeStrategy in assembly).value(x)
},
artifact.in(Compile, packageBin) := artifact.in(Compile, assembly).value,
assemblyOption.in(assembly) ~= { _.copy(includeScala = false) },
addArtifact(artifact.in(Compile, packageBin), assembly),
pomPostProcess := { node =>
new RuleTransformer(new RewriteRule {
override def transform(node: XmlNode): XmlNodeSeq = node match {
case e: Elem if node.label == "dependency" =>
Comment(
"the dependency that was here has been absorbed via sbt-assembly"
)
case _ => node
}
}).transform(node).head
},
)
2019-05-11 09:42:06 +02:00
*/
// util projects used by Zinc and Lm
lazy val lowerUtils = (project in (file("internal") / "lower"))
.aggregate(lowerUtilProjects.map(p => LocalProject(p.id)): _*)
.settings(
publish / skip := true,
crossScalaVersions := Nil,
)
lazy val upperModules = (project in (file("internal") / "upper"))
.aggregate(
((allProjects diff lowerUtilProjects)
diff Seq(bundledLauncherProj)).map(p => LocalProject(p.id)): _*
)
.settings(
publish / skip := true,
crossScalaVersions := Nil,
)
lazy val sbtIgnoredProblems = {
2017-11-29 22:45:02 +01:00
Vector(
2019-10-17 23:27:43 +02:00
exclude[IncompatibleSignatureProblem]("sbt.package.some"),
exclude[IncompatibleSignatureProblem]("sbt.package.inThisBuild"),
exclude[IncompatibleSignatureProblem]("sbt.package.inConfig"),
exclude[IncompatibleSignatureProblem]("sbt.package.inTask"),
exclude[IncompatibleSignatureProblem]("sbt.package.inScope"),
exclude[MissingClassProblem]("buildinfo.BuildInfo"),
exclude[MissingClassProblem]("buildinfo.BuildInfo$"),
// Added more items to Import trait.
exclude[ReversedMissingMethodProblem]("sbt.Import.sbt$Import$_setter_$WatchSource_="),
2017-11-29 22:45:02 +01:00
exclude[ReversedMissingMethodProblem]("sbt.Import.WatchSource"),
Add support for managed task inputs In my recent changes to watch, I have been moving towards a world in which sbt manages the file inputs and outputs at the task level. The main idea is that we want to enable a user to specify the inputs and outputs of a task and have sbt able to track those inputs across multiple task evaluations. Sbt should be able to automatically trigger a build when the inputs change and it also should be able to avoid task evaluation if non of the inputs have changed. The former case of having sbt automatically watch the file inputs of a task has been present since watch was refactored. In this commit, I make it possible for the user to retrieve the lists of new, modified and deleted files. The user can then avoid task evaluation if none of the inputs have changed. To implement this, I inject a number of new settings during project load if the fileInputs setting is defined for a task. The injected settings are: allPathsAndAttributes -- this retrieves all of the paths described by the fileInputs for the task along with their attributes fileStamps -- this retrieves all of the file stamps for the files returned by allPathsAndAttributes Using these two injected tasks, I also inject a number of derived tasks, such as allFiles, which returns all of the regular files returned by allPathsAndAttributes and changedFiles, which returns all of the regular files that have been modified since the last run. Using these injected settings, the user is able to write tasks that avoid evaluation if the inputs haven't changed. foo / fileInputs += baseDirectory.value.toGlob / ** / "*.scala" foo := { foo.previous match { case Some(p) if (foo / changedFiles).value.isEmpty => p case _ => fooImpl((foo / allFiles).value } } To make this whole mechanism work, I add a private task key: val fileAttributeMap = taskKey[java.util.HashMap[Path, Stamp]]("...") This keeps track of the stamps for all of the files that are managed by sbt. The fileStamps task will first look for the stamp in the attribute map and, only if it is not present, it will update the cache. This allows us to ensure that a given file will only be stamped once per task evaluation run no matter how the file inputs are specified. Moreover, in a continuous build, I'm able to reuse the attribute map which can significantly reduce latency because the default file stamping implementation used by zinc is fairly expensive (it can take anywhere between 300-1500ms to stamp 5000 8kb source files on my mac). I also renamed some of the watch related keys to be a bit more clear.
2019-04-24 02:00:13 +02:00
exclude[ReversedMissingMethodProblem]("sbt.Import.AnyPath"),
exclude[ReversedMissingMethodProblem]("sbt.Import.sbt$Import$_setter_$**_="),
exclude[ReversedMissingMethodProblem]("sbt.Import.sbt$Import$_setter_$*_="),
exclude[ReversedMissingMethodProblem]("sbt.Import.sbt$Import$_setter_$ChangedFiles_="),
Add support for managed task inputs In my recent changes to watch, I have been moving towards a world in which sbt manages the file inputs and outputs at the task level. The main idea is that we want to enable a user to specify the inputs and outputs of a task and have sbt able to track those inputs across multiple task evaluations. Sbt should be able to automatically trigger a build when the inputs change and it also should be able to avoid task evaluation if non of the inputs have changed. The former case of having sbt automatically watch the file inputs of a task has been present since watch was refactored. In this commit, I make it possible for the user to retrieve the lists of new, modified and deleted files. The user can then avoid task evaluation if none of the inputs have changed. To implement this, I inject a number of new settings during project load if the fileInputs setting is defined for a task. The injected settings are: allPathsAndAttributes -- this retrieves all of the paths described by the fileInputs for the task along with their attributes fileStamps -- this retrieves all of the file stamps for the files returned by allPathsAndAttributes Using these two injected tasks, I also inject a number of derived tasks, such as allFiles, which returns all of the regular files returned by allPathsAndAttributes and changedFiles, which returns all of the regular files that have been modified since the last run. Using these injected settings, the user is able to write tasks that avoid evaluation if the inputs haven't changed. foo / fileInputs += baseDirectory.value.toGlob / ** / "*.scala" foo := { foo.previous match { case Some(p) if (foo / changedFiles).value.isEmpty => p case _ => fooImpl((foo / allFiles).value } } To make this whole mechanism work, I add a private task key: val fileAttributeMap = taskKey[java.util.HashMap[Path, Stamp]]("...") This keeps track of the stamps for all of the files that are managed by sbt. The fileStamps task will first look for the stamp in the attribute map and, only if it is not present, it will update the cache. This allows us to ensure that a given file will only be stamped once per task evaluation run no matter how the file inputs are specified. Moreover, in a continuous build, I'm able to reuse the attribute map which can significantly reduce latency because the default file stamping implementation used by zinc is fairly expensive (it can take anywhere between 300-1500ms to stamp 5000 8kb source files on my mac). I also renamed some of the watch related keys to be a bit more clear.
2019-04-24 02:00:13 +02:00
exclude[ReversedMissingMethodProblem]("sbt.Import.sbt$Import$_setter_$AnyPath_="),
exclude[ReversedMissingMethodProblem]("sbt.Import.sbt$Import$_setter_$Glob_="),
exclude[ReversedMissingMethodProblem]("sbt.Import.sbt$Import$_setter_$RecursiveGlob_="),
exclude[ReversedMissingMethodProblem]("sbt.Import.sbt$Import$_setter_$RelativeGlob_="),
exclude[ReversedMissingMethodProblem]("sbt.Import.*"),
exclude[ReversedMissingMethodProblem]("sbt.Import.**"),
exclude[ReversedMissingMethodProblem]("sbt.Import.ChangedFiles"),
Add support for managed task inputs In my recent changes to watch, I have been moving towards a world in which sbt manages the file inputs and outputs at the task level. The main idea is that we want to enable a user to specify the inputs and outputs of a task and have sbt able to track those inputs across multiple task evaluations. Sbt should be able to automatically trigger a build when the inputs change and it also should be able to avoid task evaluation if non of the inputs have changed. The former case of having sbt automatically watch the file inputs of a task has been present since watch was refactored. In this commit, I make it possible for the user to retrieve the lists of new, modified and deleted files. The user can then avoid task evaluation if none of the inputs have changed. To implement this, I inject a number of new settings during project load if the fileInputs setting is defined for a task. The injected settings are: allPathsAndAttributes -- this retrieves all of the paths described by the fileInputs for the task along with their attributes fileStamps -- this retrieves all of the file stamps for the files returned by allPathsAndAttributes Using these two injected tasks, I also inject a number of derived tasks, such as allFiles, which returns all of the regular files returned by allPathsAndAttributes and changedFiles, which returns all of the regular files that have been modified since the last run. Using these injected settings, the user is able to write tasks that avoid evaluation if the inputs haven't changed. foo / fileInputs += baseDirectory.value.toGlob / ** / "*.scala" foo := { foo.previous match { case Some(p) if (foo / changedFiles).value.isEmpty => p case _ => fooImpl((foo / allFiles).value } } To make this whole mechanism work, I add a private task key: val fileAttributeMap = taskKey[java.util.HashMap[Path, Stamp]]("...") This keeps track of the stamps for all of the files that are managed by sbt. The fileStamps task will first look for the stamp in the attribute map and, only if it is not present, it will update the cache. This allows us to ensure that a given file will only be stamped once per task evaluation run no matter how the file inputs are specified. Moreover, in a continuous build, I'm able to reuse the attribute map which can significantly reduce latency because the default file stamping implementation used by zinc is fairly expensive (it can take anywhere between 300-1500ms to stamp 5000 8kb source files on my mac). I also renamed some of the watch related keys to be a bit more clear.
2019-04-24 02:00:13 +02:00
exclude[ReversedMissingMethodProblem]("sbt.Import.RecursiveGlob"),
exclude[ReversedMissingMethodProblem]("sbt.Import.Glob"),
exclude[ReversedMissingMethodProblem]("sbt.Import.RelativeGlob"),
2017-11-29 22:45:02 +01:00
// Dropped in favour of kind-projector's polymorphic lambda literals
exclude[DirectMissingMethodProblem]("sbt.Import.Param"),
exclude[DirectMissingMethodProblem]("sbt.package.Param"),
2018-07-01 09:13:09 +02:00
exclude[ReversedMissingMethodProblem]("sbt.Import.SemanticSelector"),
exclude[ReversedMissingMethodProblem]("sbt.Import.sbt$Import$_setter_$SemanticSelector_="),
2017-11-29 22:45:02 +01:00
// Dropped in favour of plain scala.Function, and its compose method
exclude[DirectMissingMethodProblem]("sbt.package.toFn1"),
2017-04-21 09:14:31 +02:00
)
}
2014-12-18 05:38:10 +01:00
def runNpm(command: String, base: File, log: sbt.internal.util.ManagedLogger) = {
import scala.sys.process._
try {
2017-12-19 06:17:46 +01:00
val exitCode = Process(s"npm $command", Option(base)) ! log
if (exitCode != 0) throw new Exception("Process returned exit code: " + exitCode)
} catch {
case e: java.io.IOException => log.warn("failed to run npm " + e.getMessage)
}
}
lazy val vscodePlugin = (project in file("vscode-sbt-scala"))
.settings(
crossPaths := false,
crossScalaVersions := Seq(baseScalaVersion),
skip in publish := true,
compile in Compile := {
val _ = update.value
runNpm("run compile", baseDirectory.value, streams.value.log)
sbt.internal.inc.Analysis.empty
},
update := {
val old = update.value
val t = target.value / "updated"
val base = baseDirectory.value
val log = streams.value.log
if (t.exists) ()
else {
runNpm("install", base, log)
IO.touch(t)
}
old
},
cleanFiles ++= {
val base = baseDirectory.value
Vector(
target.value / "updated",
2019-05-11 09:42:06 +02:00
base / "node_modules",
base / "client" / "node_modules",
base / "client" / "server",
base / "client" / "out",
2019-05-11 09:42:06 +02:00
base / "server" / "node_modules"
) filter { _.exists }
}
)
def scriptedTask(launch: Boolean): Def.Initialize[InputTask[Unit]] = Def.inputTask {
val _ = publishLocalBinAll.value
val launchJar = s"-Dsbt.launch.jar=${(bundledLauncherProj / Compile / packageBin).value}"
2017-04-21 09:14:31 +02:00
Scripted.doScripted(
(scalaInstance in scriptedSbtReduxProj).value,
2017-04-21 09:14:31 +02:00
scriptedSource.value,
scriptedBufferLog.value,
2018-01-24 14:42:18 +01:00
Def.setting(Scripted.scriptedParser(scriptedSource.value)).parsed,
2017-04-21 09:14:31 +02:00
scriptedPrescripted.value,
scriptedLaunchOpts.value ++ (if (launch) Some(launchJar) else None),
Explicitly set scripted and server test classpath This commit makes it so that the scalaVersion, sbtVersion and classpath are always passed in as parameters to any method that creates an sbt server -- either for scripted or for the sbt server tests. By making that change, I was able to change the implementation of scripted in the sbt project to use publishLocalBin instead of publishLocal. This makes the scripted tests start much faster (doc alone can easily take 30 second) with messing with the build to exclude slow tasks from publishLocal. As part of this change, I removed the test dependency on scriptedSbtRedux for sbtProj and instead had scriptedSbtRedux depend on sbtProj. This allowed me to remove some messy LocalProject logic in the resourceGenerators for scriptedSbtReduxProj. I also had to remove a number of imports in the scriptedSbtReduxProj because the definitions available in the sbt package object became available. I also removed the dependency on sbt-buildinfo and instead pass the values from the build into test classes using scalatest properties. I ran into a number of minor issues with the build info plugin, namely that I couldn't get fullClasspathAsJars to reliably run as a BuildInfo key. It also is somewhat more clear to me to just rely on the built in scalatest functionality. The big drawback is that the scalatest properties can only be strings, but that restriction isn't really a problem here (strangely the TestData structure has a field configMap which is effectively Map[String, Any] but Any is actually always String given how the TestData is created as part of framework initialization. Since scripted no longer publishes, scriptedUnpublished is now effectively an alias for scripted. To get publishLocalBin working, I had to copy private code from IvyXml.scala into PublishBinPlugin. Once we publish a new version of sbt, we can remove the copied code and invoke IvyXml.makeIvyXmlBefore directly.
2020-01-12 04:52:36 +01:00
scalaVersion.value,
version.value,
(scriptedSbtReduxProj / Test / fullClasspathAsJars).value
.map(_.data)
.filterNot(_.getName.contains("scala-compiler")),
streams.value.log
2017-04-21 09:14:31 +02:00
)
2014-12-18 05:38:10 +01:00
}
lazy val publishLauncher = TaskKey[Unit]("publish-launcher")
2017-04-21 09:14:31 +02:00
def allProjects =
Seq(
logicProj,
completeProj,
2017-04-21 09:14:31 +02:00
testingProj,
testAgentProj,
taskProj,
stdTaskProj,
runProj,
scriptedSbtReduxProj,
scriptedSbtOldProj,
2017-04-21 09:14:31 +02:00
scriptedPluginProj,
dependencyTreeProj,
2017-04-21 09:14:31 +02:00
protocolProj,
actionsProj,
commandProj,
mainSettingsProj,
2019-04-18 09:14:04 +02:00
zincLmIntegrationProj,
2017-04-21 09:14:31 +02:00
mainProj,
sbtProj,
2017-05-26 06:59:49 +02:00
bundledLauncherProj,
sbtClientProj,
) ++ lowerUtilProjects
// These need to be cross published to 2.12 and 2.13 for Zinc
lazy val lowerUtilProjects =
Seq(
collectionProj,
coreMacrosProj,
utilCache,
utilControl,
utilInterface,
utilLogging,
utilPosition,
utilRelation,
utilScripted,
utilTracking
2017-04-21 09:14:31 +02:00
)
2015-02-03 04:44:02 +01:00
lazy val nonRoots = allProjects.map(p => LocalProject(p.id))
2014-12-18 05:38:10 +01:00
2018-07-31 02:28:42 +02:00
ThisBuild / scriptedBufferLog := true
2019-05-11 09:42:06 +02:00
ThisBuild / scriptedPrescripted := { _ =>
}
2018-07-31 02:28:42 +02:00
2017-04-21 09:14:31 +02:00
def otherRootSettings =
Seq(
scripted := scriptedTask(false).evaluated,
scriptedUnpublished := scriptedTask(false).evaluated,
2017-04-21 09:14:31 +02:00
scriptedSource := (sourceDirectory in sbtProj).value / "sbt-test",
watchTriggers in scripted += scriptedSource.value.toGlob / **,
Explicitly set scripted and server test classpath This commit makes it so that the scalaVersion, sbtVersion and classpath are always passed in as parameters to any method that creates an sbt server -- either for scripted or for the sbt server tests. By making that change, I was able to change the implementation of scripted in the sbt project to use publishLocalBin instead of publishLocal. This makes the scripted tests start much faster (doc alone can easily take 30 second) with messing with the build to exclude slow tasks from publishLocal. As part of this change, I removed the test dependency on scriptedSbtRedux for sbtProj and instead had scriptedSbtRedux depend on sbtProj. This allowed me to remove some messy LocalProject logic in the resourceGenerators for scriptedSbtReduxProj. I also had to remove a number of imports in the scriptedSbtReduxProj because the definitions available in the sbt package object became available. I also removed the dependency on sbt-buildinfo and instead pass the values from the build into test classes using scalatest properties. I ran into a number of minor issues with the build info plugin, namely that I couldn't get fullClasspathAsJars to reliably run as a BuildInfo key. It also is somewhat more clear to me to just rely on the built in scalatest functionality. The big drawback is that the scalatest properties can only be strings, but that restriction isn't really a problem here (strangely the TestData structure has a field configMap which is effectively Map[String, Any] but Any is actually always String given how the TestData is created as part of framework initialization. Since scripted no longer publishes, scriptedUnpublished is now effectively an alias for scripted. To get publishLocalBin working, I had to copy private code from IvyXml.scala into PublishBinPlugin. Once we publish a new version of sbt, we can remove the copied code and invoke IvyXml.makeIvyXmlBefore directly.
2020-01-12 04:52:36 +01:00
watchTriggers in scriptedUnpublished := (watchTriggers in scripted).value,
2019-12-30 01:26:05 +01:00
scriptedLaunchOpts := List("-Xmx1500M", "-Xms512M", "-server") :::
(sys.props.get("sbt.ivy.home") match {
case Some(home) => List(s"-Dsbt.ivy.home=$home")
case _ => Nil
}),
publishLocalBinAll := {
val _ = (Compile / publishLocalBin).all(scriptedProjects).value
},
Explicitly set scripted and server test classpath This commit makes it so that the scalaVersion, sbtVersion and classpath are always passed in as parameters to any method that creates an sbt server -- either for scripted or for the sbt server tests. By making that change, I was able to change the implementation of scripted in the sbt project to use publishLocalBin instead of publishLocal. This makes the scripted tests start much faster (doc alone can easily take 30 second) with messing with the build to exclude slow tasks from publishLocal. As part of this change, I removed the test dependency on scriptedSbtRedux for sbtProj and instead had scriptedSbtRedux depend on sbtProj. This allowed me to remove some messy LocalProject logic in the resourceGenerators for scriptedSbtReduxProj. I also had to remove a number of imports in the scriptedSbtReduxProj because the definitions available in the sbt package object became available. I also removed the dependency on sbt-buildinfo and instead pass the values from the build into test classes using scalatest properties. I ran into a number of minor issues with the build info plugin, namely that I couldn't get fullClasspathAsJars to reliably run as a BuildInfo key. It also is somewhat more clear to me to just rely on the built in scalatest functionality. The big drawback is that the scalatest properties can only be strings, but that restriction isn't really a problem here (strangely the TestData structure has a field configMap which is effectively Map[String, Any] but Any is actually always String given how the TestData is created as part of framework initialization. Since scripted no longer publishes, scriptedUnpublished is now effectively an alias for scripted. To get publishLocalBin working, I had to copy private code from IvyXml.scala into PublishBinPlugin. Once we publish a new version of sbt, we can remove the copied code and invoke IvyXml.makeIvyXmlBefore directly.
2020-01-12 04:52:36 +01:00
aggregate in bintrayRelease := false,
2017-04-21 09:14:31 +02:00
) ++ inConfig(Scripted.RepoOverrideTest)(
Seq(
2017-06-23 18:58:00 +02:00
scriptedLaunchOpts := List(
"-Xmx1500M",
"-Xms512M",
"-server",
"-Dsbt.override.build.repos=true",
s"""-Dsbt.repository.config=${scriptedSource.value / "repo.config"}"""
2019-12-30 01:26:05 +01:00
) :::
(sys.props.get("sbt.ivy.home") match {
case Some(home) => List(s"-Dsbt.ivy.home=$home")
case _ => Nil
}),
scripted := scriptedTask(true).evaluated,
scriptedUnpublished := scriptedTask(true).evaluated,
2017-04-21 09:14:31 +02:00
scriptedSource := (sourceDirectory in sbtProj).value / "repo-override-test"
2019-05-11 09:42:06 +02:00
)
)
lazy val docProjects: ScopeFilter = ScopeFilter(
2019-05-11 09:42:06 +02:00
inAnyProject -- inProjects(
sbtRoot,
sbtProj,
scriptedSbtReduxProj,
scriptedSbtOldProj,
scriptedPluginProj,
upperModules,
lowerUtils,
2019-05-11 09:42:06 +02:00
),
inConfigurations(Compile)
2014-12-18 05:38:10 +01:00
)
lazy val javafmtOnCompile = taskKey[Unit]("Formats java sources before compile")
Explicitly set scripted and server test classpath This commit makes it so that the scalaVersion, sbtVersion and classpath are always passed in as parameters to any method that creates an sbt server -- either for scripted or for the sbt server tests. By making that change, I was able to change the implementation of scripted in the sbt project to use publishLocalBin instead of publishLocal. This makes the scripted tests start much faster (doc alone can easily take 30 second) with messing with the build to exclude slow tasks from publishLocal. As part of this change, I removed the test dependency on scriptedSbtRedux for sbtProj and instead had scriptedSbtRedux depend on sbtProj. This allowed me to remove some messy LocalProject logic in the resourceGenerators for scriptedSbtReduxProj. I also had to remove a number of imports in the scriptedSbtReduxProj because the definitions available in the sbt package object became available. I also removed the dependency on sbt-buildinfo and instead pass the values from the build into test classes using scalatest properties. I ran into a number of minor issues with the build info plugin, namely that I couldn't get fullClasspathAsJars to reliably run as a BuildInfo key. It also is somewhat more clear to me to just rely on the built in scalatest functionality. The big drawback is that the scalatest properties can only be strings, but that restriction isn't really a problem here (strangely the TestData structure has a field configMap which is effectively Map[String, Any] but Any is actually always String given how the TestData is created as part of framework initialization. Since scripted no longer publishes, scriptedUnpublished is now effectively an alias for scripted. To get publishLocalBin working, I had to copy private code from IvyXml.scala into PublishBinPlugin. Once we publish a new version of sbt, we can remove the copied code and invoke IvyXml.makeIvyXmlBefore directly.
2020-01-12 04:52:36 +01:00
lazy val scriptedProjects = ScopeFilter(inAnyProject -- inProjects(vscodePlugin))
2014-12-18 23:40:20 +01:00
def customCommands: Seq[Setting[_]] = Seq(
commands += Command.command("setupBuildScala212") { state =>
s"""set scalaVersion in ThisBuild := "$scala212" """ ::
2014-12-18 23:40:20 +01:00
state
},
commands += Command.command("whitesourceOnPush") { state =>
sys.env.get("TRAVIS_EVENT_TYPE") match {
case Some("push") =>
"whitesourceCheckPolicies" ::
2019-05-11 09:42:06 +02:00
"whitesourceUpdate" ::
state
case _ => state
}
},
2014-12-18 23:40:20 +01:00
commands += Command.command("release-sbt-local") { state =>
"clean" ::
2017-04-21 09:14:31 +02:00
"so compile" ::
"so publishLocal" ::
"reload" ::
state
2014-12-18 23:40:20 +01:00
},
2018-02-21 08:28:33 +01:00
commands += Command.command("publishLocalAllModule") { state =>
val extracted = Project.extract(state)
import extracted._
2019-05-11 09:42:06 +02:00
val sv = get(scalaVersion)
val projs = structure.allProjectRefs
val ioOpt = projs find { case ProjectRef(_, id) => id == "ioRoot"; case _ => false }
2018-02-21 08:28:33 +01:00
val utilOpt = projs find { case ProjectRef(_, id) => id == "utilRoot"; case _ => false }
2019-05-11 09:42:06 +02:00
val lmOpt = projs find { case ProjectRef(_, id) => id == "lmRoot"; case _ => false }
2018-02-21 08:28:33 +01:00
val zincOpt = projs find { case ProjectRef(_, id) => id == "zincRoot"; case _ => false }
2019-05-11 09:42:06 +02:00
(ioOpt map { case ProjectRef(build, _) => "{" + build.toString + "}/publishLocal" }).toList :::
(utilOpt map { case ProjectRef(build, _) => "{" + build.toString + "}/publishLocal" }).toList :::
(lmOpt map { case ProjectRef(build, _) => "{" + build.toString + "}/publishLocal" }).toList :::
(zincOpt map {
case ProjectRef(build, _) =>
val zincSv = get(scalaVersion in ProjectRef(build, "zinc"))
val csv = get(crossScalaVersions in ProjectRef(build, "compilerBridge")).toList
(csv flatMap { bridgeSv =>
s"++$bridgeSv" :: ("{" + build.toString + "}compilerBridge/publishLocal") :: Nil
}) :::
List(s"++$zincSv", "{" + build.toString + "}/publishLocal")
}).getOrElse(Nil) :::
List(s"++$sv", "publishLocal") :::
state
2018-02-21 08:28:33 +01:00
},
commands += Command.command("releaseLowerUtils") { state =>
// TODO - Any sort of validation
"clean" ::
"+lowerUtils/compile" ::
"+lowerUtils/publishSigned" ::
s"++$scala212" ::
state
},
commands += Command.command("release") { state =>
2014-12-18 23:40:20 +01:00
// TODO - Any sort of validation
"clean" ::
2017-05-30 08:44:13 +02:00
"conscriptConfigs" ::
"upperModules/compile" ::
"upperModules/publishSigned" ::
"bundledLauncherProj/publishSigned" ::
"bundledLauncherProj/publishLauncher" ::
2015-02-21 03:09:43 +01:00
state
},
2014-12-18 23:40:20 +01:00
)
2019-05-11 09:42:06 +02:00
ThisBuild / whitesourceProduct := "Lightbend Reactive Platform"
ThisBuild / whitesourceAggregateProjectName := {
// note this can get detached on tag build etc
2020-01-15 23:45:27 +01:00
val b = sys.process.Process("git rev-parse --abbrev-ref HEAD").!!.trim
val Stable = """1\.([0-9]+)\.x""".r
b match {
case Stable(y) => "sbt-1." + y.toString + "-stable"
case _ => "sbt-master"
}
}
ThisBuild / whitesourceAggregateProjectToken := {
(ThisBuild / whitesourceAggregateProjectName).value match {
case "sbt-master" => "e7a1e55518c0489a98e9c7430c8b2ccd53d9f97c12ed46148b592ebe4c8bf128"
2020-01-15 23:45:27 +01:00
case "sbt-1.3-stable" => "7e38cbb4d2fc4599835cd5d2cfb41b150597a4147b15424bb65841664ab2ec0d"
case "sbt-1.2-stable" => "54f2313767aa47198971e65595670ee16e1ad0000d20458588e72d3ac2c34763"
case _ => "" // it's ok to fail here
}
}
2019-05-11 09:42:06 +02:00
ThisBuild / whitesourceIgnoredScopes ++= Seq("plugin", "scalafmt", "sxr")
ThisBuild / whitesourceFailOnError := sys.env.contains("WHITESOURCE_PASSWORD") // fail if pwd is present
ThisBuild / whitesourceForceCheckAllDependencies := true