mirror of https://github.com/sbt/sbt.git
Refactor to build mainProj
This commit is contained in:
parent
100f1ac09c
commit
cba7a0efc3
20
build.sbt
20
build.sbt
|
|
@ -10,7 +10,7 @@ import scala.util.Try
|
||||||
// ThisBuild settings take lower precedence,
|
// ThisBuild settings take lower precedence,
|
||||||
// but can be shared across the multi projects.
|
// but can be shared across the multi projects.
|
||||||
ThisBuild / version := {
|
ThisBuild / version := {
|
||||||
val v = "2.0.0-alpha1-SNAPSHOT"
|
val v = "2.0.0-alpha2-SNAPSHOT"
|
||||||
nightlyVersion.getOrElse(v)
|
nightlyVersion.getOrElse(v)
|
||||||
}
|
}
|
||||||
ThisBuild / version2_13 := "2.0.0-alpha1-SNAPSHOT"
|
ThisBuild / version2_13 := "2.0.0-alpha1-SNAPSHOT"
|
||||||
|
|
@ -53,6 +53,7 @@ Global / excludeLint := (Global / excludeLint).?.value.getOrElse(Set.empty)
|
||||||
Global / excludeLint += componentID
|
Global / excludeLint += componentID
|
||||||
Global / excludeLint += scriptedBufferLog
|
Global / excludeLint += scriptedBufferLog
|
||||||
Global / excludeLint += checkPluginCross
|
Global / excludeLint += checkPluginCross
|
||||||
|
ThisBuild / evictionErrorLevel := Level.Info
|
||||||
|
|
||||||
def commonBaseSettings: Seq[Setting[_]] = Def.settings(
|
def commonBaseSettings: Seq[Setting[_]] = Def.settings(
|
||||||
headerLicense := Some(
|
headerLicense := Some(
|
||||||
|
|
@ -180,17 +181,7 @@ def mimaSettingsSince(versions: Seq[String]): Seq[Def.Setting[_]] = Def settings
|
||||||
val scriptedSbtReduxMimaSettings = Def.settings(mimaPreviousArtifacts := Set())
|
val scriptedSbtReduxMimaSettings = Def.settings(mimaPreviousArtifacts := Set())
|
||||||
|
|
||||||
lazy val sbtRoot: Project = (project in file("."))
|
lazy val sbtRoot: Project = (project in file("."))
|
||||||
.aggregate(
|
.aggregate(allProjects.map(p => LocalProject(p.id)): _*)
|
||||||
(allProjects diff Seq(
|
|
||||||
scriptedSbtReduxProj,
|
|
||||||
scriptedSbtOldProj,
|
|
||||||
scriptedPluginProj,
|
|
||||||
dependencyTreeProj,
|
|
||||||
mainProj,
|
|
||||||
sbtProj,
|
|
||||||
bundledLauncherProj,
|
|
||||||
)).map(p => LocalProject(p.id)): _*
|
|
||||||
)
|
|
||||||
.settings(
|
.settings(
|
||||||
minimalSettings,
|
minimalSettings,
|
||||||
onLoadMessage := {
|
onLoadMessage := {
|
||||||
|
|
@ -911,6 +902,7 @@ lazy val mainProj = (project in file("main"))
|
||||||
.enablePlugins(ContrabandPlugin)
|
.enablePlugins(ContrabandPlugin)
|
||||||
.dependsOn(
|
.dependsOn(
|
||||||
actionsProj,
|
actionsProj,
|
||||||
|
buildFileProj,
|
||||||
mainSettingsProj,
|
mainSettingsProj,
|
||||||
runProj,
|
runProj,
|
||||||
commandProj,
|
commandProj,
|
||||||
|
|
@ -984,13 +976,15 @@ lazy val sbtProj = (project in file("sbt-app"))
|
||||||
Tests.Argument(framework, s"-Dsbt.server.scala.version=${scalaVersion.value}") :: Nil
|
Tests.Argument(framework, s"-Dsbt.server.scala.version=${scalaVersion.value}") :: Nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.configure(addSbtIO, addSbtCompilerBridge)
|
.configure(addSbtIO)
|
||||||
|
// addSbtCompilerBridge
|
||||||
|
|
||||||
lazy val serverTestProj = (project in file("server-test"))
|
lazy val serverTestProj = (project in file("server-test"))
|
||||||
.dependsOn(sbtProj % "compile->test", scriptedSbtReduxProj % "compile->test")
|
.dependsOn(sbtProj % "compile->test", scriptedSbtReduxProj % "compile->test")
|
||||||
.settings(
|
.settings(
|
||||||
testedBaseSettings,
|
testedBaseSettings,
|
||||||
crossScalaVersions := Seq(baseScalaVersion),
|
crossScalaVersions := Seq(baseScalaVersion),
|
||||||
|
bspEnabled := false,
|
||||||
publish / skip := true,
|
publish / skip := true,
|
||||||
// make server tests serial
|
// make server tests serial
|
||||||
Test / watchTriggers += baseDirectory.value.toGlob / "src" / "server-test" / **,
|
Test / watchTriggers += baseDirectory.value.toGlob / "src" / "server-test" / **,
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,9 @@ class Eval(
|
||||||
valTypes: Seq[String],
|
valTypes: Seq[String],
|
||||||
extraHash: String,
|
extraHash: String,
|
||||||
): EvalDefinitions =
|
): EvalDefinitions =
|
||||||
|
println(s"""evalDefinitions(definitions = $definitions)
|
||||||
|
classpath = $classpath
|
||||||
|
""")
|
||||||
require(definitions.nonEmpty, "definitions to evaluate cannot be empty.")
|
require(definitions.nonEmpty, "definitions to evaluate cannot be empty.")
|
||||||
val extraHash0 = extraHash
|
val extraHash0 = extraHash
|
||||||
val ev = new EvalType[Seq[String]]:
|
val ev = new EvalType[Seq[String]]:
|
||||||
|
|
@ -314,7 +317,7 @@ object Eval:
|
||||||
class EvalSourceFile(name: String, startLine: Int, contents: String)
|
class EvalSourceFile(name: String, startLine: Int, contents: String)
|
||||||
extends SourceFile(
|
extends SourceFile(
|
||||||
new VirtualFile(name, contents.getBytes(StandardCharsets.UTF_8)),
|
new VirtualFile(name, contents.getBytes(StandardCharsets.UTF_8)),
|
||||||
scala.io.Codec.UTF8
|
contents.toArray
|
||||||
):
|
):
|
||||||
override def lineToOffset(line: Int): Int = super.lineToOffset((line + startLine) max 0)
|
override def lineToOffset(line: Int): Int = super.lineToOffset((line + startLine) max 0)
|
||||||
override def offsetToLine(offset: Int): Int = super.offsetToLine(offset) - startLine
|
override def offsetToLine(offset: Int): Int = super.offsetToLine(offset) - startLine
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,11 @@ import java.io.File
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import sbt.internal.util.complete.DefaultParsers.validID
|
import sbt.internal.util.complete.DefaultParsers.validID
|
||||||
import Def.{ ScopedKey, Setting }
|
import Def.{ ScopedKey, Setting }
|
||||||
// import Scope.GlobalScope
|
import Scope.GlobalScope
|
||||||
// import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0.*
|
||||||
import sbt.internal.parser.SbtParser
|
import sbt.internal.parser.SbtParser
|
||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters.*
|
||||||
import xsbti.VirtualFile
|
import xsbti.VirtualFile
|
||||||
import xsbti.VirtualFileRef
|
import xsbti.VirtualFileRef
|
||||||
|
|
||||||
|
|
@ -386,44 +386,49 @@ object Index {
|
||||||
private[this] def stringToKeyMap0(
|
private[this] def stringToKeyMap0(
|
||||||
settings: Set[AttributeKey[_]]
|
settings: Set[AttributeKey[_]]
|
||||||
)(label: AttributeKey[_] => String): Map[String, AttributeKey[_]] = {
|
)(label: AttributeKey[_] => String): Map[String, AttributeKey[_]] = {
|
||||||
// val multiMap = settings.groupBy(label)
|
val multiMap = settings.groupBy(label)
|
||||||
// val duplicates = multiMap.iterator
|
val duplicates = multiMap.iterator
|
||||||
// .collect { case (k, xs) if xs.size > 1 => (k, xs.map(_.manifest)) }
|
.collect { case (k, xs) if xs.size > 1 => (k, xs.map(_.manifest)) }
|
||||||
// .collect {
|
.collect {
|
||||||
// case (k, xs) if xs.size > 1 => (k, xs)
|
case (k, xs) if xs.size > 1 => (k, xs)
|
||||||
// }
|
}
|
||||||
// .toVector
|
.toVector
|
||||||
// if (duplicates.isEmpty)
|
if (duplicates.isEmpty)
|
||||||
// multiMap.collect { case (k, v) if validID(k) => (k, v.head) } toMap
|
multiMap.collect { case (k, v) if validID(k) => (k, v.head) } toMap
|
||||||
// else
|
else
|
||||||
// sys.error(
|
sys.error(
|
||||||
// duplicates map { case (k, tps) =>
|
duplicates map { case (k, tps) =>
|
||||||
// "'" + k + "' (" + tps.mkString(", ") + ")"
|
"'" + k + "' (" + tps.mkString(", ") + ")"
|
||||||
// } mkString ("Some keys were defined with the same name but different types: ", ", ", "")
|
} mkString ("Some keys were defined with the same name but different types: ", ", ", "")
|
||||||
// )
|
)
|
||||||
???
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] type TriggerMap = collection.mutable.HashMap[Task[_], Seq[Task[_]]]
|
private[this] type TriggerMap = collection.mutable.HashMap[Task[Any], Seq[Task[Any]]]
|
||||||
|
|
||||||
def triggers(ss: Settings[Scope]): Triggers[Task] = {
|
def triggers(ss: Settings[Scope]): Triggers[Task] = {
|
||||||
// val runBefore = new TriggerMap
|
val runBefore = new TriggerMap
|
||||||
// val triggeredBy = new TriggerMap
|
val triggeredBy = new TriggerMap
|
||||||
// ss.data.values foreach (
|
ss.data.values foreach (
|
||||||
// _.entries foreach {
|
_.entries foreach {
|
||||||
// case AttributeEntry(_, value: Task[_]) =>
|
case AttributeEntry(_, value: Task[Any]) =>
|
||||||
// val as = value.info.attributes
|
val as = value.info.attributes
|
||||||
// update(runBefore, value, as get Keys.runBefore)
|
update(runBefore, value, as.get(Def.runBefore.asInstanceOf))
|
||||||
// update(triggeredBy, value, as get Keys.triggeredBy)
|
update(triggeredBy, value, as.get(Def.triggeredBy.asInstanceOf))
|
||||||
// case _ => ()
|
case _ => ()
|
||||||
// }
|
}
|
||||||
// )
|
)
|
||||||
// val onComplete = (GlobalScope / Keys.onComplete) get ss getOrElse (() => ())
|
val onComplete = (GlobalScope / Def.onComplete) get ss getOrElse (() => ())
|
||||||
// new Triggers[Task](runBefore, triggeredBy, map => { onComplete(); map })
|
new Triggers[Task](runBefore, triggeredBy, map => { onComplete(); map })
|
||||||
???
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] def update(map: TriggerMap, base: Task[_], tasksOpt: Option[Seq[Task[_]]]): Unit =
|
private[this] def update(
|
||||||
for (tasks <- tasksOpt; task <- tasks)
|
map: TriggerMap,
|
||||||
|
base: Task[Any],
|
||||||
|
tasksOpt: Option[Seq[Task[Any]]]
|
||||||
|
): Unit =
|
||||||
|
for {
|
||||||
|
tasks <- tasksOpt
|
||||||
|
task <- tasks
|
||||||
|
}
|
||||||
map(task) = base +: map.getOrElse(task, Nil)
|
map(task) = base +: map.getOrElse(task, Nil)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,13 @@ private[sbt] object SbtParser:
|
||||||
private final val defaultClasspath =
|
private final val defaultClasspath =
|
||||||
sbt.io.Path.makeString(sbt.io.IO.classLocationPath[Product].toFile :: Nil)
|
sbt.io.Path.makeString(sbt.io.IO.classLocationPath[Product].toFile :: Nil)
|
||||||
|
|
||||||
|
def isIdentifier(ident: String): Boolean =
|
||||||
|
val code = s"val $ident = 0; val ${ident}${ident} = $ident"
|
||||||
|
try
|
||||||
|
val p = SbtParser(FAKE_FILE, List(code))
|
||||||
|
true
|
||||||
|
catch case e: Throwable => false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the previous error reporting functionality in
|
* Provides the previous error reporting functionality in
|
||||||
* [[scala.tools.reflect.ToolBox]].
|
* [[scala.tools.reflect.ToolBox]].
|
||||||
|
|
|
||||||
|
|
@ -9,31 +9,36 @@ package sbt
|
||||||
package internal
|
package internal
|
||||||
package parser
|
package parser
|
||||||
|
|
||||||
/*
|
import java.io.File
|
||||||
|
import dotty.tools.dotc.ast.untpd
|
||||||
|
import dotty.tools.dotc.core.Contexts.Context
|
||||||
|
|
||||||
private[sbt] object SbtRefactorings {
|
private[sbt] object SbtRefactorings:
|
||||||
|
|
||||||
import sbt.internal.parser.SbtParser.{ END_OF_LINE, FAKE_FILE }
|
import sbt.internal.parser.SbtParser.{ END_OF_LINE, FAKE_FILE }
|
||||||
import sbt.internal.SessionSettings.{ SessionSetting, SbtConfigFile }
|
|
||||||
|
|
||||||
|
/** A session setting is simply a tuple of a Setting[_] and the strings which define it. */
|
||||||
|
type SessionSetting = (Def.Setting[_], Seq[String])
|
||||||
|
type SbtConfigFile = (File, Seq[String])
|
||||||
val emptyString = ""
|
val emptyString = ""
|
||||||
val reverseOrderingInt = Ordering[Int].reverse
|
val reverseOrderingInt = Ordering[Int].reverse
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refactoring a `.sbt` file so that the new settings are used instead of any existing settings.
|
* Refactoring a `.sbt` file so that the new settings are used instead of any existing settings.
|
||||||
* @param configFile SbtConfigFile with the lines of an sbt file as a List[String] where each string is one line
|
* @param configFile SbtConfigFile with the lines of an sbt file as a List[String] where each string is one line
|
||||||
* @param commands A List of settings (space separate) that should be inserted into the current file.
|
* @param commands A List of settings (space separate) that should be inserted into the current file.
|
||||||
* If the settings replaces a value, it will replace the original line in the .sbt file.
|
* If the settings replaces a value, it will replace the original line in the .sbt file.
|
||||||
* If in the `.sbt` file we have multiply value for one settings -
|
* If in the `.sbt` file we have multiply value for one settings -
|
||||||
* the first will be replaced and the other will be removed.
|
* the first will be replaced and the other will be removed.
|
||||||
* @return a SbtConfigFile with new lines which represent the contents of the refactored .sbt file.
|
* @return a SbtConfigFile with new lines which represent the contents of the refactored .sbt file.
|
||||||
*/
|
*/
|
||||||
def applySessionSettings(
|
def applySessionSettings(
|
||||||
configFile: SbtConfigFile,
|
configFile: SbtConfigFile,
|
||||||
commands: Seq[SessionSetting]
|
commands: Seq[SessionSetting]
|
||||||
): SbtConfigFile = {
|
): SbtConfigFile = {
|
||||||
val (file, lines) = configFile
|
val (file, lines) = configFile
|
||||||
val split = SbtParser(FAKE_FILE, lines)
|
val split = SbtParser(FAKE_FILE, lines)
|
||||||
|
given ctx: Context = SbtParser.defaultGlobalForParser.compileCtx
|
||||||
val recordedCommands = recordCommands(commands, split)
|
val recordedCommands = recordCommands(commands, split)
|
||||||
val sortedRecordedCommands = recordedCommands.sortBy(_._1)(reverseOrderingInt)
|
val sortedRecordedCommands = recordedCommands.sortBy(_._1)(reverseOrderingInt)
|
||||||
|
|
||||||
|
|
@ -58,20 +63,22 @@ private[sbt] object SbtRefactorings {
|
||||||
if (trimmed.isEmpty) trimmed else text
|
if (trimmed.isEmpty) trimmed else text
|
||||||
}
|
}
|
||||||
|
|
||||||
private def recordCommands(commands: Seq[SessionSetting], split: SbtParser) =
|
private def recordCommands(commands: Seq[SessionSetting], split: SbtParser)(using Context) =
|
||||||
commands.flatMap { case (_, command) =>
|
commands.flatMap { case (_, command) =>
|
||||||
val map = toTreeStringMap(command)
|
val map = toTreeStringMap(command)
|
||||||
map.flatMap { case (name, _) => treesToReplacements(split, name, command) }
|
map.flatMap { case (name, _) => treesToReplacements(split, name, command) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private def treesToReplacements(split: SbtParser, name: String, command: Seq[String]) =
|
private def treesToReplacements(split: SbtParser, name: String, command: Seq[String])(using
|
||||||
|
Context
|
||||||
|
) =
|
||||||
split.settingsTrees.foldLeft(Seq.empty[(Int, String, String)]) { case (acc, (st, tree)) =>
|
split.settingsTrees.foldLeft(Seq.empty[(Int, String, String)]) { case (acc, (st, tree)) =>
|
||||||
val treeName = extractSettingName(tree)
|
val treeName = extractSettingName(tree)
|
||||||
if (name == treeName) {
|
if (name == treeName) {
|
||||||
val replacement =
|
val replacement =
|
||||||
if (acc.isEmpty) command.mkString(END_OF_LINE)
|
if (acc.isEmpty) command.mkString(END_OF_LINE)
|
||||||
else emptyString
|
else emptyString
|
||||||
(tree.pos.start, st, replacement) +: acc
|
(tree.sourcePos.start, st, replacement) +: acc
|
||||||
} else {
|
} else {
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
|
|
@ -86,14 +93,14 @@ private[sbt] object SbtRefactorings {
|
||||||
seq.toMap
|
seq.toMap
|
||||||
}
|
}
|
||||||
|
|
||||||
import scala.tools.nsc.Global
|
// todo: revisit
|
||||||
private def extractSettingName(tree: Global#Tree): String =
|
private def extractSettingName(tree: untpd.Tree): String =
|
||||||
tree.children match {
|
tree.toString()
|
||||||
case h :: _ =>
|
// tree.children match {
|
||||||
extractSettingName(h)
|
// case h :: _ =>
|
||||||
case _ =>
|
// extractSettingName(h)
|
||||||
tree.toString()
|
// case _ =>
|
||||||
}
|
// tree.toString()
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
end SbtRefactorings
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -36,4 +36,8 @@ lazy val foo = project
|
||||||
assert(p.settings(1) == ("""lazy val foo = project
|
assert(p.settings(1) == ("""lazy val foo = project
|
||||||
.settings(x := y)""" -> LineRange(7, 8)))
|
.settings(x := y)""" -> LineRange(7, 8)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("isIdentifier") {
|
||||||
|
assert(SbtParser.isIdentifier("1a") == false)
|
||||||
|
}
|
||||||
end SbtParserTest
|
end SbtParserTest
|
||||||
|
|
|
||||||
|
|
@ -13,21 +13,22 @@ object ConvertTestMacro:
|
||||||
def someMacroImpl(expr: Expr[Boolean])(using qctx: Quotes) =
|
def someMacroImpl(expr: Expr[Boolean])(using qctx: Quotes) =
|
||||||
val convert1: Convert[qctx.type] = new InputInitConvert(qctx)
|
val convert1: Convert[qctx.type] = new InputInitConvert(qctx)
|
||||||
import convert1.qctx.reflect.*
|
import convert1.qctx.reflect.*
|
||||||
def addTypeCon(tpe: TypeRepr, qual: Term, selection: Term): Term =
|
def addTypeCon[A](tpe: Type[A], qual: Term, selection: Term): Term =
|
||||||
tpe.asType match
|
tpe match
|
||||||
case '[a] =>
|
case '[a] =>
|
||||||
'{
|
'{
|
||||||
Option[a](${ selection.asExprOf[a] })
|
Option[a](${ selection.asExprOf[a] })
|
||||||
}.asTerm
|
}.asTerm
|
||||||
def substitute(name: String, tpe: TypeRepr, qual: Term, replace: Term) =
|
val substitute = [a] =>
|
||||||
convert1.convert[Boolean](name, qual) transform { (tree: Term) =>
|
(name: String, tpe: Type[a], qual: Term, replace: Term) =>
|
||||||
addTypeCon(tpe, tree, replace)
|
convert1.convert[Boolean](name, qual) transform { (tree: Term) =>
|
||||||
|
addTypeCon(tpe, tree, replace)
|
||||||
}
|
}
|
||||||
convert1.transformWrappers(expr.asTerm, substitute, Symbol.spliceOwner).asExprOf[Boolean]
|
convert1.transformWrappers(expr.asTerm, substitute, Symbol.spliceOwner).asExprOf[Boolean]
|
||||||
|
|
||||||
class InputInitConvert[C <: Quotes & scala.Singleton](override val qctx: C)
|
class InputInitConvert[C <: Quotes & scala.Singleton](override val qctx: C)
|
||||||
extends Convert[C](qctx)
|
extends Convert[C](qctx)
|
||||||
with ContextUtil[C](qctx):
|
with ContextUtil[C](qctx, 0):
|
||||||
// with TupleBuilder[C](qctx)
|
// with TupleBuilder[C](qctx)
|
||||||
// with TupleNBuilder[C](qctx):
|
// with TupleNBuilder[C](qctx):
|
||||||
import qctx.reflect.*
|
import qctx.reflect.*
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ package sbt
|
||||||
|
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import sbt.util.Level
|
import sbt.util.Level
|
||||||
|
import sbt.internal.inc.PlainVirtualFile
|
||||||
import sbt.internal.util.{ AttributeKey, FullReader, LineReader, Terminal }
|
import sbt.internal.util.{ AttributeKey, FullReader, LineReader, Terminal }
|
||||||
import sbt.internal.util.complete.{
|
import sbt.internal.util.complete.{
|
||||||
Completion,
|
Completion,
|
||||||
|
|
@ -39,6 +40,7 @@ import sbt.util.Level
|
||||||
import scala.Function.tupled
|
import scala.Function.tupled
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
import scala.util.control.NonFatal
|
import scala.util.control.NonFatal
|
||||||
|
import xsbti.VirtualFile
|
||||||
|
|
||||||
object BasicCommands {
|
object BasicCommands {
|
||||||
lazy val allBasicCommands: Seq[Command] = Seq(
|
lazy val allBasicCommands: Seq[Command] = Seq(
|
||||||
|
|
@ -110,8 +112,9 @@ object BasicCommands {
|
||||||
*/
|
*/
|
||||||
def addPluginSbtFile: Command = Command.arb(_ => addPluginSbtFileParser, addPluginSbtFileHelp()) {
|
def addPluginSbtFile: Command = Command.arb(_ => addPluginSbtFileParser, addPluginSbtFileHelp()) {
|
||||||
(s, extraSbtFile) =>
|
(s, extraSbtFile) =>
|
||||||
val extraFiles = s.get(BasicKeys.extraMetaSbtFiles).toList.flatten
|
val existing: Seq[VirtualFile] = s.get(BasicKeys.extraMetaSbtFiles).toList.flatten
|
||||||
s.put(BasicKeys.extraMetaSbtFiles, (extraFiles: Seq[File]) :+ extraSbtFile)
|
val vf = PlainVirtualFile(extraSbtFile.toPath())
|
||||||
|
s.put(BasicKeys.extraMetaSbtFiles, existing :+ vf)
|
||||||
}
|
}
|
||||||
|
|
||||||
def help: Command = Command.make(HelpCommand, helpBrief, helpDetailed)(helpParser)
|
def help: Command = Command.make(HelpCommand, helpBrief, helpDetailed)(helpParser)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ import sbt.librarymanagement.ModuleID
|
||||||
import sbt.util.Level
|
import sbt.util.Level
|
||||||
import scala.annotation.nowarn
|
import scala.annotation.nowarn
|
||||||
import scala.concurrent.duration.FiniteDuration
|
import scala.concurrent.duration.FiniteDuration
|
||||||
|
import xsbti.VirtualFile
|
||||||
|
import sbt.librarymanagement.Configuration
|
||||||
|
|
||||||
object BasicKeys {
|
object BasicKeys {
|
||||||
val historyPath = AttributeKey[Option[File]](
|
val historyPath = AttributeKey[Option[File]](
|
||||||
|
|
@ -25,7 +27,7 @@ object BasicKeys {
|
||||||
40
|
40
|
||||||
)
|
)
|
||||||
|
|
||||||
val extraMetaSbtFiles = AttributeKey[Seq[File]](
|
val extraMetaSbtFiles = AttributeKey[Seq[VirtualFile]](
|
||||||
"extraMetaSbtFile",
|
"extraMetaSbtFile",
|
||||||
"Additional plugin.sbt files.",
|
"Additional plugin.sbt files.",
|
||||||
10000
|
10000
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import sbt.internal.util.{ Terminal => ITerminal, * }
|
||||||
import Util._
|
import Util._
|
||||||
import sbt.util.Show
|
import sbt.util.Show
|
||||||
import xsbti.VirtualFile
|
import xsbti.VirtualFile
|
||||||
|
import sjsonnew.JsonFormat
|
||||||
|
|
||||||
/** A concrete settings system that uses `sbt.Scope` for the scope type. */
|
/** A concrete settings system that uses `sbt.Scope` for the scope type. */
|
||||||
object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits:
|
object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits:
|
||||||
|
|
@ -29,6 +30,10 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits:
|
||||||
|
|
||||||
def settings(ss: SettingsDefinition*): Seq[Setting[_]] = ss.flatMap(_.settings)
|
def settings(ss: SettingsDefinition*): Seq[Setting[_]] = ss.flatMap(_.settings)
|
||||||
|
|
||||||
|
val onComplete = SettingKey[() => Unit](
|
||||||
|
"onComplete",
|
||||||
|
"Hook to run when task evaluation completes. The type of this setting is subject to change, pending the resolution of SI-2915."
|
||||||
|
) // .withRank(DSetting)
|
||||||
val triggeredBy = AttributeKey[Seq[Task[_]]]("triggered-by")
|
val triggeredBy = AttributeKey[Seq[Task[_]]]("triggered-by")
|
||||||
val runBefore = AttributeKey[Seq[Task[_]]]("run-before")
|
val runBefore = AttributeKey[Seq[Task[_]]]("run-before")
|
||||||
val resolvedScoped = SettingKey[ScopedKey[_]](
|
val resolvedScoped = SettingKey[ScopedKey[_]](
|
||||||
|
|
@ -232,7 +237,8 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits:
|
||||||
|
|
||||||
inline def setting[A1](inline a: A1): Def.Initialize[A1] = ${ settingMacroImpl[A1]('a) }
|
inline def setting[A1](inline a: A1): Def.Initialize[A1] = ${ settingMacroImpl[A1]('a) }
|
||||||
|
|
||||||
// def settingDyn[T](t: Def.Initialize[T]): Def.Initialize[T] = macro settingDynMacroImpl[T]
|
inline def settingDyn[A1](inline a1: Def.Initialize[A1]): Def.Initialize[A1] =
|
||||||
|
${ SettingMacro.settingDynImpl('a1) }
|
||||||
|
|
||||||
inline def input[A1](inline p: State => Parser[A1]): ParserGen[A1] =
|
inline def input[A1](inline p: State => Parser[A1]): ParserGen[A1] =
|
||||||
${ SettingMacro.inputMacroImpl[A1]('p) }
|
${ SettingMacro.inputMacroImpl[A1]('p) }
|
||||||
|
|
@ -330,6 +336,20 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits:
|
||||||
|
|
||||||
inline def evaluated: A1 = InputWrapper.`wrapInitInputTask_\u2603\u2603`[A1](in)
|
inline def evaluated: A1 = InputWrapper.`wrapInitInputTask_\u2603\u2603`[A1](in)
|
||||||
|
|
||||||
|
def toTask(arg: String): Initialize[Task[A1]] =
|
||||||
|
import TaskExtra.singleInputTask
|
||||||
|
FullInstance.flatten(
|
||||||
|
(Def.stateKey zipWith in)((sTask, it) =>
|
||||||
|
sTask map { s =>
|
||||||
|
Parser.parse(arg, it.parser(s)) match
|
||||||
|
case Right(a) => Def.value[Task[A1]](a)
|
||||||
|
case Left(msg) =>
|
||||||
|
val indented = msg.linesIterator.map(" " + _).mkString("\n")
|
||||||
|
sys.error(s"Invalid programmatic input:\n$indented")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
inline def settingKey[A1](inline description: String): SettingKey[A1] =
|
inline def settingKey[A1](inline description: String): SettingKey[A1] =
|
||||||
${ std.KeyMacro.settingKeyImpl[A1]('description) }
|
${ std.KeyMacro.settingKeyImpl[A1]('description) }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ abstract class AutoPlugin extends Plugins.Basic with PluginsFunctions {
|
||||||
/**
|
/**
|
||||||
* This AutoPlugin requires the plugins the Plugins matcher returned by this method. See [[trigger]].
|
* This AutoPlugin requires the plugins the Plugins matcher returned by this method. See [[trigger]].
|
||||||
*/
|
*/
|
||||||
def requires: Plugins = ???
|
def requires: Plugins = Plugins.defaultRequires
|
||||||
// plugins.JvmPlugin
|
// plugins.JvmPlugin
|
||||||
|
|
||||||
val label: String = getClass.getName.stripSuffix("$")
|
val label: String = getClass.getName.stripSuffix("$")
|
||||||
|
|
@ -163,6 +163,8 @@ sealed trait PluginsFunctions {
|
||||||
|
|
||||||
object Plugins extends PluginsFunctions {
|
object Plugins extends PluginsFunctions {
|
||||||
|
|
||||||
|
private[sbt] var defaultRequires: Plugins = _
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the available auto plugins `defined`, returns a function that selects [[AutoPlugin]]s for the provided [[AutoPlugin]]s.
|
* Given the available auto plugins `defined`, returns a function that selects [[AutoPlugin]]s for the provided [[AutoPlugin]]s.
|
||||||
* The [[AutoPlugin]]s are topologically sorted so that a required [[AutoPlugin]] comes before its requiring [[AutoPlugin]].
|
* The [[AutoPlugin]]s are topologically sorted so that a required [[AutoPlugin]] comes before its requiring [[AutoPlugin]].
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,8 @@ object Previous {
|
||||||
// private[sbt] def task: ScopedKey[Task[T]] = key.task
|
// private[sbt] def task: ScopedKey[Task[T]] = key.task
|
||||||
|
|
||||||
lazy val stamped: JsonFormat[T] =
|
lazy val stamped: JsonFormat[T] =
|
||||||
StampedFormat.withStamp(key.task.key.classTag.toString)(format)
|
StampedFormat.withStamp(key.task.key.manifest.toString)(format)
|
||||||
|
|
||||||
def setTask(newTask: ScopedKey[Task[T]]) = new Referenced(newTask, format)
|
def setTask(newTask: ScopedKey[Task[T]]) = new Referenced(newTask, format)
|
||||||
private[sbt] def read(streams: Streams): Option[T] =
|
private[sbt] def read(streams: Streams): Option[T] =
|
||||||
try Option(streams(key.cacheKey).cacheStoreFactory.make(StreamName).read[T]()(stamped))
|
try Option(streams(key.cacheKey).cacheStoreFactory.make(StreamName).read[T]()(stamped))
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,13 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.Locale
|
||||||
import sbt.librarymanagement.Configuration
|
import sbt.librarymanagement.Configuration
|
||||||
import sbt.Def.{ Flattened, Initialize, ScopedKey, Setting }
|
import sbt.Def.{ Flattened, Initialize, ScopedKey, Setting }
|
||||||
import sbt.internal.util.Dag
|
import sbt.internal.util.Dag
|
||||||
|
import sbt.internal.util.complete.Parser
|
||||||
import sbt.internal.util.complete.DefaultParsers
|
import sbt.internal.util.complete.DefaultParsers
|
||||||
|
import Scope.{ Global, ThisScope }
|
||||||
|
|
||||||
sealed trait ProjectDefinition[PR <: ProjectReference] {
|
sealed trait ProjectDefinition[PR <: ProjectReference] {
|
||||||
|
|
||||||
|
|
@ -158,6 +161,19 @@ sealed trait Project extends ProjectDefinition[ProjectReference] with CompositeP
|
||||||
/** Definitively set the [[ProjectOrigin]] for this project. */
|
/** Definitively set the [[ProjectOrigin]] for this project. */
|
||||||
private[sbt] def setProjectOrigin(origin: ProjectOrigin): Project = copy(projectOrigin = origin)
|
private[sbt] def setProjectOrigin(origin: ProjectOrigin): Project = copy(projectOrigin = origin)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the given functions to this Project.
|
||||||
|
* The second function is applied to the result of applying the first to this Project and so on.
|
||||||
|
* The intended use is a convenience for applying default configuration provided by a plugin.
|
||||||
|
*/
|
||||||
|
def configure(transforms: (Project => Project)*): Project =
|
||||||
|
Function.chain(transforms)(this)
|
||||||
|
|
||||||
|
def withId(id: String): Project = copy(id = id)
|
||||||
|
|
||||||
|
/** Sets the base directory for this project. */
|
||||||
|
def in(dir: File): Project = copy(base = dir)
|
||||||
|
|
||||||
private[sbt] def copy(
|
private[sbt] def copy(
|
||||||
id: String = id,
|
id: String = id,
|
||||||
base: File = base,
|
base: File = base,
|
||||||
|
|
@ -180,9 +196,52 @@ sealed trait Project extends ProjectDefinition[ProjectReference] with CompositeP
|
||||||
autoPlugins,
|
autoPlugins,
|
||||||
projectOrigin
|
projectOrigin
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private[sbt] def resolveBuild(resolveRef: ProjectReference => ProjectReference): Project =
|
||||||
|
def resolveRefs(prs: Seq[ProjectReference]) = prs map resolveRef
|
||||||
|
def resolveDeps(ds: Seq[ClasspathDep[ProjectReference]]) = ds map resolveDep
|
||||||
|
def resolveDep(d: ClasspathDep[ProjectReference]) =
|
||||||
|
ClasspathDep.ClasspathDependency(resolveRef(d.project), d.configuration)
|
||||||
|
copy(
|
||||||
|
aggregate = resolveRefs(aggregate),
|
||||||
|
dependencies = resolveDeps(dependencies),
|
||||||
|
)
|
||||||
|
|
||||||
|
private[sbt] def resolve(resolveRef: ProjectReference => ProjectRef): ResolvedProject =
|
||||||
|
def resolveRefs(prs: Seq[ProjectReference]) = prs.map(resolveRef)
|
||||||
|
def resolveDeps(ds: Seq[ClasspathDep[ProjectReference]]) = ds.map(resolveDep)
|
||||||
|
def resolveDep(d: ClasspathDep[ProjectReference]) =
|
||||||
|
ClasspathDep.ResolvedClasspathDependency(resolveRef(d.project), d.configuration)
|
||||||
|
Project.resolved(
|
||||||
|
id,
|
||||||
|
base,
|
||||||
|
aggregate = resolveRefs(aggregate),
|
||||||
|
dependencies = resolveDeps(dependencies),
|
||||||
|
settings,
|
||||||
|
configurations,
|
||||||
|
plugins,
|
||||||
|
autoPlugins,
|
||||||
|
projectOrigin
|
||||||
|
)
|
||||||
end Project
|
end Project
|
||||||
|
|
||||||
object Project:
|
object Project:
|
||||||
|
def apply(id: String, base: File): Project =
|
||||||
|
unresolved(id, base, Nil, Nil, Nil, Nil, Plugins.empty, Nil, ProjectOrigin.Organic)
|
||||||
|
|
||||||
|
/** This is a variation of def apply that mixes in GeneratedRootProject. */
|
||||||
|
private[sbt] def mkGeneratedRoot(
|
||||||
|
id: String,
|
||||||
|
base: File,
|
||||||
|
aggregate: Seq[ProjectReference]
|
||||||
|
): Project =
|
||||||
|
validProjectID(id).foreach(errMsg => sys.error(s"Invalid project ID: $errMsg"))
|
||||||
|
val plugins = Plugins.empty
|
||||||
|
val origin = ProjectOrigin.GenericRoot
|
||||||
|
new ProjectDef(id, base, aggregate, Nil, Nil, Nil, plugins, Nil, origin)
|
||||||
|
with Project
|
||||||
|
with GeneratedRootProject
|
||||||
|
|
||||||
private abstract class ProjectDef[PR <: ProjectReference](
|
private abstract class ProjectDef[PR <: ProjectReference](
|
||||||
val id: String,
|
val id: String,
|
||||||
val base: File,
|
val base: File,
|
||||||
|
|
@ -198,7 +257,9 @@ object Project:
|
||||||
Dag.topologicalSort(configurations)(_.extendsConfigs)
|
Dag.topologicalSort(configurations)(_.extendsConfigs)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def unresolved(
|
// Data structure representing an unresolved Project in terms of the project references.
|
||||||
|
// This is created in build.sbt by the build user.
|
||||||
|
private[sbt] def unresolved(
|
||||||
id: String,
|
id: String,
|
||||||
base: File,
|
base: File,
|
||||||
aggregate: Seq[ProjectReference],
|
aggregate: Seq[ProjectReference],
|
||||||
|
|
@ -208,7 +269,7 @@ object Project:
|
||||||
plugins: Plugins,
|
plugins: Plugins,
|
||||||
autoPlugins: Seq[AutoPlugin],
|
autoPlugins: Seq[AutoPlugin],
|
||||||
origin: ProjectOrigin
|
origin: ProjectOrigin
|
||||||
): Project = {
|
): Project =
|
||||||
validProjectID(id).foreach(errMsg => sys.error("Invalid project ID: " + errMsg))
|
validProjectID(id).foreach(errMsg => sys.error("Invalid project ID: " + errMsg))
|
||||||
new ProjectDef[ProjectReference](
|
new ProjectDef[ProjectReference](
|
||||||
id,
|
id,
|
||||||
|
|
@ -221,11 +282,106 @@ object Project:
|
||||||
autoPlugins,
|
autoPlugins,
|
||||||
origin
|
origin
|
||||||
) with Project
|
) with Project
|
||||||
}
|
|
||||||
|
// Data structure representing resolved Project in terms of references to
|
||||||
|
// other projects in dependencies etc.
|
||||||
|
private def resolved(
|
||||||
|
id: String,
|
||||||
|
base: File,
|
||||||
|
aggregate: Seq[ProjectRef],
|
||||||
|
dependencies: Seq[ClasspathDep[ProjectRef]],
|
||||||
|
settings: Seq[Def.Setting[_]],
|
||||||
|
configurations: Seq[Configuration],
|
||||||
|
plugins: Plugins,
|
||||||
|
autoPlugins: Seq[AutoPlugin],
|
||||||
|
origin: ProjectOrigin
|
||||||
|
): ResolvedProject =
|
||||||
|
new ProjectDef[ProjectRef](
|
||||||
|
id,
|
||||||
|
base,
|
||||||
|
aggregate,
|
||||||
|
dependencies,
|
||||||
|
settings,
|
||||||
|
configurations,
|
||||||
|
plugins,
|
||||||
|
autoPlugins,
|
||||||
|
origin
|
||||||
|
) with ResolvedProject
|
||||||
|
|
||||||
/** Returns None if `id` is a valid Project ID or Some containing the parser error message if it is not. */
|
/** Returns None if `id` is a valid Project ID or Some containing the parser error message if it is not. */
|
||||||
def validProjectID(id: String): Option[String] =
|
def validProjectID(id: String): Option[String] =
|
||||||
DefaultParsers.parse(id, DefaultParsers.ID).left.toOption
|
DefaultParsers.parse(id, DefaultParsers.ID).left.toOption
|
||||||
|
|
||||||
|
private[this] def validProjectIDStart(id: String): Boolean =
|
||||||
|
DefaultParsers.parse(id, DefaultParsers.IDStart).isRight
|
||||||
|
|
||||||
|
def fillTaskAxis(scoped: ScopedKey[_]): ScopedKey[_] =
|
||||||
|
ScopedKey(Scope.fillTaskAxis(scoped.scope, scoped.key), scoped.key)
|
||||||
|
|
||||||
|
def mapScope(f: Scope => Scope): [a] => ScopedKey[a] => ScopedKey[a] =
|
||||||
|
[a] => (k: ScopedKey[a]) => ScopedKey(f(k.scope), k.key)
|
||||||
|
|
||||||
|
def transform(g: Scope => Scope, ss: Seq[Def.Setting[_]]): Seq[Def.Setting[_]] =
|
||||||
|
val f = mapScope(g)
|
||||||
|
ss.map { setting =>
|
||||||
|
setting.mapKey(f).mapReferenced(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
def transformRef(g: Scope => Scope, ss: Seq[Def.Setting[_]]): Seq[Def.Setting[_]] =
|
||||||
|
val f = mapScope(g)
|
||||||
|
ss.map(_ mapReferenced f)
|
||||||
|
|
||||||
|
def inThisBuild(ss: Seq[Setting[_]]): Seq[Setting[_]] =
|
||||||
|
inScope(ThisScope.copy(project = Select(ThisBuild)))(ss)
|
||||||
|
|
||||||
|
private[sbt] def inThisBuild[T](i: Initialize[T]): Initialize[T] =
|
||||||
|
inScope(ThisScope.copy(project = Select(ThisBuild)), i)
|
||||||
|
|
||||||
|
private[sbt] def inConfig[T](conf: Configuration, i: Initialize[T]): Initialize[T] =
|
||||||
|
inScope(ThisScope.copy(config = Select(conf)), i)
|
||||||
|
|
||||||
|
def inTask(t: Scoped)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
|
||||||
|
inScope(ThisScope.copy(task = Select(t.key)))(ss)
|
||||||
|
|
||||||
|
private[sbt] def inTask[A](t: Scoped, i: Initialize[A]): Initialize[A] =
|
||||||
|
inScope(ThisScope.copy(task = Select(t.key)), i)
|
||||||
|
|
||||||
|
def inScope(scope: Scope)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
|
||||||
|
Project.transform(Scope.replaceThis(scope), ss)
|
||||||
|
|
||||||
|
private[sbt] def inScope[A](scope: Scope, i: Initialize[A]): Initialize[A] =
|
||||||
|
i.mapReferenced(Project.mapScope(Scope.replaceThis(scope)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a String so that it is suitable for use as a dependency management module identifier.
|
||||||
|
* This is a best effort implementation, since valid characters are not documented or consistent.
|
||||||
|
*/
|
||||||
|
def normalizeModuleID(id: String): String = normalizeBase(id)
|
||||||
|
|
||||||
|
/** Constructs a valid Project ID based on `id` and returns it in Right or returns the error message in Left if one cannot be constructed. */
|
||||||
|
private[sbt] def normalizeProjectID(id: String): Either[String, String] = {
|
||||||
|
val attempt = normalizeBase(id)
|
||||||
|
val refined =
|
||||||
|
if (attempt.length < 1) "root"
|
||||||
|
else if (!validProjectIDStart(attempt.substring(0, 1))) "root-" + attempt
|
||||||
|
else attempt
|
||||||
|
validProjectID(refined).toLeft(refined)
|
||||||
|
}
|
||||||
|
|
||||||
|
private[this] def normalizeBase(s: String) =
|
||||||
|
s.toLowerCase(Locale.ENGLISH).replaceAll("""\W+""", "-")
|
||||||
|
|
||||||
|
private[sbt] enum LoadAction:
|
||||||
|
case Return
|
||||||
|
case Current
|
||||||
|
case Plugins
|
||||||
|
|
||||||
|
private[sbt] lazy val loadActionParser: Parser[LoadAction] = {
|
||||||
|
import DefaultParsers.*
|
||||||
|
token(
|
||||||
|
Space ~> ("plugins" ^^^ LoadAction.Plugins | "return" ^^^ LoadAction.Return)
|
||||||
|
) ?? LoadAction.Current
|
||||||
|
}
|
||||||
end Project
|
end Project
|
||||||
|
|
||||||
sealed trait ResolvedProject extends ProjectDefinition[ProjectRef] {
|
sealed trait ResolvedProject extends ProjectDefinition[ProjectRef] {
|
||||||
|
|
@ -234,3 +390,5 @@ sealed trait ResolvedProject extends ProjectDefinition[ProjectRef] {
|
||||||
def autoPlugins: Seq[AutoPlugin]
|
def autoPlugins: Seq[AutoPlugin]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private[sbt] trait GeneratedRootProject
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import sbt.ConcurrentRestrictions.Tag
|
||||||
import sbt.Def.{ Initialize, ScopedKey, Setting, setting }
|
import sbt.Def.{ Initialize, ScopedKey, Setting, setting }
|
||||||
import std.TaskMacro
|
import std.TaskMacro
|
||||||
import std.TaskExtra.{ task => mktask, _ }
|
import std.TaskExtra.{ task => mktask, _ }
|
||||||
|
import scala.reflect.ManifestFactory
|
||||||
|
|
||||||
/** An abstraction on top of Settings for build configuration and task definition. */
|
/** An abstraction on top of Settings for build configuration and task definition. */
|
||||||
sealed trait Scoped extends Equals:
|
sealed trait Scoped extends Equals:
|
||||||
|
|
@ -195,7 +196,7 @@ sealed abstract class TaskKey[A1]
|
||||||
): Setting[Task[A1]] =
|
): Setting[Task[A1]] =
|
||||||
set0(
|
set0(
|
||||||
this.zipWith(other) { (ta1: Task[A1], ta2: Task[A2]) =>
|
this.zipWith(other) { (ta1: Task[A1], ta2: Task[A2]) =>
|
||||||
multT2Task((ta1, ta2)) map f.tupled
|
multT2Task((ta1, ta2)).mapN(f.tupled)
|
||||||
},
|
},
|
||||||
source
|
source
|
||||||
)
|
)
|
||||||
|
|
@ -204,7 +205,7 @@ sealed abstract class TaskKey[A1]
|
||||||
f: (A1, A2) => A1
|
f: (A1, A2) => A1
|
||||||
): Setting[Task[A1]] =
|
): Setting[Task[A1]] =
|
||||||
set(this.zipWith(other) { (ta1: Task[A1], ta2: Task[A2]) =>
|
set(this.zipWith(other) { (ta1: Task[A1], ta2: Task[A2]) =>
|
||||||
multT2Task((ta1, ta2)) map f.tupled
|
multT2Task((ta1, ta2)).mapN(f.tupled)
|
||||||
})
|
})
|
||||||
|
|
||||||
final def withRank(rank: Int): TaskKey[A1] =
|
final def withRank(rank: Int): TaskKey[A1] =
|
||||||
|
|
@ -440,6 +441,9 @@ object Scoped:
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def coerceToAnyTaskSeq(tasks: Seq[AnyInitTask]): Seq[Def.Initialize[Task[Any]]] =
|
||||||
|
tasks.asInstanceOf[Seq[Def.Initialize[Task[Any]]]]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enriches `Initialize[Task[S]]` types.
|
* Enriches `Initialize[Task[S]]` types.
|
||||||
*
|
*
|
||||||
|
|
@ -449,9 +453,13 @@ object Scoped:
|
||||||
final class RichInitializeTask[S](i: Initialize[Task[S]]) extends RichInitTaskBase[S, Task] {
|
final class RichInitializeTask[S](i: Initialize[Task[S]]) extends RichInitTaskBase[S, Task] {
|
||||||
protected def onTask[T](f: Task[S] => Task[T]): Initialize[Task[T]] = i apply f
|
protected def onTask[T](f: Task[S] => Task[T]): Initialize[Task[T]] = i apply f
|
||||||
|
|
||||||
def dependsOn(tasks: AnyInitTask*): Initialize[Task[S]] = {
|
def dependsOn[B1](task1: Initialize[Task[B1]]): Initialize[Task[S]] =
|
||||||
i.zipWith(Initialize.joinAny[Task](tasks))((thisTask, deps) => thisTask.dependsOn(deps: _*))
|
dependsOn(Seq[AnyInitTask](task1.asInstanceOf[AnyInitTask]))
|
||||||
}
|
|
||||||
|
def dependsOn(tasks: Seq[AnyInitTask]): Initialize[Task[S]] =
|
||||||
|
i.zipWith(
|
||||||
|
Initialize.joinAny[Task](coerceToAnyTaskSeq(tasks))
|
||||||
|
)((thisTask, deps) => thisTask.dependsOn(deps: _*))
|
||||||
|
|
||||||
def failure: Initialize[Task[Incomplete]] = i(_.failure)
|
def failure: Initialize[Task[Incomplete]] = i(_.failure)
|
||||||
def result: Initialize[Task[Result[S]]] = i(_.result)
|
def result: Initialize[Task[Result[S]]] = i(_.result)
|
||||||
|
|
@ -469,7 +477,9 @@ object Scoped:
|
||||||
tasks: Seq[AnyInitTask],
|
tasks: Seq[AnyInitTask],
|
||||||
key: AttributeKey[Seq[Task[_]]]
|
key: AttributeKey[Seq[Task[_]]]
|
||||||
): Initialize[Task[S]] =
|
): Initialize[Task[S]] =
|
||||||
Initialize.joinAny[Task](tasks).zipWith(i)((ts, i) => i.copy(info = i.info.set(key, ts)))
|
Initialize
|
||||||
|
.joinAny[Task](coerceToAnyTaskSeq(tasks))
|
||||||
|
.zipWith(i)((ts, i) => i.copy(info = i.info.set(key, ts)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -483,11 +493,10 @@ object Scoped:
|
||||||
|
|
||||||
protected def onTask[T](f: Task[S] => Task[T]): Initialize[InputTask[T]] = i(_ mapTask f)
|
protected def onTask[T](f: Task[S] => Task[T]): Initialize[InputTask[T]] = i(_ mapTask f)
|
||||||
|
|
||||||
def dependsOn(tasks: AnyInitTask*): Initialize[InputTask[S]] = {
|
def dependsOn(tasks: AnyInitTask*): Initialize[InputTask[S]] =
|
||||||
i.zipWith(Initialize.joinAny[Task](tasks))((thisTask, deps) =>
|
i.zipWith(Initialize.joinAny[Task](coerceToAnyTaskSeq(tasks)))((thisTask, deps) =>
|
||||||
thisTask.mapTask(_.dependsOn(deps: _*))
|
thisTask.mapTask(_.dependsOn(deps: _*))
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -538,7 +547,7 @@ object Scoped:
|
||||||
def mapFailure[T](f: Incomplete => T): Initialize[R[T]] = onTask(_.result map (f compose failM))
|
def mapFailure[T](f: Incomplete => T): Initialize[R[T]] = onTask(_.result map (f compose failM))
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnyInitTask = Initialize[Task[Any]]
|
type AnyInitTask = Initialize[Task[_]]
|
||||||
|
|
||||||
implicit def richTaskSeq[T](in: Seq[Initialize[Task[T]]]): RichTaskSeq[T] = new RichTaskSeq(in)
|
implicit def richTaskSeq[T](in: Seq[Initialize[Task[T]]]): RichTaskSeq[T] = new RichTaskSeq(in)
|
||||||
final class RichTaskSeq[T](keys: Seq[Initialize[Task[T]]]) {
|
final class RichTaskSeq[T](keys: Seq[Initialize[Task[T]]]) {
|
||||||
|
|
@ -549,7 +558,9 @@ object Scoped:
|
||||||
implicit def richAnyTaskSeq(in: Seq[AnyInitTask]): RichAnyTaskSeq = new RichAnyTaskSeq(in)
|
implicit def richAnyTaskSeq(in: Seq[AnyInitTask]): RichAnyTaskSeq = new RichAnyTaskSeq(in)
|
||||||
final class RichAnyTaskSeq(keys: Seq[AnyInitTask]) {
|
final class RichAnyTaskSeq(keys: Seq[AnyInitTask]) {
|
||||||
def dependOn: Initialize[Task[Unit]] =
|
def dependOn: Initialize[Task[Unit]] =
|
||||||
Initialize.joinAny[Task](keys).apply(deps => nop.dependsOn(deps: _*))
|
Initialize
|
||||||
|
.joinAny[Task](coerceToAnyTaskSeq(keys))
|
||||||
|
.apply(deps => nop.dependsOn(deps: _*))
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed abstract class RichTaskables[K[L[x]]](final val keys: K[Taskable])(using
|
sealed abstract class RichTaskables[K[L[x]]](final val keys: K[Taskable])(using
|
||||||
|
|
@ -761,6 +772,8 @@ object InputKey:
|
||||||
description: String = "",
|
description: String = "",
|
||||||
rank: Int = KeyRanks.DefaultInputRank
|
rank: Int = KeyRanks.DefaultInputRank
|
||||||
): InputKey[A1] =
|
): InputKey[A1] =
|
||||||
|
given mf: Manifest[InputTask[A1]] =
|
||||||
|
ManifestFactory.classType[InputTask[A1]](classOf[InputTask[A1]], manifest[A1])
|
||||||
apply(AttributeKey[InputTask[A1]](label, description, rank))
|
apply(AttributeKey[InputTask[A1]](label, description, rank))
|
||||||
|
|
||||||
def apply[A1: Manifest](
|
def apply[A1: Manifest](
|
||||||
|
|
@ -777,6 +790,8 @@ object InputKey:
|
||||||
extend1: Scoped,
|
extend1: Scoped,
|
||||||
extendN: Scoped*
|
extendN: Scoped*
|
||||||
): InputKey[A1] =
|
): InputKey[A1] =
|
||||||
|
given mf: Manifest[InputTask[A1]] =
|
||||||
|
ManifestFactory.classType[InputTask[A1]](classOf[InputTask[A1]], manifest[A1])
|
||||||
apply(AttributeKey[InputTask[A1]](label, description, extendScoped(extend1, extendN), rank))
|
apply(AttributeKey[InputTask[A1]](label, description, extendScoped(extend1, extendN), rank))
|
||||||
|
|
||||||
def apply[A1](akey: AttributeKey[InputTask[A1]]): InputKey[A1] =
|
def apply[A1](akey: AttributeKey[InputTask[A1]]): InputKey[A1] =
|
||||||
|
|
@ -791,6 +806,8 @@ object TaskKey:
|
||||||
description: String = "",
|
description: String = "",
|
||||||
rank: Int = KeyRanks.DefaultTaskRank
|
rank: Int = KeyRanks.DefaultTaskRank
|
||||||
): TaskKey[A1] =
|
): TaskKey[A1] =
|
||||||
|
given mf: Manifest[Task[A1]] =
|
||||||
|
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], manifest[A1])
|
||||||
apply(AttributeKey[Task[A1]](label, description, rank))
|
apply(AttributeKey[Task[A1]](label, description, rank))
|
||||||
|
|
||||||
def apply[A1: Manifest](
|
def apply[A1: Manifest](
|
||||||
|
|
@ -799,6 +816,8 @@ object TaskKey:
|
||||||
extend1: Scoped,
|
extend1: Scoped,
|
||||||
extendN: Scoped*
|
extendN: Scoped*
|
||||||
): TaskKey[A1] =
|
): TaskKey[A1] =
|
||||||
|
given mf: Manifest[Task[A1]] =
|
||||||
|
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], manifest[A1])
|
||||||
apply(AttributeKey[Task[A1]](label, description, extendScoped(extend1, extendN)))
|
apply(AttributeKey[Task[A1]](label, description, extendScoped(extend1, extendN)))
|
||||||
|
|
||||||
def apply[A1: Manifest](
|
def apply[A1: Manifest](
|
||||||
|
|
@ -808,12 +827,17 @@ object TaskKey:
|
||||||
extend1: Scoped,
|
extend1: Scoped,
|
||||||
extendN: Scoped*
|
extendN: Scoped*
|
||||||
): TaskKey[A1] =
|
): TaskKey[A1] =
|
||||||
|
given mf: Manifest[Task[A1]] =
|
||||||
|
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], manifest[A1])
|
||||||
apply(AttributeKey[Task[A1]](label, description, extendScoped(extend1, extendN), rank))
|
apply(AttributeKey[Task[A1]](label, description, extendScoped(extend1, extendN), rank))
|
||||||
|
|
||||||
def apply[A1](akey: AttributeKey[Task[A1]]): TaskKey[A1] =
|
def apply[A1](akey: AttributeKey[Task[A1]]): TaskKey[A1] =
|
||||||
Scoped.scopedTask(Scope.ThisScope, akey)
|
Scoped.scopedTask(Scope.ThisScope, akey)
|
||||||
|
|
||||||
def local[A1: Manifest]: TaskKey[A1] = apply[A1](AttributeKey.local[Task[A1]])
|
def local[A1: Manifest]: TaskKey[A1] =
|
||||||
|
given mf: Manifest[Task[A1]] =
|
||||||
|
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], manifest[A1])
|
||||||
|
apply[A1](AttributeKey.local[Task[A1]])
|
||||||
|
|
||||||
end TaskKey
|
end TaskKey
|
||||||
|
|
||||||
|
|
@ -821,8 +845,27 @@ end TaskKey
|
||||||
object SettingKey:
|
object SettingKey:
|
||||||
def apply[A1: Manifest: OptJsonWriter](
|
def apply[A1: Manifest: OptJsonWriter](
|
||||||
label: String,
|
label: String,
|
||||||
description: String = "",
|
): SettingKey[A1] =
|
||||||
rank: Int = KeyRanks.DefaultSettingRank
|
apply[A1](
|
||||||
|
label = label,
|
||||||
|
description = "",
|
||||||
|
rank = KeyRanks.DefaultSettingRank
|
||||||
|
)
|
||||||
|
|
||||||
|
def apply[A1: Manifest: OptJsonWriter](
|
||||||
|
label: String,
|
||||||
|
description: String,
|
||||||
|
): SettingKey[A1] =
|
||||||
|
apply[A1](
|
||||||
|
label = label,
|
||||||
|
description = description,
|
||||||
|
rank = KeyRanks.DefaultSettingRank,
|
||||||
|
)
|
||||||
|
|
||||||
|
def apply[A1: Manifest: OptJsonWriter](
|
||||||
|
label: String,
|
||||||
|
description: String,
|
||||||
|
rank: Int
|
||||||
): SettingKey[A1] =
|
): SettingKey[A1] =
|
||||||
apply(AttributeKey[A1](label, description, rank))
|
apply(AttributeKey[A1](label, description, rank))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,22 +153,6 @@ object InputWrapper:
|
||||||
unexpectedType(c)(pos, tpe)
|
unexpectedType(c)(pos, tpe)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Translates <task: TaskKey[T]>.previous(format) to Previous.runtime(<task>)(format).value */
|
|
||||||
def previousMacroImpl[T: c.WeakTypeTag](
|
|
||||||
using qctx: Quotes
|
|
||||||
)(format: c.Expr[sjsonnew.JsonFormat[T]]): c.Expr[Option[T]] = {
|
|
||||||
import c.universe._
|
|
||||||
c.macroApplication match {
|
|
||||||
case a @ Apply(Select(Apply(_, t :: Nil), _), _) =>
|
|
||||||
if (t.tpe <:< c.weakTypeOf[TaskKey[T]]) {
|
|
||||||
val tsTyped = c.Expr[TaskKey[T]](t)
|
|
||||||
val newTree = c.universe.reify { Previous.runtime[T](tsTyped.splice)(format.splice) }
|
|
||||||
wrapPrevious[T](c)(newTree, a.pos)
|
|
||||||
} else unexpectedType(c)(a.pos, t.tpe)
|
|
||||||
case x => ContextUtil.unexpectedTree(x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def unexpectedType(using qctx: Quotes)(pos: c.Position, tpe: c.Type) =
|
private def unexpectedType(using qctx: Quotes)(pos: c.Position, tpe: c.Type) =
|
||||||
c.abort(pos, s"Internal sbt error. Unexpected type ${tpe.widen}")
|
c.abort(pos, s"Internal sbt error. Unexpected type ${tpe.widen}")
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -77,15 +77,18 @@ object FullInstance:
|
||||||
flatten(nested)
|
flatten(nested)
|
||||||
|
|
||||||
override def flatten[A1](in: Initialize[Task[Initialize[Task[A1]]]]): Initialize[Task[A1]] =
|
override def flatten[A1](in: Initialize[Task[Initialize[Task[A1]]]]): Initialize[Task[A1]] =
|
||||||
type K[L[x]] =
|
FullInstance.flatten[A1](in)
|
||||||
AList.Tuple3K[Task[Initialize[Task[A1]]], Task[SS], [a] => Initialize[a] => Initialize[a]][
|
|
||||||
L
|
def flatten[A1](in: Initialize[Task[Initialize[Task[A1]]]]): Initialize[Task[A1]] =
|
||||||
]
|
type K[L[x]] =
|
||||||
Def.app[K, Task[A1]]((in, settingsData, Def.capturedTransformations)) {
|
AList.Tuple3K[Task[Initialize[Task[A1]]], Task[SS], [a] => Initialize[a] => Initialize[a]][
|
||||||
case (a: Task[Initialize[Task[A1]]], data: Task[SS], f) =>
|
L
|
||||||
import TaskExtra.multT2Task
|
]
|
||||||
(a, data).flatMap { case (a, d) => f(a) evaluate d }
|
Def.app[K, Task[A1]]((in, settingsData, Def.capturedTransformations)) {
|
||||||
}(AList.tuple3[Task[Initialize[Task[A1]]], Task[SS], [a] => Initialize[a] => Initialize[a]])
|
case (a: Task[Initialize[Task[A1]]], data: Task[SS], f) =>
|
||||||
|
import TaskExtra.multT2Task
|
||||||
|
(a, data).flatMapN { case (a, d) => f(a) evaluate d }
|
||||||
|
}(AList.tuple3[Task[Initialize[Task[A1]]], Task[SS], [a] => Initialize[a] => Initialize[a]])
|
||||||
|
|
||||||
def flattenFun[A1, A2](
|
def flattenFun[A1, A2](
|
||||||
in: Initialize[Task[A1 => Initialize[Task[A2]]]]
|
in: Initialize[Task[A1 => Initialize[Task[A2]]]]
|
||||||
|
|
@ -98,7 +101,7 @@ object FullInstance:
|
||||||
case (a: Task[A1 => Initialize[Task[A2]]] @unchecked, data: Task[SS] @unchecked, f) => {
|
case (a: Task[A1 => Initialize[Task[A2]]] @unchecked, data: Task[SS] @unchecked, f) => {
|
||||||
(s: A1) =>
|
(s: A1) =>
|
||||||
import TaskExtra.multT2Task
|
import TaskExtra.multT2Task
|
||||||
(a, data) flatMap { case (af, d) => f(af(s)) evaluate d }
|
(a, data) flatMapN { case (af, d) => f(af(s)) evaluate d }
|
||||||
}
|
}
|
||||||
}(
|
}(
|
||||||
AList.tuple3[Task[A1 => Initialize[Task[A2]]], Task[SS], [a] => Initialize[a] => Initialize[
|
AList.tuple3[Task[A1 => Initialize[Task[A2]]], Task[SS], [a] => Initialize[a] => Initialize[
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package sbt
|
package sbt
|
||||||
package std
|
package std
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.quoted.*
|
import scala.quoted.*
|
||||||
|
|
||||||
|
|
@ -59,9 +60,18 @@ private[sbt] object KeyMacro:
|
||||||
Expr.summon[OptJsonWriter[A1]].getOrElse(sys.error("OptJsonWriter[A] not found for $tpe")),
|
Expr.summon[OptJsonWriter[A1]].getOrElse(sys.error("OptJsonWriter[A] not found for $tpe")),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def projectImpl(using qctx: Quotes): Expr[Project] =
|
||||||
|
val name = Expr(definingValName(errorMsg2("project")))
|
||||||
|
'{
|
||||||
|
Project($name, new File($name))
|
||||||
|
}
|
||||||
|
|
||||||
private def errorMsg(methodName: String): String =
|
private def errorMsg(methodName: String): String =
|
||||||
s"""$methodName must be directly assigned to a val, such as `val x = $methodName[Int]("description")`."""
|
s"""$methodName must be directly assigned to a val, such as `val x = $methodName[Int]("description")`."""
|
||||||
|
|
||||||
|
private def errorMsg2(methodName: String): String =
|
||||||
|
s"""$methodName must be directly assigned to a val, such as `val x = ($methodName in file("core"))`."""
|
||||||
|
|
||||||
private def definingValName(errorMsg: String)(using qctx: Quotes): String =
|
private def definingValName(errorMsg: String)(using qctx: Quotes): String =
|
||||||
val term = enclosingTerm
|
val term = enclosingTerm
|
||||||
if term.isValDef then term.name
|
if term.isValDef then term.name
|
||||||
|
|
@ -75,5 +85,4 @@ private[sbt] object KeyMacro:
|
||||||
case sym if !sym.isTerm => enclosingTerm0(sym.owner)
|
case sym if !sym.isTerm => enclosingTerm0(sym.owner)
|
||||||
case _ => sym
|
case _ => sym
|
||||||
enclosingTerm0(Symbol.spliceOwner)
|
enclosingTerm0(Symbol.spliceOwner)
|
||||||
|
|
||||||
end KeyMacro
|
end KeyMacro
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import language.experimental.macros
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.reflect.internal.util.UndefinedPosition
|
import scala.reflect.internal.util.UndefinedPosition
|
||||||
import scala.quoted.*
|
import scala.quoted.*
|
||||||
|
import sjsonnew.JsonFormat
|
||||||
|
|
||||||
object TaskMacro:
|
object TaskMacro:
|
||||||
final val AssignInitName = "set"
|
final val AssignInitName = "set"
|
||||||
|
|
@ -76,23 +77,20 @@ object TaskMacro:
|
||||||
def taskDynMacroImpl[A1: Type](
|
def taskDynMacroImpl[A1: Type](
|
||||||
t: Expr[Initialize[Task[A1]]]
|
t: Expr[Initialize[Task[A1]]]
|
||||||
)(using qctx: Quotes): Expr[Initialize[Task[A1]]] =
|
)(using qctx: Quotes): Expr[Initialize[Task[A1]]] =
|
||||||
val convert1 = new FullConvert(qctx, 0)
|
val convert1 = new FullConvert(qctx, 1000)
|
||||||
convert1.contFlatMap[A1, F, Id](t, convert1.appExpr)
|
convert1.contFlatMap[A1, F, Id](t, convert1.appExpr)
|
||||||
|
|
||||||
/*
|
/** Translates <task: TaskKey[T]>.previous(format) to Previous.runtime(<task>)(format).value */
|
||||||
def taskIfMacroImpl[A: Type](
|
def previousImpl[A1: Type](t: Expr[TaskKey[A1]])(using
|
||||||
c: blackbox.Context
|
qctx: Quotes
|
||||||
)(a: c.Expr[A]): c.Expr[Initialize[Task[A]]] = {
|
): Expr[Option[A1]] =
|
||||||
import c.universe._
|
import qctx.reflect.*
|
||||||
a.tree match {
|
Expr.summon[JsonFormat[A1]] match
|
||||||
case Block(stat, If(cond, thenp, elsep)) =>
|
case Some(ev) =>
|
||||||
c.Expr[Initialize[Task[A]]](mkIfS(c)(Block(stat, cond), thenp, elsep))
|
'{
|
||||||
case If(cond, thenp, elsep) =>
|
InputWrapper.`wrapInitTask_\u2603\u2603`[Option[A1]](Previous.runtime[A1]($t)($ev))
|
||||||
c.Expr[Initialize[Task[A]]](mkIfS(c)(cond, thenp, elsep))
|
}
|
||||||
case x => ContextUtil.unexpectedTree(x)
|
case _ => report.errorAndAbort(s"JsonFormat[${Type.of[A1]}] missing")
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Implementation of := macro for settings. */
|
/** Implementation of := macro for settings. */
|
||||||
def settingAssignMacroImpl[A1: Type](rec: Expr[Scoped.DefinableSetting[A1]], v: Expr[A1])(using
|
def settingAssignMacroImpl[A1: Type](rec: Expr[Scoped.DefinableSetting[A1]], v: Expr[A1])(using
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ import sbt.internal.util.complete.DefaultParsers
|
||||||
import sbt.{ Def, InputTask, Task }
|
import sbt.{ Def, InputTask, Task }
|
||||||
import sbt.Def.parsed
|
import sbt.Def.parsed
|
||||||
import sbt.Def.value
|
import sbt.Def.value
|
||||||
|
import sbt.Def.previous
|
||||||
|
import sbt.util.CacheImplicits.given
|
||||||
|
|
||||||
object UseTask:
|
object UseTask:
|
||||||
val set = Def.setting { 23 }
|
val set = Def.setting { 23 }
|
||||||
|
|
@ -42,6 +44,7 @@ object Assign {
|
||||||
val ak = taskKey[Int]("a")
|
val ak = taskKey[Int]("a")
|
||||||
val bk = taskKey[Seq[Int]]("b")
|
val bk = taskKey[Seq[Int]]("b")
|
||||||
val ck = settingKey[File]("c")
|
val ck = settingKey[File]("c")
|
||||||
|
val intTask = taskKey[Int]("int")
|
||||||
val sk = taskKey[Set[_]]("s")
|
val sk = taskKey[Set[_]]("s")
|
||||||
val bgList = taskKey[Seq[Int]]("")
|
val bgList = taskKey[Seq[Int]]("")
|
||||||
|
|
||||||
|
|
@ -76,6 +79,10 @@ object Assign {
|
||||||
bgList := { mk.value.toString.toList.map(_.toInt) },
|
bgList := { mk.value.toString.toList.map(_.toInt) },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val sd = Def.settingDyn {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
|
||||||
val zz = Def.task {
|
val zz = Def.task {
|
||||||
mk.value + tk.value + mk.value + tk.value + mk.value + tk.value + mk.value + tk.value + mk.value + tk.value + mk.value + tk.value
|
mk.value + tk.value + mk.value + tk.value + mk.value + tk.value + mk.value + tk.value + mk.value + tk.value + mk.value + tk.value
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,13 @@
|
||||||
|
|
||||||
// DO NOT EDIT MANUALLY
|
// DO NOT EDIT MANUALLY
|
||||||
package sbt
|
package sbt
|
||||||
|
/**
|
||||||
|
* Indicate whether the project was created organically, synthesized by a plugin,
|
||||||
|
* or is a "generic root" project supplied by sbt when a project doesn't exist for `file(".")`.
|
||||||
|
* Type for AutoPlugin's trigger method.
|
||||||
|
* Determines whether an AutoPlugin will be activated for a project when the
|
||||||
|
* `requires` clause is satisfied.
|
||||||
|
*/
|
||||||
final class JavaVersion private (
|
final class JavaVersion private (
|
||||||
val numbers: Vector[Long],
|
val numbers: Vector[Long],
|
||||||
val tags: Vector[String],
|
val tags: Vector[String],
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,15 @@
|
||||||
|
|
||||||
// DO NOT EDIT MANUALLY
|
// DO NOT EDIT MANUALLY
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type for AutoPlugin's trigger method.
|
* Type for AutoPlugin's trigger method.
|
||||||
* Determines whether an AutoPlugin will be activated for a project when the
|
* Determines whether an AutoPlugin will be activated for a project when the
|
||||||
* `requires` clause is satisfied.
|
* `requires` clause is satisfied.
|
||||||
*/
|
*/
|
||||||
sealed abstract class PluginTrigger extends Serializable
|
// sealed abstract class PluginTrigger extends Serializable
|
||||||
object PluginTrigger {
|
// object PluginTrigger {
|
||||||
|
|
||||||
|
// case object AllRequirements extends PluginTrigger
|
||||||
case object AllRequirements extends PluginTrigger
|
// case object NoTrigger extends PluginTrigger
|
||||||
case object NoTrigger extends PluginTrigger
|
// }
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@
|
||||||
|
|
||||||
// DO NOT EDIT MANUALLY
|
// DO NOT EDIT MANUALLY
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate whether the project was created organically, synthesized by a plugin,
|
* Indicate whether the project was created organically, synthesized by a plugin,
|
||||||
* or is a "generic root" project supplied by sbt when a project doesn't exist for `file(".")`.
|
* or is a "generic root" project supplied by sbt when a project doesn't exist for `file(".")`.
|
||||||
*/
|
*/
|
||||||
sealed abstract class ProjectOrigin extends Serializable
|
// sealed abstract class ProjectOrigin extends Serializable
|
||||||
object ProjectOrigin {
|
// object ProjectOrigin {
|
||||||
|
|
||||||
|
// case object Organic extends ProjectOrigin
|
||||||
case object Organic extends ProjectOrigin
|
// case object ExtraProject extends ProjectOrigin
|
||||||
case object ExtraProject extends ProjectOrigin
|
// case object DerivedProject extends ProjectOrigin
|
||||||
case object DerivedProject extends ProjectOrigin
|
// case object GenericRoot extends ProjectOrigin
|
||||||
case object GenericRoot extends ProjectOrigin
|
// }
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,20 @@ package sbt
|
||||||
|
|
||||||
## Indicate whether the project was created organically, synthesized by a plugin,
|
## Indicate whether the project was created organically, synthesized by a plugin,
|
||||||
## or is a "generic root" project supplied by sbt when a project doesn't exist for `file(".")`.
|
## or is a "generic root" project supplied by sbt when a project doesn't exist for `file(".")`.
|
||||||
enum ProjectOrigin {
|
#enum ProjectOrigin {
|
||||||
Organic
|
# Organic
|
||||||
ExtraProject
|
# ExtraProject
|
||||||
DerivedProject
|
# DerivedProject
|
||||||
GenericRoot
|
# GenericRoot
|
||||||
}
|
#}
|
||||||
|
|
||||||
## Type for AutoPlugin's trigger method.
|
## Type for AutoPlugin's trigger method.
|
||||||
## Determines whether an AutoPlugin will be activated for a project when the
|
## Determines whether an AutoPlugin will be activated for a project when the
|
||||||
## `requires` clause is satisfied.
|
## `requires` clause is satisfied.
|
||||||
enum PluginTrigger {
|
#enum PluginTrigger {
|
||||||
AllRequirements
|
# AllRequirements
|
||||||
NoTrigger
|
# NoTrigger
|
||||||
}
|
#}
|
||||||
|
|
||||||
type JavaVersion {
|
type JavaVersion {
|
||||||
numbers: [Long] @since("1.2.0")
|
numbers: [Long] @since("1.2.0")
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,21 @@ package sbt
|
||||||
import sbt.internal.DslEntry
|
import sbt.internal.DslEntry
|
||||||
import sbt.librarymanagement.Configuration
|
import sbt.librarymanagement.Configuration
|
||||||
|
|
||||||
private[sbt] trait BuildSyntax {
|
private[sbt] trait BuildSyntax:
|
||||||
import scala.language.experimental.macros
|
import scala.language.experimental.macros
|
||||||
def settingKey[A](description: String): SettingKey[A] = ???
|
|
||||||
// macro std.KeyMacro.settingKeyImpl[T]
|
/**
|
||||||
def taskKey[A](description: String): TaskKey[A] = ???
|
* Creates a new Project. This is a macro that expects to be assigned directly to a val.
|
||||||
// macro std.KeyMacro.taskKeyImpl[T]
|
* The name of the val is used as the project ID and the name of the base directory of the project.
|
||||||
def inputKey[A](description: String): InputKey[A] = ???
|
*/
|
||||||
// macro std.KeyMacro.inputKeyImpl[T]
|
inline def project: Project =
|
||||||
|
${ std.KeyMacro.projectImpl }
|
||||||
|
inline def settingKey[A1](inline description: String): SettingKey[A1] =
|
||||||
|
${ std.KeyMacro.settingKeyImpl[A1]('description) }
|
||||||
|
inline def taskKey[A1](inline description: String): TaskKey[A1] =
|
||||||
|
${ std.KeyMacro.taskKeyImpl[A1]('description) }
|
||||||
|
inline def inputKey[A1](inline description: String): InputKey[A1] =
|
||||||
|
${ std.KeyMacro.inputKeyImpl[A1]('description) }
|
||||||
|
|
||||||
def enablePlugins(ps: AutoPlugin*): DslEntry = DslEntry.DslEnablePlugins(ps)
|
def enablePlugins(ps: AutoPlugin*): DslEntry = DslEntry.DslEnablePlugins(ps)
|
||||||
def disablePlugins(ps: AutoPlugin*): DslEntry = DslEntry.DslDisablePlugins(ps)
|
def disablePlugins(ps: AutoPlugin*): DslEntry = DslEntry.DslDisablePlugins(ps)
|
||||||
|
|
@ -28,5 +35,6 @@ private[sbt] trait BuildSyntax {
|
||||||
|
|
||||||
implicit def sbtStateToUpperStateOps(s: State): UpperStateOps =
|
implicit def sbtStateToUpperStateOps(s: State): UpperStateOps =
|
||||||
new UpperStateOps.UpperStateOpsImpl(s)
|
new UpperStateOps.UpperStateOpsImpl(s)
|
||||||
}
|
end BuildSyntax
|
||||||
|
|
||||||
private[sbt] object BuildSyntax extends BuildSyntax
|
private[sbt] object BuildSyntax extends BuildSyntax
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ package sbt
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import sbt.Def.{ ScopedKey, Setting }
|
import sbt.Def.{ ScopedKey, Setting }
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.internal.Act
|
import sbt.internal.Act
|
||||||
import sbt.internal.CommandStrings._
|
import sbt.internal.CommandStrings._
|
||||||
|
|
|
||||||
|
|
@ -18,19 +18,20 @@ import org.apache.ivy.core.module.descriptor.ModuleDescriptor
|
||||||
import org.apache.ivy.core.module.id.ModuleRevisionId
|
import org.apache.ivy.core.module.id.ModuleRevisionId
|
||||||
import org.apache.logging.log4j.core.{ Appender => XAppender }
|
import org.apache.logging.log4j.core.{ Appender => XAppender }
|
||||||
import org.scalasbt.ipcsocket.Win32SecurityLevel
|
import org.scalasbt.ipcsocket.Win32SecurityLevel
|
||||||
import sbt.Def.{ Initialize, ScopedKey, Setting, SettingsDefinition }
|
import sbt.Def.{ Initialize, ScopedKey, Setting, SettingsDefinition, parsed }
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
import sbt.OptionSyntax._
|
import sbt.OptionSyntax._
|
||||||
import sbt.Project.{
|
import sbt.Project.{
|
||||||
inConfig,
|
|
||||||
inScope,
|
inScope,
|
||||||
inTask,
|
inTask,
|
||||||
richInitialize,
|
// richInitialize,
|
||||||
richInitializeTask,
|
// richInitializeTask,
|
||||||
richTaskSessionVar,
|
// richTaskSessionVar,
|
||||||
sbtRichTaskPromise
|
// sbtRichTaskPromise
|
||||||
}
|
}
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
import sbt.Scope.{ GlobalScope, ThisScope, fillTaskAxis }
|
import sbt.Scope.{ GlobalScope, ThisScope, fillTaskAxis }
|
||||||
|
import sbt.State.StateOpsImpl
|
||||||
import sbt.coursierint._
|
import sbt.coursierint._
|
||||||
import sbt.internal.CommandStrings.ExportStream
|
import sbt.internal.CommandStrings.ExportStream
|
||||||
import sbt.internal._
|
import sbt.internal._
|
||||||
|
|
@ -81,7 +82,7 @@ import sbt.nio.Keys._
|
||||||
import sbt.nio.file.syntax._
|
import sbt.nio.file.syntax._
|
||||||
import sbt.nio.file.{ FileTreeView, Glob, RecursiveGlob }
|
import sbt.nio.file.{ FileTreeView, Glob, RecursiveGlob }
|
||||||
import sbt.nio.Watch
|
import sbt.nio.Watch
|
||||||
import sbt.std.TaskExtra._
|
import sbt.std.TaskExtra.*
|
||||||
import sbt.testing.{ AnnotatedFingerprint, Framework, Runner, SubclassFingerprint }
|
import sbt.testing.{ AnnotatedFingerprint, Framework, Runner, SubclassFingerprint }
|
||||||
import sbt.util.CacheImplicits._
|
import sbt.util.CacheImplicits._
|
||||||
import sbt.util.InterfaceUtil.{ t2, toJavaFunction => f1 }
|
import sbt.util.InterfaceUtil.{ t2, toJavaFunction => f1 }
|
||||||
|
|
@ -308,7 +309,7 @@ object Defaults extends BuildCommon {
|
||||||
try onUnload.value(s)
|
try onUnload.value(s)
|
||||||
finally IO.delete(taskTemporaryDirectory.value)
|
finally IO.delete(taskTemporaryDirectory.value)
|
||||||
},
|
},
|
||||||
// extraLoggers is deprecated
|
// // extraLoggers is deprecated
|
||||||
SettingKey[ScopedKey[_] => Seq[XAppender]]("extraLoggers") :== { _ =>
|
SettingKey[ScopedKey[_] => Seq[XAppender]]("extraLoggers") :== { _ =>
|
||||||
Nil
|
Nil
|
||||||
},
|
},
|
||||||
|
|
@ -904,7 +905,7 @@ object Defaults extends BuildCommon {
|
||||||
tastyFiles := Def.taskIf {
|
tastyFiles := Def.taskIf {
|
||||||
if (ScalaArtifacts.isScala3(scalaVersion.value)) {
|
if (ScalaArtifacts.isScala3(scalaVersion.value)) {
|
||||||
val _ = compile.value
|
val _ = compile.value
|
||||||
val tastyFiles = classDirectory.value.**("*.tasty").get
|
val tastyFiles = classDirectory.value.**("*.tasty").get()
|
||||||
tastyFiles.map(_.getAbsoluteFile)
|
tastyFiles.map(_.getAbsoluteFile)
|
||||||
} else Nil
|
} else Nil
|
||||||
}.value,
|
}.value,
|
||||||
|
|
@ -919,7 +920,7 @@ object Defaults extends BuildCommon {
|
||||||
override def afterEarlyOutput(isSuccess: Boolean): Unit = {
|
override def afterEarlyOutput(isSuccess: Boolean): Unit = {
|
||||||
if (isSuccess) s.log.debug(s"[$mn / $c] early output is success")
|
if (isSuccess) s.log.debug(s"[$mn / $c] early output is success")
|
||||||
else s.log.debug(s"[$mn / $c] early output can't be made because of macros")
|
else s.log.debug(s"[$mn / $c] early output can't be made because of macros")
|
||||||
promise.complete(Value(isSuccess))
|
promise.complete(Result.Value(isSuccess))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -1090,11 +1091,10 @@ object Defaults extends BuildCommon {
|
||||||
override def triggeredMessage(s: WatchState) = trigMsg(s)
|
override def triggeredMessage(s: WatchState) = trigMsg(s)
|
||||||
override def watchService() = getService()
|
override def watchService() = getService()
|
||||||
override def watchSources(s: State) =
|
override def watchSources(s: State) =
|
||||||
EvaluateTask(Project structure s, key, s, base) match {
|
EvaluateTask(Project structure s, key, s, base) match
|
||||||
case Some((_, Value(ps))) => ps
|
case Some((_, Result.Value(ps))) => ps
|
||||||
case Some((_, Inc(i))) => throw i
|
case Some((_, Result.Inc(i))) => throw i
|
||||||
case None => sys.error("key not found: " + Def.displayFull(key))
|
case None => sys.error("key not found: " + Def.displayFull(key))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1252,22 +1252,34 @@ object Defaults extends BuildCommon {
|
||||||
_.name
|
_.name
|
||||||
).distinct) storeAs definedTestNames triggeredBy compile).value,
|
).distinct) storeAs definedTestNames triggeredBy compile).value,
|
||||||
testQuick / testFilter := testQuickFilter.value,
|
testQuick / testFilter := testQuickFilter.value,
|
||||||
executeTests := (
|
executeTests := {
|
||||||
Def.taskDyn {
|
import sbt.TupleSyntax.*
|
||||||
|
(
|
||||||
|
test / streams,
|
||||||
|
loadedTestFrameworks,
|
||||||
|
testLoader,
|
||||||
|
(test / testGrouping),
|
||||||
|
(test / testExecution),
|
||||||
|
(test / fullClasspath),
|
||||||
|
testForkedParallel,
|
||||||
|
(test / javaOptions),
|
||||||
|
(classLoaderLayeringStrategy),
|
||||||
|
thisProject,
|
||||||
|
).flatMapN { case (s, lt, tl, gp, ex, cp, fp, jo, clls, thisProj) =>
|
||||||
allTestGroupsTask(
|
allTestGroupsTask(
|
||||||
(test / streams).value,
|
s,
|
||||||
loadedTestFrameworks.value,
|
lt,
|
||||||
testLoader.value,
|
tl,
|
||||||
(test / testGrouping).value,
|
gp,
|
||||||
(test / testExecution).value,
|
ex,
|
||||||
(test / fullClasspath).value,
|
cp,
|
||||||
testForkedParallel.value,
|
fp,
|
||||||
(test / javaOptions).value,
|
jo,
|
||||||
(classLoaderLayeringStrategy).value,
|
clls,
|
||||||
projectId = s"${thisProject.value.id} / ",
|
projectId = s"${thisProj.id} / ",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
).value,
|
}.value,
|
||||||
// ((streams in test, loadedTestFrameworks, testLoader, testGrouping in test, testExecution in test, fullClasspath in test, javaHome in test, testForkedParallel, javaOptions in test) flatMap allTestGroupsTask).value,
|
// ((streams in test, loadedTestFrameworks, testLoader, testGrouping in test, testExecution in test, fullClasspath in test, javaHome in test, testForkedParallel, javaOptions in test) flatMap allTestGroupsTask).value,
|
||||||
Test / test / testResultLogger :== TestResultLogger.SilentWhenNoTests, // https://github.com/sbt/sbt/issues/1185
|
Test / test / testResultLogger :== TestResultLogger.SilentWhenNoTests, // https://github.com/sbt/sbt/issues/1185
|
||||||
test := {
|
test := {
|
||||||
|
|
@ -1285,6 +1297,7 @@ object Defaults extends BuildCommon {
|
||||||
finally close(testLoader.value)
|
finally close(testLoader.value)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
private def close(sbtLoader: ClassLoader): Unit = sbtLoader match {
|
private def close(sbtLoader: ClassLoader): Unit = sbtLoader match {
|
||||||
case u: AutoCloseable => u.close()
|
case u: AutoCloseable => u.close()
|
||||||
case c: ClasspathFilter => c.close()
|
case c: ClasspathFilter => c.close()
|
||||||
|
|
@ -1439,8 +1452,8 @@ object Defaults extends BuildCommon {
|
||||||
val s = streams.value
|
val s = streams.value
|
||||||
val filter = testFilter.value
|
val filter = testFilter.value
|
||||||
val config = testExecution.value
|
val config = testExecution.value
|
||||||
|
val st = state.value
|
||||||
implicit val display = Project.showContextKey(state.value)
|
given display: Show[ScopedKey[_]] = Project.showContextKey(st)
|
||||||
val modifiedOpts =
|
val modifiedOpts =
|
||||||
Tests.Filters(filter(selected)) +: Tests.Argument(frameworkOptions: _*) +: config.options
|
Tests.Filters(filter(selected)) +: Tests.Argument(frameworkOptions: _*) +: config.options
|
||||||
val newConfig = config.copy(options = modifiedOpts)
|
val newConfig = config.copy(options = modifiedOpts)
|
||||||
|
|
@ -1458,7 +1471,9 @@ object Defaults extends BuildCommon {
|
||||||
)
|
)
|
||||||
val taskName = display.show(resolvedScoped.value)
|
val taskName = display.show(resolvedScoped.value)
|
||||||
val trl = testResultLogger.value
|
val trl = testResultLogger.value
|
||||||
output.map(out => trl.run(s.log, out, taskName))
|
(Def
|
||||||
|
.value[Task[Tests.Output]] { output })
|
||||||
|
.map { out => trl.run(s.log, out, taskName) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1486,7 +1501,7 @@ object Defaults extends BuildCommon {
|
||||||
groups: Seq[Tests.Group],
|
groups: Seq[Tests.Group],
|
||||||
config: Tests.Execution,
|
config: Tests.Execution,
|
||||||
cp: Classpath,
|
cp: Classpath,
|
||||||
): Initialize[Task[Tests.Output]] = {
|
): Task[Tests.Output] = {
|
||||||
allTestGroupsTask(
|
allTestGroupsTask(
|
||||||
s,
|
s,
|
||||||
frameworks,
|
frameworks,
|
||||||
|
|
@ -1509,7 +1524,7 @@ object Defaults extends BuildCommon {
|
||||||
config: Tests.Execution,
|
config: Tests.Execution,
|
||||||
cp: Classpath,
|
cp: Classpath,
|
||||||
forkedParallelExecution: Boolean
|
forkedParallelExecution: Boolean
|
||||||
): Initialize[Task[Tests.Output]] = {
|
): Task[Tests.Output] = {
|
||||||
allTestGroupsTask(
|
allTestGroupsTask(
|
||||||
s,
|
s,
|
||||||
frameworks,
|
frameworks,
|
||||||
|
|
@ -1535,7 +1550,7 @@ object Defaults extends BuildCommon {
|
||||||
javaOptions: Seq[String],
|
javaOptions: Seq[String],
|
||||||
strategy: ClassLoaderLayeringStrategy,
|
strategy: ClassLoaderLayeringStrategy,
|
||||||
projectId: String
|
projectId: String
|
||||||
): Initialize[Task[Tests.Output]] = {
|
): Task[Tests.Output] = {
|
||||||
val processedOptions: Map[Tests.Group, Tests.ProcessedOptions] =
|
val processedOptions: Map[Tests.Group, Tests.ProcessedOptions] =
|
||||||
groups
|
groups
|
||||||
.map(group => group -> Tests.processOptions(config, group.tests.toVector, s.log))
|
.map(group => group -> Tests.processOptions(config, group.tests.toVector, s.log))
|
||||||
|
|
@ -1632,7 +1647,8 @@ object Defaults extends BuildCommon {
|
||||||
}
|
}
|
||||||
out.copy(summaries = summaries)
|
out.copy(summaries = summaries)
|
||||||
}
|
}
|
||||||
Def.value { result }
|
// Def.value[Task[Tests.Output]] {
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
def selectedFilter(args: Seq[String]): Seq[String => Boolean] = {
|
def selectedFilter(args: Seq[String]): Seq[String => Boolean] = {
|
||||||
|
|
@ -1710,13 +1726,20 @@ object Defaults extends BuildCommon {
|
||||||
packageTaskSettings(packageDoc, packageDocMappings) ++
|
packageTaskSettings(packageDoc, packageDocMappings) ++
|
||||||
Seq(Keys.`package` := packageBin.value)
|
Seq(Keys.`package` := packageBin.value)
|
||||||
|
|
||||||
def packageBinMappings = products map { _ flatMap Path.allSubpaths }
|
def packageBinMappings: Initialize[Task[Seq[(File, String)]]] =
|
||||||
def packageDocMappings = doc map { Path.allSubpaths(_).toSeq }
|
products.map { _ flatMap Path.allSubpaths }
|
||||||
def packageSrcMappings = concatMappings(resourceMappings, sourceMappings)
|
def packageDocMappings: Initialize[Task[Seq[(File, String)]]] =
|
||||||
|
doc.map { x => Path.allSubpaths(x).toSeq }
|
||||||
|
def packageSrcMappings: Initialize[Task[Seq[(File, String)]]] =
|
||||||
|
concatMappings(resourceMappings, sourceMappings)
|
||||||
|
|
||||||
private type Mappings = Initialize[Task[Seq[(File, String)]]]
|
private type Mappings = Initialize[Task[Seq[(File, String)]]]
|
||||||
def concatMappings(as: Mappings, bs: Mappings) =
|
def concatMappings(as: Mappings, bs: Mappings): Mappings =
|
||||||
(as zipWith bs)((a, b) => (a, b) map { case (a, b) => a ++ b })
|
as.zipWith(bs) { (a: Task[Seq[(File, String)]], b: Task[Seq[(File, String)]]) =>
|
||||||
|
(a, b).mapN { case (seq1: Seq[(File, String)], seq2: Seq[(File, String)]) =>
|
||||||
|
seq1 ++ seq2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// drop base directories, since there are no valid mappings for these
|
// drop base directories, since there are no valid mappings for these
|
||||||
def sourceMappings: Initialize[Task[Seq[(File, String)]]] =
|
def sourceMappings: Initialize[Task[Seq[(File, String)]]] =
|
||||||
|
|
@ -1752,7 +1775,7 @@ object Defaults extends BuildCommon {
|
||||||
excludes: Taskable[FileFilter]
|
excludes: Taskable[FileFilter]
|
||||||
): Initialize[Task[Seq[File]]] =
|
): Initialize[Task[Seq[File]]] =
|
||||||
Def.task {
|
Def.task {
|
||||||
dirs.toTask.value.descendantsExcept(filter.toTask.value, excludes.toTask.value).get
|
dirs.toTask.value.descendantsExcept(filter.toTask.value, excludes.toTask.value).get()
|
||||||
}
|
}
|
||||||
|
|
||||||
def relativeMappings( // forward to widened variant
|
def relativeMappings( // forward to widened variant
|
||||||
|
|
@ -1972,10 +1995,10 @@ object Defaults extends BuildCommon {
|
||||||
mainClassTask: Initialize[Task[Option[String]]],
|
mainClassTask: Initialize[Task[Option[String]]],
|
||||||
copyClasspath: Initialize[Boolean],
|
copyClasspath: Initialize[Boolean],
|
||||||
scalaRun: Initialize[Task[ScalaRun]]
|
scalaRun: Initialize[Task[ScalaRun]]
|
||||||
): Initialize[InputTask[JobHandle]] = {
|
): Initialize[InputTask[JobHandle]] =
|
||||||
import Def.parserToInput
|
|
||||||
val parser = Def.spaceDelimited()
|
val parser = Def.spaceDelimited()
|
||||||
Def.inputTask {
|
Def.inputTask {
|
||||||
|
val args = parser.parsed
|
||||||
val service = bgJobService.value
|
val service = bgJobService.value
|
||||||
val mainClass = mainClassTask.value getOrElse sys.error("No main class detected.")
|
val mainClass = mainClassTask.value getOrElse sys.error("No main class detected.")
|
||||||
val hashClasspath = (bgRun / bgHashClasspath).value
|
val hashClasspath = (bgRun / bgHashClasspath).value
|
||||||
|
|
@ -1986,17 +2009,14 @@ object Defaults extends BuildCommon {
|
||||||
service.copyClasspath(products.value, classpath.value, workingDir, hashClasspath)
|
service.copyClasspath(products.value, classpath.value, workingDir, hashClasspath)
|
||||||
else classpath.value
|
else classpath.value
|
||||||
val cp = data(files)
|
val cp = data(files)
|
||||||
val args = parser.parsed
|
scalaRun.value match
|
||||||
scalaRun.value match {
|
|
||||||
case r: Run =>
|
case r: Run =>
|
||||||
val loader = r.newLoader(cp)
|
val loader = r.newLoader(cp)
|
||||||
(Some(loader), wrapper(() => r.runWithLoader(loader, cp, mainClass, args, logger).get))
|
(Some(loader), wrapper(() => r.runWithLoader(loader, cp, mainClass, args, logger).get))
|
||||||
case sr =>
|
case sr =>
|
||||||
(None, wrapper(() => sr.run(mainClass, cp, args, logger).get))
|
(None, wrapper(() => sr.run(mainClass, cp, args, logger).get))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// runMain calls bgRunMain in the background and waits for the result.
|
// runMain calls bgRunMain in the background and waits for the result.
|
||||||
def foregroundRunMainTask: Initialize[InputTask[Unit]] =
|
def foregroundRunMainTask: Initialize[InputTask[Unit]] =
|
||||||
|
|
@ -2031,14 +2051,13 @@ object Defaults extends BuildCommon {
|
||||||
classpath: Initialize[Task[Classpath]],
|
classpath: Initialize[Task[Classpath]],
|
||||||
mainClassTask: Initialize[Task[Option[String]]],
|
mainClassTask: Initialize[Task[Option[String]]],
|
||||||
scalaRun: Initialize[Task[ScalaRun]]
|
scalaRun: Initialize[Task[ScalaRun]]
|
||||||
): Initialize[InputTask[Unit]] = {
|
): Initialize[InputTask[Unit]] =
|
||||||
import Def.parserToInput
|
|
||||||
val parser = Def.spaceDelimited()
|
val parser = Def.spaceDelimited()
|
||||||
Def.inputTask {
|
Def.inputTask {
|
||||||
|
val in = parser.parsed
|
||||||
val mainClass = mainClassTask.value getOrElse sys.error("No main class detected.")
|
val mainClass = mainClassTask.value getOrElse sys.error("No main class detected.")
|
||||||
scalaRun.value.run(mainClass, data(classpath.value), parser.parsed, streams.value.log).get
|
scalaRun.value.run(mainClass, data(classpath.value), in, streams.value.log).get
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def runnerTask: Setting[Task[ScalaRun]] = runner := runnerInit.value
|
def runnerTask: Setting[Task[ScalaRun]] = runner := runnerInit.value
|
||||||
|
|
||||||
|
|
@ -2837,7 +2856,7 @@ object Classpaths {
|
||||||
key: Scoped.ScopingSetting[SettingKey[T]], // should be just SettingKey[T] (mea culpa)
|
key: Scoped.ScopingSetting[SettingKey[T]], // should be just SettingKey[T] (mea culpa)
|
||||||
pkgTasks: Seq[TaskKey[_]],
|
pkgTasks: Seq[TaskKey[_]],
|
||||||
): Initialize[Seq[T]] =
|
): Initialize[Seq[T]] =
|
||||||
pkgTasks.map(pkg => key in pkg.scope in pkg).join
|
pkgTasks.map(pkg => (pkg.scope / pkg / key)).join
|
||||||
|
|
||||||
private[this] def publishGlobalDefaults =
|
private[this] def publishGlobalDefaults =
|
||||||
Defaults.globalDefaults(
|
Defaults.globalDefaults(
|
||||||
|
|
@ -2982,7 +3001,10 @@ object Classpaths {
|
||||||
Resolver.reorganizeAppResolvers(ars, uj, useMavenCentral)
|
Resolver.reorganizeAppResolvers(ars, uj, useMavenCentral)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
bootResolvers := (appConfiguration map bootRepositories).value,
|
bootResolvers := {
|
||||||
|
import Scoped.syntax.richInitialize
|
||||||
|
(appConfiguration map bootRepositories).value
|
||||||
|
},
|
||||||
fullResolvers :=
|
fullResolvers :=
|
||||||
(Def.task {
|
(Def.task {
|
||||||
val proj = projectResolver.value
|
val proj = projectResolver.value
|
||||||
|
|
@ -4547,26 +4569,21 @@ trait BuildExtra extends BuildCommon with DefExtra {
|
||||||
mainClass: String,
|
mainClass: String,
|
||||||
baseArguments: String*
|
baseArguments: String*
|
||||||
): Vector[Setting[_]] = {
|
): Vector[Setting[_]] = {
|
||||||
// TODO: Re-write to avoid InputTask.apply which is deprecated
|
|
||||||
// I tried "Def.spaceDelimited().parsed" (after importing Def.parserToInput)
|
|
||||||
// but it broke actions/run-task
|
|
||||||
// Maybe it needs to be defined inside a Def.inputTask?
|
|
||||||
@nowarn
|
|
||||||
def inputTask[T](f: TaskKey[Seq[String]] => Initialize[Task[T]]): Initialize[InputTask[T]] =
|
|
||||||
InputTask.apply(Def.value((s: State) => Def.spaceDelimited()))(f)
|
|
||||||
|
|
||||||
Vector(
|
Vector(
|
||||||
scoped := inputTask { result =>
|
scoped := (Def
|
||||||
initScoped(
|
.input((s: State) => Def.spaceDelimited())
|
||||||
scoped.scopedKey,
|
.flatMapTask { result =>
|
||||||
ClassLoaders.runner mapReferenced Project.mapScope(s => s.in(config))
|
initScoped(
|
||||||
).zipWith(Def.task { ((config / fullClasspath).value, streams.value, result.value) }) {
|
scoped.scopedKey,
|
||||||
(rTask, t) =>
|
ClassLoaders.runner mapReferenced Project.mapScope(s => s.in(config))
|
||||||
(t, rTask) map { case ((cp, s, args), r) =>
|
).zipWith(Def.task { ((config / fullClasspath).value, streams.value, result) }) {
|
||||||
r.run(mainClass, data(cp), baseArguments ++ args, s.log).get
|
(rTask, t) =>
|
||||||
}
|
(t, rTask) mapN { case ((cp, s, args), r) =>
|
||||||
}
|
r.run(mainClass, data(cp), baseArguments ++ args, s.log).get
|
||||||
}.evaluated
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.value
|
||||||
) ++ inTask(scoped)((config / forkOptions) := forkOptionsTask.value)
|
) ++ inTask(scoped)((config / forkOptions) := forkOptionsTask.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4584,7 +4601,7 @@ trait BuildExtra extends BuildCommon with DefExtra {
|
||||||
scoped.scopedKey,
|
scoped.scopedKey,
|
||||||
ClassLoaders.runner mapReferenced Project.mapScope(s => s.in(config))
|
ClassLoaders.runner mapReferenced Project.mapScope(s => s.in(config))
|
||||||
).zipWith(Def.task { ((config / fullClasspath).value, streams.value) }) { case (rTask, t) =>
|
).zipWith(Def.task { ((config / fullClasspath).value, streams.value) }) { case (rTask, t) =>
|
||||||
(t, rTask) map { case ((cp, s), r) =>
|
(t, rTask).mapN { case ((cp: Keys.Classpath, s: Streams), r: ScalaRun) =>
|
||||||
r.run(mainClass, data(cp), arguments, s.log).get
|
r.run(mainClass, data(cp), arguments, s.log).get
|
||||||
}
|
}
|
||||||
}.value
|
}.value
|
||||||
|
|
@ -4628,7 +4645,7 @@ trait BuildCommon {
|
||||||
final class RichPathFinder private[sbt] (s: PathFinder) {
|
final class RichPathFinder private[sbt] (s: PathFinder) {
|
||||||
|
|
||||||
/** Converts the `PathFinder` to a `Classpath`, which is an alias for `Seq[Attributed[File]]`. */
|
/** Converts the `PathFinder` to a `Classpath`, which is an alias for `Seq[Attributed[File]]`. */
|
||||||
def classpath: Classpath = Attributed blankSeq s.get
|
def classpath: Classpath = Attributed.blankSeq(s.get())
|
||||||
}
|
}
|
||||||
final class RichAttributed private[sbt] (s: Seq[Attributed[File]]) {
|
final class RichAttributed private[sbt] (s: Seq[Attributed[File]]) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@ import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
import sbt.Def.{ ScopedKey, Setting, dummyState }
|
import sbt.Def.{ ScopedKey, Setting, dummyState }
|
||||||
import sbt.Keys.{ TaskProgress => _, name => _, _ }
|
import sbt.Keys.{ TaskProgress => _, name => _, _ }
|
||||||
import sbt.Project.richInitializeTask
|
// import sbt.Project.richInitializeTask
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
import sbt.Scope.Global
|
import sbt.Scope.Global
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.internal.Aggregation.KeyValue
|
import sbt.internal.Aggregation.KeyValue
|
||||||
|
|
@ -390,17 +391,20 @@ object EvaluateTask {
|
||||||
def logIncomplete(result: Incomplete, state: State, streams: Streams): Unit = {
|
def logIncomplete(result: Incomplete, state: State, streams: Streams): Unit = {
|
||||||
val all = Incomplete linearize result
|
val all = Incomplete linearize result
|
||||||
val keyed =
|
val keyed =
|
||||||
all collect { case Incomplete(Some(key: ScopedKey[_]), _, msg, _, ex) => (key, msg, ex) }
|
all collect { case Incomplete(Some(key: ScopedKey[_]), _, msg, _, ex) =>
|
||||||
|
(key, msg, ex)
|
||||||
|
}
|
||||||
|
|
||||||
import ExceptionCategory._
|
import ExceptionCategory._
|
||||||
for ((key, msg, Some(ex)) <- keyed) {
|
for {
|
||||||
|
(key, msg, Some(ex)) <- keyed
|
||||||
|
} do
|
||||||
def log = getStreams(key, streams).log
|
def log = getStreams(key, streams).log
|
||||||
ExceptionCategory(ex) match {
|
ExceptionCategory(ex) match {
|
||||||
case AlreadyHandled => ()
|
case AlreadyHandled => ()
|
||||||
case m: MessageOnly => if (msg.isEmpty) log.error(m.message)
|
case m: MessageOnly => if (msg.isEmpty) log.error(m.message)
|
||||||
case f: Full => log.trace(f.exception)
|
case f: Full => log.trace(f.exception)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for ((key, msg, ex) <- keyed if msg.isDefined || ex.isDefined) {
|
for ((key, msg, ex) <- keyed if msg.isDefined || ex.isDefined) {
|
||||||
val msgString = (msg.toList ++ ex.toList.map(ErrorHandling.reducedToString)).mkString("\n\t")
|
val msgString = (msg.toList ++ ex.toList.map(ErrorHandling.reducedToString)).mkString("\n\t")
|
||||||
|
|
@ -633,7 +637,7 @@ object EvaluateTask {
|
||||||
val injectStreams: ScopedKey[_] => Seq[Setting[_]] = scoped =>
|
val injectStreams: ScopedKey[_] => Seq[Setting[_]] = scoped =>
|
||||||
if (scoped.key == streams.key) {
|
if (scoped.key == streams.key) {
|
||||||
Seq(scoped.scope / streams := {
|
Seq(scoped.scope / streams := {
|
||||||
(streamsManager map { mgr =>
|
(streamsManager.map { mgr =>
|
||||||
val stream = mgr(scoped)
|
val stream = mgr(scoped)
|
||||||
stream.open()
|
stream.open()
|
||||||
stream
|
stream
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import sbt.internal.util.AttributeKey
|
||||||
import sbt.util.Show
|
import sbt.util.Show
|
||||||
import std.Transform.DummyTaskMap
|
import std.Transform.DummyTaskMap
|
||||||
import sbt.EvaluateTask.extractedTaskConfig
|
import sbt.EvaluateTask.extractedTaskConfig
|
||||||
|
import sbt.ProjectExtra.setProject
|
||||||
import scala.annotation.nowarn
|
import scala.annotation.nowarn
|
||||||
|
|
||||||
final case class Extracted(
|
final case class Extracted(
|
||||||
|
|
@ -148,6 +149,7 @@ final case class Extracted(
|
||||||
state: State,
|
state: State,
|
||||||
sessionSettings: Seq[Setting[_]],
|
sessionSettings: Seq[Setting[_]],
|
||||||
): State = {
|
): State = {
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
val appendSettings =
|
val appendSettings =
|
||||||
Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, settings)
|
Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, settings)
|
||||||
val newStructure = Load.reapply(sessionSettings ++ appendSettings, structure)
|
val newStructure = Load.reapply(sessionSettings ++ appendSettings, structure)
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ object Keys {
|
||||||
val onLoadMessage = settingKey[String]("Message to display when the project is loaded.").withRank(DSetting)
|
val onLoadMessage = settingKey[String]("Message to display when the project is loaded.").withRank(DSetting)
|
||||||
val transformState = AttributeKey[State => State]("transformState", "State transformation to apply after tasks run.", DSetting)
|
val transformState = AttributeKey[State => State]("transformState", "State transformation to apply after tasks run.", DSetting)
|
||||||
|
|
||||||
val onComplete = settingKey[() => Unit]("Hook to run when task evaluation completes. The type of this setting is subject to change, pending the resolution of SI-2915.").withRank(DSetting)
|
val onComplete = Def.onComplete // settingKey[() => Unit]("Hook to run when task evaluation completes. The type of this setting is subject to change, pending the resolution of SI-2915.").withRank(DSetting)
|
||||||
|
|
||||||
// Command keys
|
// Command keys
|
||||||
val historyPath = SettingKey(BasicKeys.historyPath)
|
val historyPath = SettingKey(BasicKeys.historyPath)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
import sbt.BasicCommandStrings.{ JavaClient, Shell, Shutdown, TemplateCommand }
|
import sbt.BasicCommandStrings.{ JavaClient, Shell, Shutdown, TemplateCommand }
|
||||||
import sbt.Project.LoadAction
|
import sbt.Project.LoadAction
|
||||||
import sbt.compiler.EvalImports
|
import sbt.ProjectExtra.*
|
||||||
|
import sbt.internal.EvalImports
|
||||||
import sbt.internal.Aggregation.AnyKeys
|
import sbt.internal.Aggregation.AnyKeys
|
||||||
import sbt.internal.CommandStrings.BootCommand
|
import sbt.internal.CommandStrings.BootCommand
|
||||||
import sbt.internal._
|
import sbt.internal._
|
||||||
|
|
@ -41,10 +42,11 @@ import scala.concurrent.duration.Duration
|
||||||
import scala.util.control.NonFatal
|
import scala.util.control.NonFatal
|
||||||
|
|
||||||
/** This class is the entry point for sbt. */
|
/** This class is the entry point for sbt. */
|
||||||
final class xMain extends xsbti.AppMain {
|
final class xMain extends xsbti.AppMain:
|
||||||
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
||||||
new XMainConfiguration().run("xMain", configuration)
|
new XMainConfiguration().run("xMain", configuration)
|
||||||
}
|
end xMain
|
||||||
|
|
||||||
private[sbt] object xMain {
|
private[sbt] object xMain {
|
||||||
private[sbt] def dealiasBaseDirectory(config: xsbti.AppConfiguration): xsbti.AppConfiguration = {
|
private[sbt] def dealiasBaseDirectory(config: xsbti.AppConfiguration): xsbti.AppConfiguration = {
|
||||||
val dealiasedBase = config.baseDirectory.getCanonicalFile
|
val dealiasedBase = config.baseDirectory.getCanonicalFile
|
||||||
|
|
@ -56,6 +58,7 @@ private[sbt] object xMain {
|
||||||
override def provider: AppProvider = config.provider()
|
override def provider: AppProvider = config.provider()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private[sbt] def run(configuration: xsbti.AppConfiguration): xsbti.MainResult = {
|
private[sbt] def run(configuration: xsbti.AppConfiguration): xsbti.MainResult = {
|
||||||
try {
|
try {
|
||||||
import BasicCommandStrings.{ DashDashClient, DashDashServer, runEarly }
|
import BasicCommandStrings.{ DashDashClient, DashDashServer, runEarly }
|
||||||
|
|
@ -64,6 +67,7 @@ private[sbt] object xMain {
|
||||||
import sbt.internal.CommandStrings.{ BootCommand, DefaultsCommand, InitCommand }
|
import sbt.internal.CommandStrings.{ BootCommand, DefaultsCommand, InitCommand }
|
||||||
import sbt.internal.client.NetworkClient
|
import sbt.internal.client.NetworkClient
|
||||||
|
|
||||||
|
Plugins.defaultRequires = sbt.plugins.JvmPlugin
|
||||||
// if we detect -Dsbt.client=true or -client, run thin client.
|
// if we detect -Dsbt.client=true or -client, run thin client.
|
||||||
val clientModByEnv = SysProp.client
|
val clientModByEnv = SysProp.client
|
||||||
val userCommands = configuration.arguments
|
val userCommands = configuration.arguments
|
||||||
|
|
@ -127,8 +131,9 @@ private[sbt] object xMain {
|
||||||
)
|
)
|
||||||
.put(BasicKeys.detachStdio, detachStdio)
|
.put(BasicKeys.detachStdio, detachStdio)
|
||||||
val state = bootServerSocket match {
|
val state = bootServerSocket match {
|
||||||
case Some(l) => state0.put(Keys.bootServerSocket, l)
|
// todo: fix this
|
||||||
case _ => state0
|
// case Some(l) => state0.put(Keys.bootServerSocket, l)
|
||||||
|
case _ => state0
|
||||||
}
|
}
|
||||||
try StandardMain.runManaged(state)
|
try StandardMain.runManaged(state)
|
||||||
finally bootServerSocket.foreach(_.close())
|
finally bootServerSocket.foreach(_.close())
|
||||||
|
|
@ -557,10 +562,10 @@ object BuiltinCommands {
|
||||||
def continuous: Command = Continuous.continuous
|
def continuous: Command = Continuous.continuous
|
||||||
|
|
||||||
private[this] def loadedEval(s: State, arg: String): Unit = {
|
private[this] def loadedEval(s: State, arg: String): Unit = {
|
||||||
val extracted = Project extract s
|
val extracted = Project.extract(s)
|
||||||
import extracted._
|
import extracted._
|
||||||
val result =
|
val result =
|
||||||
session.currentEval().eval(arg, srcName = "<eval>", imports = autoImports(extracted))
|
session.currentEval().evalInfer(expression = arg, imports = autoImports(extracted))
|
||||||
s.log.info(s"ans: ${result.tpe} = ${result.getValue(currentLoader)}")
|
s.log.info(s"ans: ${result.tpe} = ${result.getValue(currentLoader)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -568,8 +573,8 @@ object BuiltinCommands {
|
||||||
val app = s.configuration.provider
|
val app = s.configuration.provider
|
||||||
val classpath = app.mainClasspath ++ app.scalaProvider.jars
|
val classpath = app.mainClasspath ++ app.scalaProvider.jars
|
||||||
val result = Load
|
val result = Load
|
||||||
.mkEval(classpath, s.baseDir, Nil)
|
.mkEval(classpath.map(_.toPath()), s.baseDir, Nil)
|
||||||
.eval(arg, srcName = "<eval>", imports = new EvalImports(Nil, ""))
|
.evalInfer(expression = arg, imports = EvalImports(Nil))
|
||||||
s.log.info(s"ans: ${result.tpe} = ${result.getValue(app.loader)}")
|
s.log.info(s"ans: ${result.tpe} = ${result.getValue(app.loader)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -646,7 +651,7 @@ object BuiltinCommands {
|
||||||
(s, sks) match {
|
(s, sks) match {
|
||||||
case (s, (pattern, Some(sks))) =>
|
case (s, (pattern, Some(sks))) =>
|
||||||
val (str, _, display) = extractLast(s)
|
val (str, _, display) = extractLast(s)
|
||||||
Output.lastGrep(sks, str.streams(s), pattern, printLast)(display)
|
Output.lastGrep(sks, str.streams(s), pattern, printLast)(using display)
|
||||||
keepLastLog(s)
|
keepLastLog(s)
|
||||||
case (s, (pattern, None)) =>
|
case (s, (pattern, None)) =>
|
||||||
for (logFile <- lastLogFile(s)) yield Output.lastGrep(logFile, pattern, printLast)
|
for (logFile <- lastLogFile(s)) yield Output.lastGrep(logFile, pattern, printLast)
|
||||||
|
|
@ -668,7 +673,8 @@ object BuiltinCommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
import Def.ScopedKey
|
import Def.ScopedKey
|
||||||
type KeysParser = Parser[Seq[ScopedKey[T]] forSome { type T }]
|
// type PolyStateKeysParser = [a] => State => Parser[Seq[ScopedKey[a]]]
|
||||||
|
type KeysParser = Parser[Seq[ScopedKey[Any]]]
|
||||||
|
|
||||||
val spacedAggregatedParser: State => KeysParser = (s: State) =>
|
val spacedAggregatedParser: State => KeysParser = (s: State) =>
|
||||||
Act.requireSession(s, token(Space) ~> Act.aggregatedKeyParser(s))
|
Act.requireSession(s, token(Space) ~> Act.aggregatedKeyParser(s))
|
||||||
|
|
@ -728,7 +734,7 @@ object BuiltinCommands {
|
||||||
|
|
||||||
private[this] def lastImpl(s: State, sks: AnyKeys, sid: Option[String]): State = {
|
private[this] def lastImpl(s: State, sks: AnyKeys, sid: Option[String]): State = {
|
||||||
val (str, _, display) = extractLast(s)
|
val (str, _, display) = extractLast(s)
|
||||||
Output.last(sks, str.streams(s), printLast, sid)(display)
|
Output.last(sks, str.streams(s), printLast, sid)(using display)
|
||||||
keepLastLog(s)
|
keepLastLog(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -759,7 +765,7 @@ object BuiltinCommands {
|
||||||
def printLast: Seq[String] => Unit = _ foreach println
|
def printLast: Seq[String] => Unit = _ foreach println
|
||||||
|
|
||||||
def autoImports(extracted: Extracted): EvalImports =
|
def autoImports(extracted: Extracted): EvalImports =
|
||||||
new EvalImports(imports(extracted), "<auto-imports>")
|
new EvalImports(imports(extracted).map(_._1)) // <auto-imports>
|
||||||
|
|
||||||
def imports(extracted: Extracted): Seq[(String, Int)] = {
|
def imports(extracted: Extracted): Seq[(String, Int)] = {
|
||||||
val curi = extracted.currentRef.build
|
val curi = extracted.currentRef.build
|
||||||
|
|
@ -864,7 +870,7 @@ object BuiltinCommands {
|
||||||
@tailrec
|
@tailrec
|
||||||
private[this] def doLoadFailed(s: State, loadArg: String): State = {
|
private[this] def doLoadFailed(s: State, loadArg: String): State = {
|
||||||
s.log.warn("Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? (default: r)")
|
s.log.warn("Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? (default: r)")
|
||||||
val result =
|
val result: Int =
|
||||||
try
|
try
|
||||||
ITerminal.get.withRawInput(System.in.read) match {
|
ITerminal.get.withRawInput(System.in.read) match {
|
||||||
case -1 => 'q'.toInt
|
case -1 => 'q'.toInt
|
||||||
|
|
@ -944,7 +950,7 @@ object BuiltinCommands {
|
||||||
state.log.info(s"welcome to sbt $appVersion ($javaVersion)")
|
state.log.info(s"welcome to sbt $appVersion ($javaVersion)")
|
||||||
}
|
}
|
||||||
|
|
||||||
def doLoadProject(s0: State, action: LoadAction.Value): State = {
|
def doLoadProject(s0: State, action: LoadAction): State = {
|
||||||
welcomeBanner(s0)
|
welcomeBanner(s0)
|
||||||
checkSBTVersionChanged(s0)
|
checkSBTVersionChanged(s0)
|
||||||
val (s1, base) = Project.loadAction(SessionVar.clear(s0), action)
|
val (s1, base) = Project.loadAction(SessionVar.clear(s0), action)
|
||||||
|
|
@ -954,7 +960,7 @@ object BuiltinCommands {
|
||||||
val (eval, structure) =
|
val (eval, structure) =
|
||||||
try Load.defaultLoad(s2, base, s2.log, Project.inPluginProject(s2), Project.extraBuilds(s2))
|
try Load.defaultLoad(s2, base, s2.log, Project.inPluginProject(s2), Project.extraBuilds(s2))
|
||||||
catch {
|
catch {
|
||||||
case ex: compiler.EvalException =>
|
case ex: sbt.internal.EvalException =>
|
||||||
s0.log.debug(ex.getMessage)
|
s0.log.debug(ex.getMessage)
|
||||||
ex.getStackTrace map (ste => s"\tat $ste") foreach (s0.log.debug(_))
|
ex.getStackTrace map (ste => s"\tat $ste") foreach (s0.log.debug(_))
|
||||||
ex.setStackTrace(Array.empty)
|
ex.setStackTrace(Array.empty)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import sbt.BasicCommandStrings.{ StashOnFailure, networkExecPrefix }
|
import sbt.BasicCommandStrings.{ StashOnFailure, networkExecPrefix }
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
import sbt.internal.langserver.ErrorCodes
|
import sbt.internal.langserver.ErrorCodes
|
||||||
import sbt.internal.nio.CheckBuildSources.CheckBuildSourcesKey
|
import sbt.internal.nio.CheckBuildSources.CheckBuildSourcesKey
|
||||||
import sbt.internal.protocol.JsonRpcResponseError
|
import sbt.internal.protocol.JsonRpcResponseError
|
||||||
|
|
@ -97,7 +98,7 @@ object MainLoop {
|
||||||
} else None
|
} else None
|
||||||
val sbtVersion = sbtVersionOpt.getOrElse(appId.version)
|
val sbtVersion = sbtVersionOpt.getOrElse(appId.version)
|
||||||
val currentArtDirs = defaultBoot * "*" / appId.groupID / appId.name / sbtVersion
|
val currentArtDirs = defaultBoot * "*" / appId.groupID / appId.name / sbtVersion
|
||||||
currentArtDirs.get foreach { dir =>
|
currentArtDirs.get().foreach { dir =>
|
||||||
state.log.info(s"deleting $dir")
|
state.log.info(s"deleting $dir")
|
||||||
IO.delete(dir)
|
IO.delete(dir)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ object DefaultOptions {
|
||||||
import Opts._
|
import Opts._
|
||||||
import sbt.io.syntax._
|
import sbt.io.syntax._
|
||||||
import BuildPaths.{ getGlobalBase, getGlobalSettingsDirectory }
|
import BuildPaths.{ getGlobalBase, getGlobalSettingsDirectory }
|
||||||
import Project.extract
|
import sbt.ProjectExtra.extract
|
||||||
import Def.Setting
|
import Def.Setting
|
||||||
|
|
||||||
def javac: Seq[String] = compile.encoding("UTF-8")
|
def javac: Seq[String] = compile.encoding("UTF-8")
|
||||||
|
|
@ -92,6 +92,10 @@ object DefaultOptions {
|
||||||
|
|
||||||
def shellPrompt(version: String): State => String =
|
def shellPrompt(version: String): State => String =
|
||||||
s =>
|
s =>
|
||||||
"%s:%s:%s> ".format(s.configuration.provider.id.name, extract(s).currentProject.id, version)
|
"%s:%s:%s> ".format(
|
||||||
|
s.configuration.provider.id.name,
|
||||||
|
Project.extract(s).currentProject.id,
|
||||||
|
version
|
||||||
|
)
|
||||||
def setupShellPrompt: Setting[_] = Keys.shellPrompt := { shellPrompt(Keys.version.value) }
|
def setupShellPrompt: Setting[_] = Keys.shellPrompt := { shellPrompt(Keys.version.value) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import sbt.internal.CommandStrings._
|
||||||
import Cross.{ spacedFirst, requireSession }
|
import Cross.{ spacedFirst, requireSession }
|
||||||
import sbt.librarymanagement.VersionNumber
|
import sbt.librarymanagement.VersionNumber
|
||||||
import Project.inScope
|
import Project.inScope
|
||||||
|
import ProjectExtra.{ extract, getProject, setProject }
|
||||||
import scala.annotation.nowarn
|
import scala.annotation.nowarn
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -47,7 +48,7 @@ private[sbt] object PluginCross {
|
||||||
val x = Project.extract(state)
|
val x = Project.extract(state)
|
||||||
import x._
|
import x._
|
||||||
state.log.info(s"Setting `sbtVersion in pluginCrossBuild` to $version")
|
state.log.info(s"Setting `sbtVersion in pluginCrossBuild` to $version")
|
||||||
val add = List(sbtVersion in GlobalScope in pluginCrossBuild :== version) ++
|
val add = List(GlobalScope / pluginCrossBuild / sbtVersion :== version) ++
|
||||||
List(scalaVersion := scalaVersionSetting.value) ++
|
List(scalaVersion := scalaVersionSetting.value) ++
|
||||||
inScope(GlobalScope.copy(project = Select(currentRef)))(
|
inScope(GlobalScope.copy(project = Select(currentRef)))(
|
||||||
Seq(scalaVersion := scalaVersionSetting.value)
|
Seq(scalaVersion := scalaVersionSetting.value)
|
||||||
|
|
|
||||||
|
|
@ -1,936 +0,0 @@
|
||||||
/*
|
|
||||||
* sbt
|
|
||||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
|
||||||
* Copyright 2008 - 2010, Mark Harrah
|
|
||||||
* Licensed under Apache License 2.0 (see LICENSE)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package sbt
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URI
|
|
||||||
import java.util.Locale
|
|
||||||
import Project._
|
|
||||||
import BasicKeys.serverLogLevel
|
|
||||||
import Keys.{
|
|
||||||
stateBuildStructure,
|
|
||||||
bspEnabled,
|
|
||||||
colorShellPrompt,
|
|
||||||
commands,
|
|
||||||
configuration,
|
|
||||||
historyPath,
|
|
||||||
projectCommand,
|
|
||||||
sessionSettings,
|
|
||||||
shellPrompt,
|
|
||||||
templateResolverInfos,
|
|
||||||
autoStartServer,
|
|
||||||
serverHost,
|
|
||||||
serverIdleTimeout,
|
|
||||||
serverLog,
|
|
||||||
serverPort,
|
|
||||||
serverUseJni,
|
|
||||||
serverAuthentication,
|
|
||||||
serverConnectionType,
|
|
||||||
fullServerHandlers,
|
|
||||||
logLevel,
|
|
||||||
windowsServerSecurityLevel,
|
|
||||||
}
|
|
||||||
import Scope.{ Global, ThisScope }
|
|
||||||
import sbt.SlashSyntax0._
|
|
||||||
import Def.{ Flattened, Initialize, ScopedKey, Setting }
|
|
||||||
import sbt.internal.{
|
|
||||||
Load,
|
|
||||||
BuildStructure,
|
|
||||||
LoadedBuild,
|
|
||||||
LoadedBuildUnit,
|
|
||||||
SettingGraph,
|
|
||||||
SettingCompletions,
|
|
||||||
SessionSettings
|
|
||||||
}
|
|
||||||
import sbt.internal.util.{ AttributeKey, AttributeMap, Dag, Relation, Settings, ~> }
|
|
||||||
import sbt.internal.util.Types.{ const, idFun }
|
|
||||||
import sbt.internal.util.complete.DefaultParsers
|
|
||||||
import sbt.internal.server.ServerHandler
|
|
||||||
import sbt.librarymanagement.Configuration
|
|
||||||
import sbt.util.{ Show, Level }
|
|
||||||
import sjsonnew.JsonFormat
|
|
||||||
|
|
||||||
import language.experimental.macros
|
|
||||||
import scala.concurrent.TimeoutException
|
|
||||||
import scala.concurrent.duration.FiniteDuration
|
|
||||||
|
|
||||||
trait CompositeProject {
|
|
||||||
def componentProjects: Seq[Project]
|
|
||||||
}
|
|
||||||
|
|
||||||
private[sbt] object CompositeProject {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expand user defined projects with the component projects of `compositeProjects`.
|
|
||||||
*
|
|
||||||
* If two projects with the same id appear in the user defined projects and
|
|
||||||
* in `compositeProjects.componentProjects`, the user defined project wins.
|
|
||||||
* This is necessary for backward compatibility with the idioms:
|
|
||||||
* {{{
|
|
||||||
* lazy val foo = crossProject
|
|
||||||
* lazy val fooJS = foo.js.settings(...)
|
|
||||||
* lazy val fooJVM = foo.jvm.settings(...)
|
|
||||||
* }}}
|
|
||||||
* and the rarer:
|
|
||||||
* {{{
|
|
||||||
* lazy val fooJS = foo.js.settings(...)
|
|
||||||
* lazy val foo = crossProject
|
|
||||||
* lazy val fooJVM = foo.jvm.settings(...)
|
|
||||||
* }}}
|
|
||||||
*/
|
|
||||||
def expand(compositeProjects: Seq[CompositeProject]): Seq[Project] = {
|
|
||||||
val userProjects = compositeProjects.collect { case p: Project => p }
|
|
||||||
for (p <- compositeProjects.flatMap(_.componentProjects)) yield {
|
|
||||||
userProjects.find(_.id == p.id) match {
|
|
||||||
case Some(userProject) => userProject
|
|
||||||
case None => p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.distinct
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed trait Project extends ProjectDefinition[ProjectReference] with CompositeProject {
|
|
||||||
def componentProjects: Seq[Project] = this :: Nil
|
|
||||||
|
|
||||||
private[sbt] def copy(
|
|
||||||
id: String = id,
|
|
||||||
base: File = base,
|
|
||||||
aggregate: Seq[ProjectReference] = aggregate,
|
|
||||||
dependencies: Seq[ClasspathDep[ProjectReference]] = dependencies,
|
|
||||||
settings: Seq[Setting[_]] = settings,
|
|
||||||
configurations: Seq[Configuration] = configurations
|
|
||||||
): Project =
|
|
||||||
copy2(id, base, aggregate, dependencies, settings, configurations)
|
|
||||||
|
|
||||||
private[this] def copy2(
|
|
||||||
id: String = id,
|
|
||||||
base: File = base,
|
|
||||||
aggregate: Seq[ProjectReference] = aggregate,
|
|
||||||
dependencies: Seq[ClasspathDep[ProjectReference]] = dependencies,
|
|
||||||
settings: Seq[Setting[_]] = settings,
|
|
||||||
configurations: Seq[Configuration] = configurations,
|
|
||||||
plugins: Plugins = plugins,
|
|
||||||
autoPlugins: Seq[AutoPlugin] = autoPlugins,
|
|
||||||
projectOrigin: ProjectOrigin = projectOrigin,
|
|
||||||
): Project =
|
|
||||||
unresolved(
|
|
||||||
id,
|
|
||||||
base,
|
|
||||||
aggregate = aggregate,
|
|
||||||
dependencies = dependencies,
|
|
||||||
settings = settings,
|
|
||||||
configurations,
|
|
||||||
plugins,
|
|
||||||
autoPlugins,
|
|
||||||
projectOrigin
|
|
||||||
)
|
|
||||||
|
|
||||||
def resolve(resolveRef: ProjectReference => ProjectRef): ResolvedProject = {
|
|
||||||
def resolveRefs(prs: Seq[ProjectReference]) = prs map resolveRef
|
|
||||||
def resolveDeps(ds: Seq[ClasspathDep[ProjectReference]]) = ds map resolveDep
|
|
||||||
def resolveDep(d: ClasspathDep[ProjectReference]) =
|
|
||||||
ResolvedClasspathDependency(resolveRef(d.project), d.configuration)
|
|
||||||
resolved(
|
|
||||||
id,
|
|
||||||
base,
|
|
||||||
aggregate = resolveRefs(aggregate),
|
|
||||||
dependencies = resolveDeps(dependencies),
|
|
||||||
settings,
|
|
||||||
configurations,
|
|
||||||
plugins,
|
|
||||||
autoPlugins,
|
|
||||||
projectOrigin
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def resolveBuild(resolveRef: ProjectReference => ProjectReference): Project = {
|
|
||||||
def resolveRefs(prs: Seq[ProjectReference]) = prs map resolveRef
|
|
||||||
def resolveDeps(ds: Seq[ClasspathDep[ProjectReference]]) = ds map resolveDep
|
|
||||||
def resolveDep(d: ClasspathDep[ProjectReference]) =
|
|
||||||
ClasspathDependency(resolveRef(d.project), d.configuration)
|
|
||||||
copy2(aggregate = resolveRefs(aggregate), dependencies = resolveDeps(dependencies))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies the given functions to this Project.
|
|
||||||
* The second function is applied to the result of applying the first to this Project and so on.
|
|
||||||
* The intended use is a convenience for applying default configuration provided by a plugin.
|
|
||||||
*/
|
|
||||||
def configure(transforms: (Project => Project)*): Project = Function.chain(transforms)(this)
|
|
||||||
|
|
||||||
def withId(id: String) = copy(id = id)
|
|
||||||
|
|
||||||
/** Sets the base directory for this project. */
|
|
||||||
def in(dir: File): Project = copy(base = dir)
|
|
||||||
|
|
||||||
/** Adds configurations to this project. Added configurations replace existing configurations with the same name. */
|
|
||||||
def overrideConfigs(cs: Configuration*): Project =
|
|
||||||
copy(configurations = Defaults.overrideConfigs(cs: _*)(configurations))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds configuration at the *start* of the configuration list for this project. Previous configurations replace this prefix
|
|
||||||
* list with the same name.
|
|
||||||
*/
|
|
||||||
private[sbt] def prefixConfigs(cs: Configuration*): Project =
|
|
||||||
copy(configurations = Defaults.overrideConfigs(configurations: _*)(cs))
|
|
||||||
|
|
||||||
/** Adds new configurations directly to this project. To override an existing configuration, use `overrideConfigs`. */
|
|
||||||
def configs(cs: Configuration*): Project = copy(configurations = configurations ++ cs)
|
|
||||||
|
|
||||||
/** Adds classpath dependencies on internal or external projects. */
|
|
||||||
def dependsOn(deps: ClasspathDep[ProjectReference]*): Project =
|
|
||||||
copy(dependencies = dependencies ++ deps)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds projects to be aggregated. When a user requests a task to run on this project from the command line,
|
|
||||||
* the task will also be run in aggregated projects.
|
|
||||||
*/
|
|
||||||
def aggregate(refs: ProjectReference*): Project =
|
|
||||||
copy(aggregate = (aggregate: Seq[ProjectReference]) ++ refs)
|
|
||||||
|
|
||||||
/** Appends settings to the current settings sequence for this project. */
|
|
||||||
def settings(ss: Def.SettingsDefinition*): Project =
|
|
||||||
copy(settings = (settings: Seq[Def.Setting[_]]) ++ Def.settings(ss: _*))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the [[AutoPlugin]]s of this project.
|
|
||||||
* A [[AutoPlugin]] is a common label that is used by plugins to determine what settings, if any, to enable on a project.
|
|
||||||
*/
|
|
||||||
def enablePlugins(ns: Plugins*): Project = setPlugins(ns.foldLeft(plugins)(Plugins.and))
|
|
||||||
|
|
||||||
/** Disable the given plugins on this project. */
|
|
||||||
def disablePlugins(ps: AutoPlugin*): Project =
|
|
||||||
setPlugins(Plugins.and(plugins, Plugins.And(ps.map(p => Plugins.Exclude(p)).toList)))
|
|
||||||
|
|
||||||
private[sbt] def setPlugins(ns: Plugins): Project = copy2(plugins = ns)
|
|
||||||
|
|
||||||
/** Definitively set the [[AutoPlugin]]s for this project. */
|
|
||||||
private[sbt] def setAutoPlugins(autos: Seq[AutoPlugin]): Project = copy2(autoPlugins = autos)
|
|
||||||
|
|
||||||
/** Definitively set the [[ProjectOrigin]] for this project. */
|
|
||||||
private[sbt] def setProjectOrigin(origin: ProjectOrigin): Project = copy2(projectOrigin = origin)
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed trait ResolvedProject extends ProjectDefinition[ProjectRef] {
|
|
||||||
|
|
||||||
/** The [[AutoPlugin]]s enabled for this project as computed from [[plugins]]. */
|
|
||||||
def autoPlugins: Seq[AutoPlugin]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed trait ClasspathDep[PR <: ProjectReference] {
|
|
||||||
def project: PR; def configuration: Option[String]
|
|
||||||
}
|
|
||||||
|
|
||||||
final case class ResolvedClasspathDependency(project: ProjectRef, configuration: Option[String])
|
|
||||||
extends ClasspathDep[ProjectRef]
|
|
||||||
|
|
||||||
final case class ClasspathDependency(project: ProjectReference, configuration: Option[String])
|
|
||||||
extends ClasspathDep[ProjectReference]
|
|
||||||
|
|
||||||
object Project extends ProjectExtra {
|
|
||||||
|
|
||||||
private abstract class ProjectDef[PR <: ProjectReference](
|
|
||||||
val id: String,
|
|
||||||
val base: File,
|
|
||||||
val aggregate: Seq[PR],
|
|
||||||
val dependencies: Seq[ClasspathDep[PR]],
|
|
||||||
val settings: Seq[Def.Setting[_]],
|
|
||||||
val configurations: Seq[Configuration],
|
|
||||||
val plugins: Plugins,
|
|
||||||
val autoPlugins: Seq[AutoPlugin],
|
|
||||||
val projectOrigin: ProjectOrigin
|
|
||||||
) extends ProjectDefinition[PR] {
|
|
||||||
// checks for cyclic references here instead of having to do it in Scope.delegates
|
|
||||||
Dag.topologicalSort(configurations)(_.extendsConfigs)
|
|
||||||
}
|
|
||||||
|
|
||||||
def apply(id: String, base: File): Project =
|
|
||||||
unresolved(id, base, Nil, Nil, Nil, Nil, Plugins.empty, Nil, ProjectOrigin.Organic)
|
|
||||||
|
|
||||||
def showContextKey(state: State): Show[ScopedKey[_]] =
|
|
||||||
showContextKey(state, None)
|
|
||||||
|
|
||||||
def showContextKey(state: State, keyNameColor: Option[String]): Show[ScopedKey[_]] =
|
|
||||||
if (isProjectLoaded(state)) showContextKey2(session(state), keyNameColor)
|
|
||||||
else Def.showFullKey
|
|
||||||
|
|
||||||
@deprecated("Use showContextKey2 which doesn't take the unused structure param", "1.1.1")
|
|
||||||
def showContextKey(
|
|
||||||
session: SessionSettings,
|
|
||||||
structure: BuildStructure,
|
|
||||||
keyNameColor: Option[String] = None
|
|
||||||
): Show[ScopedKey[_]] =
|
|
||||||
showContextKey2(session, keyNameColor)
|
|
||||||
|
|
||||||
def showContextKey2(
|
|
||||||
session: SessionSettings,
|
|
||||||
keyNameColor: Option[String] = None
|
|
||||||
): Show[ScopedKey[_]] =
|
|
||||||
Def.showRelativeKey2(session.current, keyNameColor)
|
|
||||||
|
|
||||||
def showLoadingKey(
|
|
||||||
loaded: LoadedBuild,
|
|
||||||
keyNameColor: Option[String] = None
|
|
||||||
): Show[ScopedKey[_]] =
|
|
||||||
Def.showRelativeKey2(
|
|
||||||
ProjectRef(loaded.root, loaded.units(loaded.root).rootProjects.head),
|
|
||||||
keyNameColor
|
|
||||||
)
|
|
||||||
|
|
||||||
/** This is a variation of def apply that mixes in GeneratedRootProject. */
|
|
||||||
private[sbt] def mkGeneratedRoot(
|
|
||||||
id: String,
|
|
||||||
base: File,
|
|
||||||
aggregate: Seq[ProjectReference]
|
|
||||||
): Project = {
|
|
||||||
validProjectID(id).foreach(errMsg => sys.error(s"Invalid project ID: $errMsg"))
|
|
||||||
val plugins = Plugins.empty
|
|
||||||
val origin = ProjectOrigin.GenericRoot
|
|
||||||
new ProjectDef(id, base, aggregate, Nil, Nil, Nil, plugins, Nil, origin)
|
|
||||||
with Project
|
|
||||||
with GeneratedRootProject
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns None if `id` is a valid Project ID or Some containing the parser error message if it is not. */
|
|
||||||
def validProjectID(id: String): Option[String] =
|
|
||||||
DefaultParsers.parse(id, DefaultParsers.ID).left.toOption
|
|
||||||
|
|
||||||
private[this] def validProjectIDStart(id: String): Boolean =
|
|
||||||
DefaultParsers.parse(id, DefaultParsers.IDStart).isRight
|
|
||||||
|
|
||||||
/** Constructs a valid Project ID based on `id` and returns it in Right or returns the error message in Left if one cannot be constructed. */
|
|
||||||
def normalizeProjectID(id: String): Either[String, String] = {
|
|
||||||
val attempt = normalizeBase(id)
|
|
||||||
val refined =
|
|
||||||
if (attempt.length < 1) "root"
|
|
||||||
else if (!validProjectIDStart(attempt.substring(0, 1))) "root-" + attempt
|
|
||||||
else attempt
|
|
||||||
validProjectID(refined).toLeft(refined)
|
|
||||||
}
|
|
||||||
private[this] def normalizeBase(s: String) =
|
|
||||||
s.toLowerCase(Locale.ENGLISH).replaceAll("""\W+""", "-")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalize a String so that it is suitable for use as a dependency management module identifier.
|
|
||||||
* This is a best effort implementation, since valid characters are not documented or consistent.
|
|
||||||
*/
|
|
||||||
def normalizeModuleID(id: String): String = normalizeBase(id)
|
|
||||||
|
|
||||||
private def resolved(
|
|
||||||
id: String,
|
|
||||||
base: File,
|
|
||||||
aggregate: Seq[ProjectRef],
|
|
||||||
dependencies: Seq[ClasspathDep[ProjectRef]],
|
|
||||||
settings: Seq[Def.Setting[_]],
|
|
||||||
configurations: Seq[Configuration],
|
|
||||||
plugins: Plugins,
|
|
||||||
autoPlugins: Seq[AutoPlugin],
|
|
||||||
origin: ProjectOrigin
|
|
||||||
): ResolvedProject =
|
|
||||||
new ProjectDef[ProjectRef](
|
|
||||||
id,
|
|
||||||
base,
|
|
||||||
aggregate,
|
|
||||||
dependencies,
|
|
||||||
settings,
|
|
||||||
configurations,
|
|
||||||
plugins,
|
|
||||||
autoPlugins,
|
|
||||||
origin
|
|
||||||
) with ResolvedProject
|
|
||||||
|
|
||||||
private def unresolved(
|
|
||||||
id: String,
|
|
||||||
base: File,
|
|
||||||
aggregate: Seq[ProjectReference],
|
|
||||||
dependencies: Seq[ClasspathDep[ProjectReference]],
|
|
||||||
settings: Seq[Def.Setting[_]],
|
|
||||||
configurations: Seq[Configuration],
|
|
||||||
plugins: Plugins,
|
|
||||||
autoPlugins: Seq[AutoPlugin],
|
|
||||||
origin: ProjectOrigin
|
|
||||||
): Project = {
|
|
||||||
validProjectID(id).foreach(errMsg => sys.error("Invalid project ID: " + errMsg))
|
|
||||||
new ProjectDef[ProjectReference](
|
|
||||||
id,
|
|
||||||
base,
|
|
||||||
aggregate,
|
|
||||||
dependencies,
|
|
||||||
settings,
|
|
||||||
configurations,
|
|
||||||
plugins,
|
|
||||||
autoPlugins,
|
|
||||||
origin
|
|
||||||
) with Project
|
|
||||||
}
|
|
||||||
|
|
||||||
final class Constructor(p: ProjectReference) {
|
|
||||||
def %(conf: Configuration): ClasspathDependency = %(conf.name)
|
|
||||||
|
|
||||||
def %(conf: String): ClasspathDependency = ClasspathDependency(p, Some(conf))
|
|
||||||
}
|
|
||||||
|
|
||||||
def getOrError[T](state: State, key: AttributeKey[T], msg: String): T =
|
|
||||||
state get key getOrElse sys.error(msg)
|
|
||||||
|
|
||||||
def structure(state: State): BuildStructure =
|
|
||||||
getOrError(state, stateBuildStructure, "No build loaded.")
|
|
||||||
|
|
||||||
def session(state: State): SessionSettings =
|
|
||||||
getOrError(state, sessionSettings, "Session not initialized.")
|
|
||||||
|
|
||||||
def isProjectLoaded(state: State): Boolean =
|
|
||||||
(state has sessionSettings) && (state has stateBuildStructure)
|
|
||||||
|
|
||||||
def extract(state: State): Extracted = extract(session(state), structure(state))
|
|
||||||
|
|
||||||
private[sbt] def extract(se: SessionSettings, st: BuildStructure): Extracted =
|
|
||||||
Extracted(st, se, se.current)(showContextKey2(se))
|
|
||||||
|
|
||||||
def getProjectForReference(ref: Reference, structure: BuildStructure): Option[ResolvedProject] =
|
|
||||||
ref match { case pr: ProjectRef => getProject(pr, structure); case _ => None }
|
|
||||||
|
|
||||||
def getProject(ref: ProjectRef, structure: BuildStructure): Option[ResolvedProject] =
|
|
||||||
getProject(ref, structure.units)
|
|
||||||
|
|
||||||
def getProject(ref: ProjectRef, structure: LoadedBuild): Option[ResolvedProject] =
|
|
||||||
getProject(ref, structure.units)
|
|
||||||
|
|
||||||
def getProject(ref: ProjectRef, units: Map[URI, LoadedBuildUnit]): Option[ResolvedProject] =
|
|
||||||
(units get ref.build).flatMap(_.defined get ref.project)
|
|
||||||
|
|
||||||
def runUnloadHooks(s: State): State = {
|
|
||||||
val previousOnUnload = orIdentity(s get Keys.onUnload.key)
|
|
||||||
previousOnUnload(s.runExitHooks())
|
|
||||||
}
|
|
||||||
|
|
||||||
def setProject(session: SessionSettings, structure: BuildStructure, s: State): State =
|
|
||||||
setProject(session, structure, s, identity)
|
|
||||||
|
|
||||||
def setProject(
|
|
||||||
session: SessionSettings,
|
|
||||||
structure: BuildStructure,
|
|
||||||
s: State,
|
|
||||||
preOnLoad: State => State
|
|
||||||
): State = {
|
|
||||||
val unloaded = runUnloadHooks(s)
|
|
||||||
val (onLoad, onUnload) = getHooks(structure.data)
|
|
||||||
val newAttrs = unloaded.attributes
|
|
||||||
.put(stateBuildStructure, structure)
|
|
||||||
.put(sessionSettings, session)
|
|
||||||
.put(Keys.onUnload.key, onUnload)
|
|
||||||
val newState = unloaded.copy(attributes = newAttrs)
|
|
||||||
// TODO: Fix this
|
|
||||||
onLoad(
|
|
||||||
preOnLoad(
|
|
||||||
updateCurrent(newState)
|
|
||||||
) /*LogManager.setGlobalLogLevels(updateCurrent(newState), structure.data)*/
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def orIdentity[T](opt: Option[T => T]): T => T = opt getOrElse idFun
|
|
||||||
|
|
||||||
def getHook[T](key: SettingKey[T => T], data: Settings[Scope]): T => T =
|
|
||||||
orIdentity((Global / key) get data)
|
|
||||||
|
|
||||||
def getHooks(data: Settings[Scope]): (State => State, State => State) =
|
|
||||||
(getHook(Keys.onLoad, data), getHook(Keys.onUnload, data))
|
|
||||||
|
|
||||||
def current(state: State): ProjectRef = session(state).current
|
|
||||||
|
|
||||||
def updateCurrent(s: State): State = {
|
|
||||||
val structure = Project.structure(s)
|
|
||||||
val ref = Project.current(s)
|
|
||||||
Load.getProject(structure.units, ref.build, ref.project)
|
|
||||||
val msg = (ref / Keys.onLoadMessage) get structure.data getOrElse ""
|
|
||||||
if (!msg.isEmpty) s.log.info(msg)
|
|
||||||
def get[T](k: SettingKey[T]): Option[T] = (ref / k) get structure.data
|
|
||||||
def commandsIn(axis: ResolvedReference) = (axis / commands) get structure.data toList
|
|
||||||
|
|
||||||
val allCommands = commandsIn(ref) ++ commandsIn(
|
|
||||||
BuildRef(ref.build)
|
|
||||||
) ++ ((Global / commands) get structure.data toList)
|
|
||||||
val history = get(historyPath) flatMap idFun
|
|
||||||
val prompt = get(shellPrompt)
|
|
||||||
val newPrompt = get(colorShellPrompt)
|
|
||||||
val trs = ((Global / templateResolverInfos) get structure.data).toList.flatten
|
|
||||||
val startSvr: Option[Boolean] = get(autoStartServer)
|
|
||||||
val host: Option[String] = get(serverHost)
|
|
||||||
val port: Option[Int] = get(serverPort)
|
|
||||||
val enabledBsp: Option[Boolean] = get(bspEnabled)
|
|
||||||
val timeout: Option[Option[FiniteDuration]] = get(serverIdleTimeout)
|
|
||||||
val authentication: Option[Set[ServerAuthentication]] = get(serverAuthentication)
|
|
||||||
val connectionType: Option[ConnectionType] = get(serverConnectionType)
|
|
||||||
val srvLogLevel: Option[Level.Value] = (ref / serverLog / logLevel).get(structure.data)
|
|
||||||
val hs: Option[Seq[ServerHandler]] = get(ThisBuild / fullServerHandlers)
|
|
||||||
val commandDefs = allCommands.distinct.flatten[Command].map(_ tag (projectCommand, true))
|
|
||||||
val newDefinedCommands = commandDefs ++ BasicCommands.removeTagged(
|
|
||||||
s.definedCommands,
|
|
||||||
projectCommand
|
|
||||||
)
|
|
||||||
val winSecurityLevel = get(windowsServerSecurityLevel).getOrElse(2)
|
|
||||||
val useJni = get(serverUseJni).getOrElse(false)
|
|
||||||
val newAttrs =
|
|
||||||
s.attributes
|
|
||||||
.put(historyPath.key, history)
|
|
||||||
.put(windowsServerSecurityLevel.key, winSecurityLevel)
|
|
||||||
.put(serverUseJni.key, useJni)
|
|
||||||
.setCond(bspEnabled.key, enabledBsp)
|
|
||||||
.setCond(autoStartServer.key, startSvr)
|
|
||||||
.setCond(serverPort.key, port)
|
|
||||||
.setCond(serverHost.key, host)
|
|
||||||
.setCond(serverAuthentication.key, authentication)
|
|
||||||
.setCond(serverConnectionType.key, connectionType)
|
|
||||||
.setCond(serverIdleTimeout.key, timeout)
|
|
||||||
.put(historyPath.key, history)
|
|
||||||
.put(templateResolverInfos.key, trs)
|
|
||||||
.setCond(shellPrompt.key, prompt)
|
|
||||||
.setCond(colorShellPrompt.key, newPrompt)
|
|
||||||
.setCond(serverLogLevel, srvLogLevel)
|
|
||||||
.setCond(fullServerHandlers.key, hs)
|
|
||||||
s.copy(
|
|
||||||
attributes = newAttrs,
|
|
||||||
definedCommands = newDefinedCommands
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def setCond[T](key: AttributeKey[T], vopt: Option[T], attributes: AttributeMap): AttributeMap =
|
|
||||||
attributes.setCond(key, vopt)
|
|
||||||
|
|
||||||
private[sbt] def checkTargets(data: Settings[Scope]): Option[String] = {
|
|
||||||
val dups = overlappingTargets(allTargets(data))
|
|
||||||
if (dups.isEmpty) None
|
|
||||||
else {
|
|
||||||
val dupStrs = dups map { case (dir, scopes) =>
|
|
||||||
s"${dir.getAbsolutePath}:\n\t${scopes.mkString("\n\t")}"
|
|
||||||
}
|
|
||||||
Some(s"Overlapping output directories:${dupStrs.mkString}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private[this] def overlappingTargets(
|
|
||||||
targets: Seq[(ProjectRef, File)]
|
|
||||||
): Map[File, Seq[ProjectRef]] =
|
|
||||||
targets.groupBy(_._2).filter(_._2.size > 1).mapValues(_.map(_._1)).toMap
|
|
||||||
|
|
||||||
private[this] def allTargets(data: Settings[Scope]): Seq[(ProjectRef, File)] = {
|
|
||||||
import ScopeFilter._
|
|
||||||
val allProjects = ScopeFilter(Make.inAnyProject)
|
|
||||||
val targetAndRef = Def.setting { (Keys.thisProjectRef.value, Keys.target.value) }
|
|
||||||
new SettingKeyAll(Def.optional(targetAndRef)(idFun))
|
|
||||||
.all(allProjects)
|
|
||||||
.evaluate(data)
|
|
||||||
.flatMap(x => x)
|
|
||||||
}
|
|
||||||
|
|
||||||
def equal(a: ScopedKey[_], b: ScopedKey[_], mask: ScopeMask): Boolean =
|
|
||||||
a.key == b.key && Scope.equal(a.scope, b.scope, mask)
|
|
||||||
|
|
||||||
def fillTaskAxis(scoped: ScopedKey[_]): ScopedKey[_] =
|
|
||||||
ScopedKey(Scope.fillTaskAxis(scoped.scope, scoped.key), scoped.key)
|
|
||||||
|
|
||||||
def mapScope(f: Scope => Scope): [a] => ScopedKey[a] => ScopedKey[a] =
|
|
||||||
[a] => (k: ScopedKey[a]) => ScopedKey(f(k.scope), k.key)
|
|
||||||
|
|
||||||
def transform(g: Scope => Scope, ss: Seq[Def.Setting[_]]): Seq[Def.Setting[_]] =
|
|
||||||
val f = mapScope(g)
|
|
||||||
ss.map { setting =>
|
|
||||||
setting.mapKey(f).mapReferenced(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
def transformRef(g: Scope => Scope, ss: Seq[Def.Setting[_]]): Seq[Def.Setting[_]] = {
|
|
||||||
val f = mapScope(g)
|
|
||||||
ss.map(_ mapReferenced f)
|
|
||||||
}
|
|
||||||
|
|
||||||
def delegates(structure: BuildStructure, scope: Scope, key: AttributeKey[_]): Seq[ScopedKey[_]] =
|
|
||||||
structure.delegates(scope).map(d => ScopedKey(d, key))
|
|
||||||
|
|
||||||
def scopedKeyData(
|
|
||||||
structure: BuildStructure,
|
|
||||||
scope: Scope,
|
|
||||||
key: AttributeKey[_]
|
|
||||||
): Option[ScopedKeyData[_]] =
|
|
||||||
structure.data.get(scope, key) map { v =>
|
|
||||||
ScopedKeyData(ScopedKey(scope, key), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
def details(structure: BuildStructure, actual: Boolean, scope: Scope, key: AttributeKey[_])(
|
|
||||||
implicit display: Show[ScopedKey[_]]
|
|
||||||
): String = {
|
|
||||||
val scoped = ScopedKey(scope, key)
|
|
||||||
|
|
||||||
val data = scopedKeyData(structure, scope, key) map { _.description } getOrElse {
|
|
||||||
"No entry for key."
|
|
||||||
}
|
|
||||||
val description = key.description match {
|
|
||||||
case Some(desc) => "Description:\n\t" + desc + "\n"; case None => ""
|
|
||||||
}
|
|
||||||
|
|
||||||
val definingScope = structure.data.definingScope(scope, key)
|
|
||||||
val providedBy = definingScope match {
|
|
||||||
case Some(sc) => "Provided by:\n\t" + Scope.display(sc, key.label) + "\n"
|
|
||||||
case None => ""
|
|
||||||
}
|
|
||||||
val definingScoped = definingScope match {
|
|
||||||
case Some(sc) => ScopedKey(sc, key); case None => scoped
|
|
||||||
}
|
|
||||||
val comp =
|
|
||||||
Def.compiled(structure.settings, actual)(structure.delegates, structure.scopeLocal, display)
|
|
||||||
val definedAt = comp get definingScoped map { c =>
|
|
||||||
Def.definedAtString(c.settings).capitalize
|
|
||||||
} getOrElse ""
|
|
||||||
|
|
||||||
val cMap = Def.flattenLocals(comp)
|
|
||||||
val related = cMap.keys.filter(k => k.key == key && k.scope != scope)
|
|
||||||
def derivedDependencies(c: ScopedKey[_]): List[ScopedKey[_]] =
|
|
||||||
comp
|
|
||||||
.get(c)
|
|
||||||
.map(_.settings.flatMap(s => if (s.isDerived) s.dependencies else Nil))
|
|
||||||
.toList
|
|
||||||
.flatten
|
|
||||||
|
|
||||||
val depends = cMap.get(scoped) match {
|
|
||||||
case Some(c) => c.dependencies.toSet; case None => Set.empty
|
|
||||||
}
|
|
||||||
val derivedDepends: Set[ScopedKey[_]] = derivedDependencies(definingScoped).toSet
|
|
||||||
|
|
||||||
val reverse = reverseDependencies(cMap, scoped)
|
|
||||||
val derivedReverse = reverse.filter(r => derivedDependencies(r).contains(definingScoped)).toSet
|
|
||||||
|
|
||||||
def printDepScopes(
|
|
||||||
baseLabel: String,
|
|
||||||
derivedLabel: String,
|
|
||||||
scopes: Iterable[ScopedKey[_]],
|
|
||||||
derived: Set[ScopedKey[_]]
|
|
||||||
): String = {
|
|
||||||
val label = s"$baseLabel${if (derived.isEmpty) "" else s" (D=$derivedLabel)"}"
|
|
||||||
val prefix: ScopedKey[_] => String =
|
|
||||||
if (derived.isEmpty) const("") else sk => if (derived(sk)) "D " else " "
|
|
||||||
printScopes(label, scopes, prefix = prefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
def printScopes(
|
|
||||||
label: String,
|
|
||||||
scopes: Iterable[ScopedKey[_]],
|
|
||||||
max: Int = Int.MaxValue,
|
|
||||||
prefix: ScopedKey[_] => String = const("")
|
|
||||||
) =
|
|
||||||
if (scopes.isEmpty) ""
|
|
||||||
else {
|
|
||||||
val (limited, more) =
|
|
||||||
if (scopes.size <= max) (scopes, "\n") else (scopes.take(max), "\n...\n")
|
|
||||||
limited.map(sk => prefix(sk) + display.show(sk)).mkString(label + ":\n\t", "\n\t", more)
|
|
||||||
}
|
|
||||||
|
|
||||||
data + "\n" +
|
|
||||||
description +
|
|
||||||
providedBy +
|
|
||||||
definedAt +
|
|
||||||
printDepScopes("Dependencies", "derived from", depends, derivedDepends) +
|
|
||||||
printDepScopes("Reverse dependencies", "derives", reverse, derivedReverse) +
|
|
||||||
printScopes("Delegates", delegates(structure, scope, key)) +
|
|
||||||
printScopes("Related", related, 10)
|
|
||||||
}
|
|
||||||
def settingGraph(structure: BuildStructure, basedir: File, scoped: ScopedKey[_])(implicit
|
|
||||||
display: Show[ScopedKey[_]]
|
|
||||||
): SettingGraph =
|
|
||||||
SettingGraph(structure, basedir, scoped, 0)
|
|
||||||
def graphSettings(structure: BuildStructure, basedir: File)(implicit
|
|
||||||
display: Show[ScopedKey[_]]
|
|
||||||
): Unit = {
|
|
||||||
def graph(actual: Boolean, name: String) =
|
|
||||||
graphSettings(structure, actual, name, new File(basedir, name + ".dot"))
|
|
||||||
graph(true, "actual_dependencies")
|
|
||||||
graph(false, "declared_dependencies")
|
|
||||||
}
|
|
||||||
def graphSettings(structure: BuildStructure, actual: Boolean, graphName: String, file: File)(
|
|
||||||
implicit display: Show[ScopedKey[_]]
|
|
||||||
): Unit = {
|
|
||||||
val rel = relation(structure, actual)
|
|
||||||
val keyToString = display.show _
|
|
||||||
DotGraph.generateGraph(file, graphName, rel, keyToString, keyToString)
|
|
||||||
}
|
|
||||||
def relation(structure: BuildStructure, actual: Boolean)(implicit
|
|
||||||
display: Show[ScopedKey[_]]
|
|
||||||
): Relation[ScopedKey[_], ScopedKey[_]] =
|
|
||||||
relation(structure.settings, actual)(structure.delegates, structure.scopeLocal, display)
|
|
||||||
|
|
||||||
private[sbt] def relation(settings: Seq[Def.Setting[_]], actual: Boolean)(implicit
|
|
||||||
delegates: Scope => Seq[Scope],
|
|
||||||
scopeLocal: Def.ScopeLocal,
|
|
||||||
display: Show[ScopedKey[_]]
|
|
||||||
): Relation[ScopedKey[_], ScopedKey[_]] = {
|
|
||||||
val cMap = Def.flattenLocals(Def.compiled(settings, actual))
|
|
||||||
val emptyRelation = Relation.empty[ScopedKey[_], ScopedKey[_]]
|
|
||||||
cMap.foldLeft(emptyRelation) { case (r, (key, value)) => r + (key, value.dependencies) }
|
|
||||||
}
|
|
||||||
|
|
||||||
def showDefinitions(key: AttributeKey[_], defs: Seq[Scope])(implicit
|
|
||||||
display: Show[ScopedKey[_]]
|
|
||||||
): String =
|
|
||||||
showKeys(defs.map(scope => ScopedKey(scope, key)))
|
|
||||||
|
|
||||||
def showUses(defs: Seq[ScopedKey[_]])(implicit display: Show[ScopedKey[_]]): String =
|
|
||||||
showKeys(defs)
|
|
||||||
|
|
||||||
private[this] def showKeys(s: Seq[ScopedKey[_]])(implicit display: Show[ScopedKey[_]]): String =
|
|
||||||
s.map(display.show).sorted.mkString("\n\t", "\n\t", "\n\n")
|
|
||||||
|
|
||||||
def definitions(structure: BuildStructure, actual: Boolean, key: AttributeKey[_])(implicit
|
|
||||||
display: Show[ScopedKey[_]]
|
|
||||||
): Seq[Scope] =
|
|
||||||
relation(structure, actual)(display)._1s.toSeq flatMap { sk =>
|
|
||||||
if (sk.key == key) sk.scope :: Nil else Nil
|
|
||||||
}
|
|
||||||
def usedBy(structure: BuildStructure, actual: Boolean, key: AttributeKey[_])(implicit
|
|
||||||
display: Show[ScopedKey[_]]
|
|
||||||
): Seq[ScopedKey[_]] =
|
|
||||||
relation(structure, actual)(display).all.toSeq flatMap { case (a, b) =>
|
|
||||||
if (b.key == key) List[ScopedKey[_]](a) else Nil
|
|
||||||
}
|
|
||||||
def reverseDependencies(
|
|
||||||
cMap: Map[ScopedKey[_], Flattened],
|
|
||||||
scoped: ScopedKey[_]
|
|
||||||
): Iterable[ScopedKey[_]] =
|
|
||||||
for ((key, compiled) <- cMap; dep <- compiled.dependencies if dep == scoped) yield key
|
|
||||||
|
|
||||||
def setAll(extracted: Extracted, settings: Seq[Def.Setting[_]]): SessionSettings =
|
|
||||||
SettingCompletions.setAll(extracted, settings).session
|
|
||||||
|
|
||||||
val ExtraBuilds = AttributeKey[List[URI]](
|
|
||||||
"extra-builds",
|
|
||||||
"Extra build URIs to load in addition to the ones defined by the project."
|
|
||||||
)
|
|
||||||
def extraBuilds(s: State): List[URI] = getOrNil(s, ExtraBuilds)
|
|
||||||
def getOrNil[T](s: State, key: AttributeKey[List[T]]): List[T] = s get key getOrElse Nil
|
|
||||||
def setExtraBuilds(s: State, extra: List[URI]): State = s.put(ExtraBuilds, extra)
|
|
||||||
def addExtraBuilds(s: State, extra: List[URI]): State =
|
|
||||||
setExtraBuilds(s, extra ::: extraBuilds(s))
|
|
||||||
def removeExtraBuilds(s: State, remove: List[URI]): State =
|
|
||||||
updateExtraBuilds(s, _.filterNot(remove.toSet))
|
|
||||||
def updateExtraBuilds(s: State, f: List[URI] => List[URI]): State =
|
|
||||||
setExtraBuilds(s, f(extraBuilds(s)))
|
|
||||||
|
|
||||||
// used by Coursier integration
|
|
||||||
private[sbt] def transitiveInterDependencies(
|
|
||||||
state: State,
|
|
||||||
projectRef: ProjectRef
|
|
||||||
): Seq[ProjectRef] = {
|
|
||||||
def dependencies(map: Map[ProjectRef, Seq[ProjectRef]], id: ProjectRef): Set[ProjectRef] = {
|
|
||||||
def helper(map: Map[ProjectRef, Seq[ProjectRef]], acc: Set[ProjectRef]): Set[ProjectRef] =
|
|
||||||
if (acc.exists(map.contains)) {
|
|
||||||
val (kept, rem) = map.partition { case (k, _) => acc(k) }
|
|
||||||
helper(rem, acc ++ kept.valuesIterator.flatten)
|
|
||||||
} else acc
|
|
||||||
helper(map - id, map.getOrElse(id, Nil).toSet)
|
|
||||||
}
|
|
||||||
val allProjectsDeps: Map[ProjectRef, Seq[ProjectRef]] =
|
|
||||||
(for {
|
|
||||||
(p, ref) <- Project.structure(state).allProjectPairs
|
|
||||||
} yield ref -> p.dependencies.map(_.project)).toMap
|
|
||||||
val deps = dependencies(allProjectsDeps.toMap, projectRef)
|
|
||||||
Project.structure(state).allProjectRefs.filter(p => deps(p))
|
|
||||||
}
|
|
||||||
|
|
||||||
object LoadAction extends Enumeration {
|
|
||||||
val Return, Current, Plugins = Value
|
|
||||||
}
|
|
||||||
import LoadAction._
|
|
||||||
import DefaultParsers._
|
|
||||||
|
|
||||||
val loadActionParser = token(Space ~> ("plugins" ^^^ Plugins | "return" ^^^ Return)) ?? Current
|
|
||||||
|
|
||||||
val ProjectReturn =
|
|
||||||
AttributeKey[List[File]]("project-return", "Maintains a stack of builds visited using reload.")
|
|
||||||
def projectReturn(s: State): List[File] = getOrNil(s, ProjectReturn)
|
|
||||||
def inPluginProject(s: State): Boolean = projectReturn(s).length > 1
|
|
||||||
def setProjectReturn(s: State, pr: List[File]): State =
|
|
||||||
s.copy(attributes = s.attributes.put(ProjectReturn, pr))
|
|
||||||
|
|
||||||
def loadAction(s: State, action: LoadAction.Value): (State, File) = action match {
|
|
||||||
case Return =>
|
|
||||||
projectReturn(s) match {
|
|
||||||
case _ /* current */ :: returnTo :: rest =>
|
|
||||||
(setProjectReturn(s, returnTo :: rest), returnTo)
|
|
||||||
case _ => sys.error("Not currently in a plugin definition")
|
|
||||||
}
|
|
||||||
|
|
||||||
case Current =>
|
|
||||||
val base = s.configuration.baseDirectory
|
|
||||||
projectReturn(s) match {
|
|
||||||
case Nil => (setProjectReturn(s, base :: Nil), base); case x :: _ => (s, x)
|
|
||||||
}
|
|
||||||
|
|
||||||
case Plugins =>
|
|
||||||
val (newBase, oldStack) =
|
|
||||||
if (Project.isProjectLoaded(s))
|
|
||||||
(Project.extract(s).currentUnit.unit.plugins.base, projectReturn(s))
|
|
||||||
else // support changing to the definition project if it fails to load
|
|
||||||
(BuildPaths.projectStandard(s.baseDir), s.baseDir :: Nil)
|
|
||||||
val newS = setProjectReturn(s, newBase :: oldStack)
|
|
||||||
(newS, newBase)
|
|
||||||
}
|
|
||||||
|
|
||||||
def runTask[T](
|
|
||||||
taskKey: ScopedKey[Task[T]],
|
|
||||||
state: State,
|
|
||||||
checkCycles: Boolean = false
|
|
||||||
): Option[(State, Result[T])] = {
|
|
||||||
val extracted = Project.extract(state)
|
|
||||||
val ch = EvaluateTask.cancelStrategy(extracted, extracted.structure, state)
|
|
||||||
val p = EvaluateTask.executeProgress(extracted, extracted.structure, state)
|
|
||||||
val r = EvaluateTask.restrictions(state)
|
|
||||||
val fgc = EvaluateTask.forcegc(extracted, extracted.structure)
|
|
||||||
val mfi = EvaluateTask.minForcegcInterval(extracted, extracted.structure)
|
|
||||||
runTask(taskKey, state, EvaluateTaskConfig(r, checkCycles, p, ch, fgc, mfi))
|
|
||||||
}
|
|
||||||
|
|
||||||
def runTask[T](
|
|
||||||
taskKey: ScopedKey[Task[T]],
|
|
||||||
state: State,
|
|
||||||
config: EvaluateTaskConfig
|
|
||||||
): Option[(State, Result[T])] = {
|
|
||||||
val extracted = Project.extract(state)
|
|
||||||
EvaluateTask(extracted.structure, taskKey, state, extracted.currentRef, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
def projectToRef(p: Project): ProjectReference = LocalProject(p.id)
|
|
||||||
|
|
||||||
implicit def projectToLocalProject(p: Project): LocalProject = LocalProject(p.id)
|
|
||||||
|
|
||||||
final class RichTaskSessionVar[S](i: Def.Initialize[Task[S]]) {
|
|
||||||
import SessionVar.{ persistAndSet, resolveContext, set, transform => tx }
|
|
||||||
|
|
||||||
def updateState(f: (State, S) => State): Def.Initialize[Task[S]] = i(t => tx(t, f))
|
|
||||||
|
|
||||||
def storeAs(key: TaskKey[S])(implicit f: JsonFormat[S]): Def.Initialize[Task[S]] = {
|
|
||||||
Keys.resolvedScoped.zipWith(i) { (scoped, task) =>
|
|
||||||
tx(
|
|
||||||
task,
|
|
||||||
(state, value) => persistAndSet(resolveContext(key, scoped.scope, state), state, value)(f)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def keepAs(key: TaskKey[S]): Def.Initialize[Task[S]] = {
|
|
||||||
i.zipWith(Keys.resolvedScoped) { (t, scoped) =>
|
|
||||||
tx(t, (state, value) => set(resolveContext(key, scoped.scope, state), state, value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* implicitly injected to tasks that return PromiseWrap.
|
|
||||||
*/
|
|
||||||
final class RichTaskPromise[A](i: Def.Initialize[Task[PromiseWrap[A]]]) {
|
|
||||||
import scala.concurrent.Await
|
|
||||||
import scala.concurrent.duration._
|
|
||||||
|
|
||||||
def await: Def.Initialize[Task[A]] = await(Duration.Inf)
|
|
||||||
|
|
||||||
def await(atMost: Duration): Def.Initialize[Task[A]] =
|
|
||||||
(Def
|
|
||||||
.task {
|
|
||||||
val p = i.value
|
|
||||||
var result: Option[A] = None
|
|
||||||
if (atMost == Duration.Inf) {
|
|
||||||
while (result.isEmpty) {
|
|
||||||
try {
|
|
||||||
result = Some(Await.result(p.underlying.future, Duration("1s")))
|
|
||||||
Thread.sleep(10)
|
|
||||||
} catch {
|
|
||||||
case _: TimeoutException => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = Some(Await.result(p.underlying.future, atMost))
|
|
||||||
}
|
|
||||||
result.get
|
|
||||||
})
|
|
||||||
.tag(Tags.Sentinel)
|
|
||||||
}
|
|
||||||
|
|
||||||
import scala.reflect.macros._
|
|
||||||
|
|
||||||
def projectMacroImpl(c: blackbox.Context): c.Expr[Project] = {
|
|
||||||
import c.universe._
|
|
||||||
val enclosingValName = std.KeyMacro.definingValName(
|
|
||||||
c,
|
|
||||||
methodName =>
|
|
||||||
s"""$methodName must be directly assigned to a val, such as `val x = $methodName`. Alternatively, you can use `sbt.Project.apply`"""
|
|
||||||
)
|
|
||||||
val name = c.Expr[String](Literal(Constant(enclosingValName)))
|
|
||||||
reify { Project(name.splice, new File(name.splice)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private[sbt] trait GeneratedRootProject
|
|
||||||
|
|
||||||
trait ProjectExtra {
|
|
||||||
implicit def configDependencyConstructor[T](
|
|
||||||
p: T
|
|
||||||
)(implicit ev: T => ProjectReference): Constructor =
|
|
||||||
new Constructor(p)
|
|
||||||
|
|
||||||
implicit def classpathDependency[T](
|
|
||||||
p: T
|
|
||||||
)(implicit ev: T => ProjectReference): ClasspathDependency = ClasspathDependency(p, None)
|
|
||||||
|
|
||||||
// These used to be in Project so that they didn't need to get imported (due to Initialize being nested in Project).
|
|
||||||
// Moving Initialize and other settings types to Def and decoupling Project, Def, and Structure means these go here for now
|
|
||||||
implicit def richInitializeTask[T](init: Initialize[Task[T]]): Scoped.RichInitializeTask[T] =
|
|
||||||
new Scoped.RichInitializeTask(init)
|
|
||||||
|
|
||||||
implicit def richInitializeInputTask[T](
|
|
||||||
init: Initialize[InputTask[T]]
|
|
||||||
): Scoped.RichInitializeInputTask[T] =
|
|
||||||
new Scoped.RichInitializeInputTask(init)
|
|
||||||
|
|
||||||
implicit def richInitialize[T](i: Initialize[T]): Scoped.RichInitialize[T] =
|
|
||||||
new Scoped.RichInitialize[T](i)
|
|
||||||
|
|
||||||
implicit def richTaskSessionVar[T](init: Initialize[Task[T]]): Project.RichTaskSessionVar[T] =
|
|
||||||
new Project.RichTaskSessionVar(init)
|
|
||||||
|
|
||||||
implicit def sbtRichTaskPromise[A](
|
|
||||||
i: Initialize[Task[PromiseWrap[A]]]
|
|
||||||
): Project.RichTaskPromise[A] =
|
|
||||||
new Project.RichTaskPromise(i)
|
|
||||||
|
|
||||||
def inThisBuild(ss: Seq[Setting[_]]): Seq[Setting[_]] =
|
|
||||||
inScope(ThisScope.copy(project = Select(ThisBuild)))(ss)
|
|
||||||
|
|
||||||
def inConfig(conf: Configuration)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
|
|
||||||
inScope(ThisScope.copy(config = Select(conf)))((configuration :== conf) +: ss)
|
|
||||||
|
|
||||||
def inTask(t: Scoped)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
|
|
||||||
inScope(ThisScope.copy(task = Select(t.key)))(ss)
|
|
||||||
|
|
||||||
def inScope(scope: Scope)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
|
|
||||||
Project.transform(Scope.replaceThis(scope), ss)
|
|
||||||
|
|
||||||
private[sbt] def inThisBuild[T](i: Initialize[T]): Initialize[T] =
|
|
||||||
inScope(ThisScope.copy(project = Select(ThisBuild)), i)
|
|
||||||
|
|
||||||
private[sbt] def inConfig[T](conf: Configuration, i: Initialize[T]): Initialize[T] =
|
|
||||||
inScope(ThisScope.copy(config = Select(conf)), i)
|
|
||||||
|
|
||||||
private[sbt] def inTask[T](t: Scoped, i: Initialize[T]): Initialize[T] =
|
|
||||||
inScope(ThisScope.copy(task = Select(t.key)), i)
|
|
||||||
|
|
||||||
private[sbt] def inScope[T](scope: Scope, i: Initialize[T]): Initialize[T] =
|
|
||||||
i mapReferenced Project.mapScope(Scope.replaceThis(scope))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Project. This is a macro that expects to be assigned directly to a val.
|
|
||||||
* The name of the val is used as the project ID and the name of the base directory of the project.
|
|
||||||
*/
|
|
||||||
def project: Project = macro Project.projectMacroImpl
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,764 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URI
|
||||||
|
import java.util.Locale
|
||||||
|
// import Project._
|
||||||
|
import Keys.{
|
||||||
|
stateBuildStructure,
|
||||||
|
bspEnabled,
|
||||||
|
colorShellPrompt,
|
||||||
|
commands,
|
||||||
|
historyPath,
|
||||||
|
projectCommand,
|
||||||
|
sessionSettings,
|
||||||
|
shellPrompt,
|
||||||
|
templateResolverInfos,
|
||||||
|
autoStartServer,
|
||||||
|
serverHost,
|
||||||
|
serverIdleTimeout,
|
||||||
|
serverLog,
|
||||||
|
serverPort,
|
||||||
|
serverUseJni,
|
||||||
|
serverAuthentication,
|
||||||
|
serverConnectionType,
|
||||||
|
fullServerHandlers,
|
||||||
|
logLevel,
|
||||||
|
windowsServerSecurityLevel,
|
||||||
|
}
|
||||||
|
import Project.LoadAction
|
||||||
|
import Scope.{ Global, ThisScope }
|
||||||
|
import sbt.SlashSyntax0._
|
||||||
|
import Def.{ Flattened, Initialize, ScopedKey, Setting }
|
||||||
|
import sbt.internal.{
|
||||||
|
Load,
|
||||||
|
BuildStructure,
|
||||||
|
LoadedBuild,
|
||||||
|
LoadedBuildUnit,
|
||||||
|
SettingGraph,
|
||||||
|
SettingCompletions,
|
||||||
|
SessionSettings
|
||||||
|
}
|
||||||
|
import sbt.internal.util.{ AttributeKey, AttributeMap, Dag, Relation, Settings, ~> }
|
||||||
|
import sbt.internal.util.Types.const // , idFun }
|
||||||
|
import sbt.internal.util.complete.DefaultParsers
|
||||||
|
import sbt.internal.server.ServerHandler
|
||||||
|
import sbt.librarymanagement.Configuration
|
||||||
|
import sbt.util.{ Show, Level }
|
||||||
|
import sjsonnew.JsonFormat
|
||||||
|
import scala.concurrent.{ Await, TimeoutException }
|
||||||
|
import scala.concurrent.duration.*
|
||||||
|
|
||||||
|
/*
|
||||||
|
sealed trait Project extends ProjectDefinition[ProjectReference] with CompositeProject {
|
||||||
|
def componentProjects: Seq[Project] = this :: Nil
|
||||||
|
|
||||||
|
private[sbt] def copy(
|
||||||
|
id: String = id,
|
||||||
|
base: File = base,
|
||||||
|
aggregate: Seq[ProjectReference] = aggregate,
|
||||||
|
dependencies: Seq[ClasspathDep[ProjectReference]] = dependencies,
|
||||||
|
settings: Seq[Setting[_]] = settings,
|
||||||
|
configurations: Seq[Configuration] = configurations
|
||||||
|
): Project =
|
||||||
|
copy2(id, base, aggregate, dependencies, settings, configurations)
|
||||||
|
|
||||||
|
private[this] def copy2(
|
||||||
|
id: String = id,
|
||||||
|
base: File = base,
|
||||||
|
aggregate: Seq[ProjectReference] = aggregate,
|
||||||
|
dependencies: Seq[ClasspathDep[ProjectReference]] = dependencies,
|
||||||
|
settings: Seq[Setting[_]] = settings,
|
||||||
|
configurations: Seq[Configuration] = configurations,
|
||||||
|
plugins: Plugins = plugins,
|
||||||
|
autoPlugins: Seq[AutoPlugin] = autoPlugins,
|
||||||
|
projectOrigin: ProjectOrigin = projectOrigin,
|
||||||
|
): Project =
|
||||||
|
unresolved(
|
||||||
|
id,
|
||||||
|
base,
|
||||||
|
aggregate = aggregate,
|
||||||
|
dependencies = dependencies,
|
||||||
|
settings = settings,
|
||||||
|
configurations,
|
||||||
|
plugins,
|
||||||
|
autoPlugins,
|
||||||
|
projectOrigin
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
/** Adds new configurations directly to this project. To override an existing configuration, use `overrideConfigs`. */
|
||||||
|
def configs(cs: Configuration*): Project = copy(configurations = configurations ++ cs)
|
||||||
|
|
||||||
|
/** Adds classpath dependencies on internal or external projects. */
|
||||||
|
def dependsOn(deps: ClasspathDep[ProjectReference]*): Project =
|
||||||
|
copy(dependencies = dependencies ++ deps)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds projects to be aggregated. When a user requests a task to run on this project from the command line,
|
||||||
|
* the task will also be run in aggregated projects.
|
||||||
|
*/
|
||||||
|
def aggregate(refs: ProjectReference*): Project =
|
||||||
|
copy(aggregate = (aggregate: Seq[ProjectReference]) ++ refs)
|
||||||
|
|
||||||
|
/** Appends settings to the current settings sequence for this project. */
|
||||||
|
def settings(ss: Def.SettingsDefinition*): Project =
|
||||||
|
copy(settings = (settings: Seq[Def.Setting[_]]) ++ Def.settings(ss: _*))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the [[AutoPlugin]]s of this project.
|
||||||
|
* A [[AutoPlugin]] is a common label that is used by plugins to determine what settings, if any, to enable on a project.
|
||||||
|
*/
|
||||||
|
def enablePlugins(ns: Plugins*): Project = setPlugins(ns.foldLeft(plugins)(Plugins.and))
|
||||||
|
|
||||||
|
/** Disable the given plugins on this project. */
|
||||||
|
def disablePlugins(ps: AutoPlugin*): Project =
|
||||||
|
setPlugins(Plugins.and(plugins, Plugins.And(ps.map(p => Plugins.Exclude(p)).toList)))
|
||||||
|
|
||||||
|
private[sbt] def setPlugins(ns: Plugins): Project = copy2(plugins = ns)
|
||||||
|
|
||||||
|
/** Definitively set the [[AutoPlugin]]s for this project. */
|
||||||
|
private[sbt] def setAutoPlugins(autos: Seq[AutoPlugin]): Project = copy2(autoPlugins = autos)
|
||||||
|
|
||||||
|
/** Definitively set the [[ProjectOrigin]] for this project. */
|
||||||
|
private[sbt] def setProjectOrigin(origin: ProjectOrigin): Project = copy2(projectOrigin = origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed trait ResolvedProject extends ProjectDefinition[ProjectRef] {
|
||||||
|
|
||||||
|
/** The [[AutoPlugin]]s enabled for this project as computed from [[plugins]]. */
|
||||||
|
def autoPlugins: Seq[AutoPlugin]
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
object ProjectExtra extends ProjectExtra:
|
||||||
|
val extraBuildsKey: AttributeKey[List[URI]] = AttributeKey[List[URI]](
|
||||||
|
"extra-builds",
|
||||||
|
"Extra build URIs to load in addition to the ones defined by the project."
|
||||||
|
)
|
||||||
|
val projectReturnKey: AttributeKey[List[File]] =
|
||||||
|
AttributeKey[List[File]]("project-return", "Maintains a stack of builds visited using reload.")
|
||||||
|
|
||||||
|
trait ProjectExtra:
|
||||||
|
import ProjectExtra.projectReturnKey
|
||||||
|
|
||||||
|
def inConfig(conf: Configuration)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
|
||||||
|
Project.inScope(ThisScope.copy(config = Select(conf)))((Keys.configuration :== conf) +: ss)
|
||||||
|
|
||||||
|
extension (self: Project)
|
||||||
|
/** Adds configurations to this project. Added configurations replace existing configurations with the same name. */
|
||||||
|
def overrideConfigs(cs: Configuration*): Project =
|
||||||
|
self.copy(
|
||||||
|
configurations = Defaults.overrideConfigs(cs: _*)(self.configurations),
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds configuration at the *start* of the configuration list for this project. Previous configurations replace this prefix
|
||||||
|
* list with the same name.
|
||||||
|
*/
|
||||||
|
private[sbt] def prefixConfigs(cs: Configuration*): Project =
|
||||||
|
self.copy(
|
||||||
|
configurations = Defaults.overrideConfigs(self.configurations: _*)(cs),
|
||||||
|
)
|
||||||
|
|
||||||
|
extension (m: Project.type)
|
||||||
|
/*
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
private abstract class ProjectDef[PR <: ProjectReference](
|
||||||
|
val id: String,
|
||||||
|
val base: File,
|
||||||
|
val aggregate: Seq[PR],
|
||||||
|
val dependencies: Seq[ClasspathDep[PR]],
|
||||||
|
val settings: Seq[Def.Setting[_]],
|
||||||
|
val configurations: Seq[Configuration],
|
||||||
|
val plugins: Plugins,
|
||||||
|
val autoPlugins: Seq[AutoPlugin],
|
||||||
|
val projectOrigin: ProjectOrigin
|
||||||
|
) extends ProjectDefinition[PR] {
|
||||||
|
// checks for cyclic references here instead of having to do it in Scope.delegates
|
||||||
|
Dag.topologicalSort(configurations)(_.extendsConfigs)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
def showContextKey(state: State): Show[ScopedKey[_]] =
|
||||||
|
showContextKey(state, None)
|
||||||
|
|
||||||
|
def showContextKey(state: State, keyNameColor: Option[String]): Show[ScopedKey[_]] =
|
||||||
|
if (isProjectLoaded(state)) showContextKey2(session(state), keyNameColor)
|
||||||
|
else Def.showFullKey
|
||||||
|
|
||||||
|
// @deprecated("Use showContextKey2 which doesn't take the unused structure param", "1.1.1")
|
||||||
|
// def showContextKey(
|
||||||
|
// session: SessionSettings,
|
||||||
|
// structure: BuildStructure,
|
||||||
|
// keyNameColor: Option[String] = None
|
||||||
|
// ): Show[ScopedKey[_]] =
|
||||||
|
// showContextKey2(session, keyNameColor)
|
||||||
|
|
||||||
|
def showContextKey2(
|
||||||
|
session: SessionSettings,
|
||||||
|
keyNameColor: Option[String] = None
|
||||||
|
): Show[ScopedKey[_]] =
|
||||||
|
Def.showRelativeKey2(session.current, keyNameColor)
|
||||||
|
|
||||||
|
def showLoadingKey(
|
||||||
|
loaded: LoadedBuild,
|
||||||
|
keyNameColor: Option[String] = None
|
||||||
|
): Show[ScopedKey[_]] =
|
||||||
|
Def.showRelativeKey2(
|
||||||
|
ProjectRef(loaded.root, loaded.units(loaded.root).rootProjects.head),
|
||||||
|
keyNameColor
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class Constructor(p: ProjectReference) {
|
||||||
|
def %(conf: Configuration): ClasspathDependency = %(conf.name)
|
||||||
|
|
||||||
|
def %(conf: String): ClasspathDependency = ClasspathDependency(p, Some(conf))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
def getOrError[T](state: State, key: AttributeKey[T], msg: String): T =
|
||||||
|
state.get(key).getOrElse(sys.error(msg))
|
||||||
|
|
||||||
|
def structure(state: State): BuildStructure =
|
||||||
|
Project.getOrError(state, Keys.stateBuildStructure, "No build loaded.")
|
||||||
|
|
||||||
|
def session(state: State): SessionSettings =
|
||||||
|
Project.getOrError(state, Keys.sessionSettings, "Session not initialized.")
|
||||||
|
|
||||||
|
def isProjectLoaded(state: State): Boolean =
|
||||||
|
(state has Keys.sessionSettings) && (state has Keys.stateBuildStructure)
|
||||||
|
|
||||||
|
def extract(state: State): Extracted =
|
||||||
|
Project.extract(Project.session(state), Project.structure(state))
|
||||||
|
|
||||||
|
private[sbt] def extract(se: SessionSettings, st: BuildStructure): Extracted =
|
||||||
|
Extracted(st, se, se.current)(Project.showContextKey2(se))
|
||||||
|
|
||||||
|
def getProjectForReference(ref: Reference, structure: BuildStructure): Option[ResolvedProject] =
|
||||||
|
ref match
|
||||||
|
case pr: ProjectRef => getProject(pr, structure)
|
||||||
|
case _ => None
|
||||||
|
|
||||||
|
def getProject(ref: ProjectRef, structure: BuildStructure): Option[ResolvedProject] =
|
||||||
|
getProject(ref, structure.units)
|
||||||
|
|
||||||
|
def getProject(ref: ProjectRef, structure: LoadedBuild): Option[ResolvedProject] =
|
||||||
|
getProject(ref, structure.units)
|
||||||
|
|
||||||
|
def getProject(ref: ProjectRef, units: Map[URI, LoadedBuildUnit]): Option[ResolvedProject] =
|
||||||
|
(units get ref.build).flatMap(_.defined get ref.project)
|
||||||
|
|
||||||
|
def runUnloadHooks(s: State): State =
|
||||||
|
val previousOnUnload = orIdentity(s get Keys.onUnload.key)
|
||||||
|
previousOnUnload(s.runExitHooks())
|
||||||
|
|
||||||
|
def setProject(session: SessionSettings, structure: BuildStructure, s: State): State =
|
||||||
|
setProject(session, structure, s, identity)
|
||||||
|
|
||||||
|
def setProject(
|
||||||
|
session: SessionSettings,
|
||||||
|
structure: BuildStructure,
|
||||||
|
s: State,
|
||||||
|
preOnLoad: State => State
|
||||||
|
): State = {
|
||||||
|
val unloaded = Project.runUnloadHooks(s)
|
||||||
|
val (onLoad, onUnload) = getHooks(structure.data)
|
||||||
|
val newAttrs = unloaded.attributes
|
||||||
|
.put(stateBuildStructure, structure)
|
||||||
|
.put(sessionSettings, session)
|
||||||
|
.put(Keys.onUnload.key, onUnload)
|
||||||
|
val newState = unloaded.copy(attributes = newAttrs)
|
||||||
|
// TODO: Fix this
|
||||||
|
onLoad(
|
||||||
|
preOnLoad(
|
||||||
|
updateCurrent(newState)
|
||||||
|
) /*LogManager.setGlobalLogLevels(updateCurrent(newState), structure.data)*/
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def orIdentity[A](opt: Option[A => A]): A => A =
|
||||||
|
opt.getOrElse(identity)
|
||||||
|
|
||||||
|
def getHook[A](key: SettingKey[A => A], data: Settings[Scope]): A => A =
|
||||||
|
orIdentity((Global / key) get data)
|
||||||
|
|
||||||
|
def getHooks(data: Settings[Scope]): (State => State, State => State) =
|
||||||
|
(getHook(Keys.onLoad, data), getHook(Keys.onUnload, data))
|
||||||
|
|
||||||
|
def current(state: State): ProjectRef = session(state).current
|
||||||
|
|
||||||
|
def updateCurrent(s: State): State = {
|
||||||
|
val structure = Project.structure(s)
|
||||||
|
val ref = Project.current(s)
|
||||||
|
Load.getProject(structure.units, ref.build, ref.project)
|
||||||
|
val msg = (ref / Keys.onLoadMessage) get structure.data getOrElse ""
|
||||||
|
if (!msg.isEmpty) s.log.info(msg)
|
||||||
|
def get[T](k: SettingKey[T]): Option[T] = (ref / k) get structure.data
|
||||||
|
def commandsIn(axis: ResolvedReference) = (axis / commands) get structure.data toList
|
||||||
|
|
||||||
|
val allCommands = commandsIn(ref) ++ commandsIn(
|
||||||
|
BuildRef(ref.build)
|
||||||
|
) ++ ((Global / commands) get structure.data toList)
|
||||||
|
val history = get(historyPath).flatMap(identity)
|
||||||
|
val prompt = get(shellPrompt)
|
||||||
|
val newPrompt = get(colorShellPrompt)
|
||||||
|
val trs = ((Global / templateResolverInfos) get structure.data).toList.flatten
|
||||||
|
val startSvr: Option[Boolean] = get(autoStartServer)
|
||||||
|
val host: Option[String] = get(serverHost)
|
||||||
|
val port: Option[Int] = get(serverPort)
|
||||||
|
val enabledBsp: Option[Boolean] = get(bspEnabled)
|
||||||
|
val timeout: Option[Option[FiniteDuration]] = get(serverIdleTimeout)
|
||||||
|
val authentication: Option[Set[ServerAuthentication]] = get(serverAuthentication)
|
||||||
|
val connectionType: Option[ConnectionType] = get(serverConnectionType)
|
||||||
|
val srvLogLevel: Option[Level.Value] = (ref / serverLog / logLevel).get(structure.data)
|
||||||
|
val hs: Option[Seq[ServerHandler]] = get(ThisBuild / fullServerHandlers)
|
||||||
|
val commandDefs = allCommands.distinct.flatten[Command].map(_ tag (projectCommand, true))
|
||||||
|
val newDefinedCommands = commandDefs ++ BasicCommands.removeTagged(
|
||||||
|
s.definedCommands,
|
||||||
|
projectCommand
|
||||||
|
)
|
||||||
|
val winSecurityLevel = get(windowsServerSecurityLevel).getOrElse(2)
|
||||||
|
val useJni = get(serverUseJni).getOrElse(false)
|
||||||
|
val newAttrs =
|
||||||
|
s.attributes
|
||||||
|
.put(historyPath.key, history)
|
||||||
|
.put(windowsServerSecurityLevel.key, winSecurityLevel)
|
||||||
|
.put(serverUseJni.key, useJni)
|
||||||
|
.setCond(bspEnabled.key, enabledBsp)
|
||||||
|
.setCond(autoStartServer.key, startSvr)
|
||||||
|
.setCond(serverPort.key, port)
|
||||||
|
.setCond(serverHost.key, host)
|
||||||
|
.setCond(serverAuthentication.key, authentication)
|
||||||
|
.setCond(serverConnectionType.key, connectionType)
|
||||||
|
.setCond(serverIdleTimeout.key, timeout)
|
||||||
|
.put(historyPath.key, history)
|
||||||
|
.put(templateResolverInfos.key, trs)
|
||||||
|
.setCond(shellPrompt.key, prompt)
|
||||||
|
.setCond(colorShellPrompt.key, newPrompt)
|
||||||
|
.setCond(BasicKeys.serverLogLevel, srvLogLevel)
|
||||||
|
.setCond(fullServerHandlers.key, hs)
|
||||||
|
s.copy(
|
||||||
|
attributes = newAttrs,
|
||||||
|
definedCommands = newDefinedCommands
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def setCond[T](key: AttributeKey[T], vopt: Option[T], attributes: AttributeMap): AttributeMap =
|
||||||
|
attributes.setCond(key, vopt)
|
||||||
|
|
||||||
|
private[sbt] def checkTargets(data: Settings[Scope]): Option[String] =
|
||||||
|
val dups = overlappingTargets(allTargets(data))
|
||||||
|
if (dups.isEmpty) None
|
||||||
|
else {
|
||||||
|
val dupStrs = dups map { case (dir, scopes) =>
|
||||||
|
s"${dir.getAbsolutePath}:\n\t${scopes.mkString("\n\t")}"
|
||||||
|
}
|
||||||
|
Some(s"Overlapping output directories:${dupStrs.mkString}")
|
||||||
|
}
|
||||||
|
|
||||||
|
private[this] def overlappingTargets(
|
||||||
|
targets: Seq[(ProjectRef, File)]
|
||||||
|
): Map[File, Seq[ProjectRef]] =
|
||||||
|
targets.groupBy(_._2).filter(_._2.size > 1).mapValues(_.map(_._1)).toMap
|
||||||
|
|
||||||
|
private[this] def allTargets(data: Settings[Scope]): Seq[(ProjectRef, File)] = {
|
||||||
|
import ScopeFilter._
|
||||||
|
val allProjects = ScopeFilter(Make.inAnyProject)
|
||||||
|
val targetAndRef = Def.setting { (Keys.thisProjectRef.value, Keys.target.value) }
|
||||||
|
new SettingKeyAll(Def.optional(targetAndRef)(identity))
|
||||||
|
.all(allProjects)
|
||||||
|
.evaluate(data)
|
||||||
|
.flatMap(x => x)
|
||||||
|
}
|
||||||
|
|
||||||
|
private[sbt] def equalKeys(a: ScopedKey[_], b: ScopedKey[_], mask: ScopeMask): Boolean =
|
||||||
|
a.key == b.key && Scope.equal(a.scope, b.scope, mask)
|
||||||
|
|
||||||
|
def delegates(
|
||||||
|
structure: BuildStructure,
|
||||||
|
scope: Scope,
|
||||||
|
key: AttributeKey[_]
|
||||||
|
): Seq[ScopedKey[_]] =
|
||||||
|
structure.delegates(scope).map(d => ScopedKey(d, key))
|
||||||
|
|
||||||
|
private[sbt] def scopedKeyData(
|
||||||
|
structure: BuildStructure,
|
||||||
|
scope: Scope,
|
||||||
|
key: AttributeKey[_]
|
||||||
|
): Option[ScopedKeyData[_]] =
|
||||||
|
structure.data.get(scope, key) map { v =>
|
||||||
|
ScopedKeyData(ScopedKey(scope, key), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
def details(structure: BuildStructure, actual: Boolean, scope: Scope, key: AttributeKey[_])(
|
||||||
|
using display: Show[ScopedKey[_]]
|
||||||
|
): String = {
|
||||||
|
val scoped = ScopedKey(scope, key)
|
||||||
|
|
||||||
|
val data = scopedKeyData(structure, scope, key) map { _.description } getOrElse {
|
||||||
|
"No entry for key."
|
||||||
|
}
|
||||||
|
val description = key.description match {
|
||||||
|
case Some(desc) => "Description:\n\t" + desc + "\n"; case None => ""
|
||||||
|
}
|
||||||
|
|
||||||
|
val definingScope = structure.data.definingScope(scope, key)
|
||||||
|
val providedBy = definingScope match {
|
||||||
|
case Some(sc) => "Provided by:\n\t" + Scope.display(sc, key.label) + "\n"
|
||||||
|
case None => ""
|
||||||
|
}
|
||||||
|
val definingScoped = definingScope match {
|
||||||
|
case Some(sc) => ScopedKey(sc, key)
|
||||||
|
case None => scoped
|
||||||
|
}
|
||||||
|
val comp =
|
||||||
|
Def.compiled(structure.settings, actual)(using
|
||||||
|
structure.delegates,
|
||||||
|
structure.scopeLocal,
|
||||||
|
display
|
||||||
|
)
|
||||||
|
val definedAt = comp get definingScoped map { c =>
|
||||||
|
Def.definedAtString(c.settings).capitalize
|
||||||
|
} getOrElse ""
|
||||||
|
|
||||||
|
val cMap = Def.flattenLocals(comp)
|
||||||
|
val related = cMap.keys.filter(k => k.key == key && k.scope != scope)
|
||||||
|
def derivedDependencies(c: ScopedKey[_]): List[ScopedKey[_]] =
|
||||||
|
comp
|
||||||
|
.get(c)
|
||||||
|
.map(_.settings.flatMap(s => if (s.isDerived) s.dependencies else Nil))
|
||||||
|
.toList
|
||||||
|
.flatten
|
||||||
|
|
||||||
|
val depends = cMap.get(scoped) match {
|
||||||
|
case Some(c) => c.dependencies.toSet; case None => Set.empty
|
||||||
|
}
|
||||||
|
val derivedDepends: Set[ScopedKey[_]] = derivedDependencies(definingScoped).toSet
|
||||||
|
|
||||||
|
val reverse = Project.reverseDependencies(cMap, scoped)
|
||||||
|
val derivedReverse =
|
||||||
|
reverse.filter(r => derivedDependencies(r).contains(definingScoped)).toSet
|
||||||
|
|
||||||
|
def printDepScopes(
|
||||||
|
baseLabel: String,
|
||||||
|
derivedLabel: String,
|
||||||
|
scopes: Iterable[ScopedKey[_]],
|
||||||
|
derived: Set[ScopedKey[_]]
|
||||||
|
): String = {
|
||||||
|
val label = s"$baseLabel${if (derived.isEmpty) "" else s" (D=$derivedLabel)"}"
|
||||||
|
val prefix: ScopedKey[_] => String =
|
||||||
|
if (derived.isEmpty) const("") else sk => if (derived(sk)) "D " else " "
|
||||||
|
printScopes(label, scopes, prefix = prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
def printScopes(
|
||||||
|
label: String,
|
||||||
|
scopes: Iterable[ScopedKey[_]],
|
||||||
|
max: Int = Int.MaxValue,
|
||||||
|
prefix: ScopedKey[_] => String = const("")
|
||||||
|
) =
|
||||||
|
if (scopes.isEmpty) ""
|
||||||
|
else {
|
||||||
|
val (limited, more) =
|
||||||
|
if (scopes.size <= max) (scopes, "\n") else (scopes.take(max), "\n...\n")
|
||||||
|
limited.map(sk => prefix(sk) + display.show(sk)).mkString(label + ":\n\t", "\n\t", more)
|
||||||
|
}
|
||||||
|
|
||||||
|
data + "\n" +
|
||||||
|
description +
|
||||||
|
providedBy +
|
||||||
|
definedAt +
|
||||||
|
printDepScopes("Dependencies", "derived from", depends, derivedDepends) +
|
||||||
|
printDepScopes("Reverse dependencies", "derives", reverse, derivedReverse) +
|
||||||
|
printScopes("Delegates", delegates(structure, scope, key)) +
|
||||||
|
printScopes("Related", related, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
def settingGraph(structure: BuildStructure, basedir: File, scoped: ScopedKey[_])(using
|
||||||
|
display: Show[ScopedKey[_]]
|
||||||
|
): SettingGraph =
|
||||||
|
SettingGraph(structure, basedir, scoped, 0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
def graphSettings(structure: BuildStructure, basedir: File)(implicit
|
||||||
|
display: Show[ScopedKey[_]]
|
||||||
|
): Unit = {
|
||||||
|
def graph(actual: Boolean, name: String) =
|
||||||
|
graphSettings(structure, actual, name, new File(basedir, name + ".dot"))
|
||||||
|
graph(true, "actual_dependencies")
|
||||||
|
graph(false, "declared_dependencies")
|
||||||
|
}
|
||||||
|
def graphSettings(structure: BuildStructure, actual: Boolean, graphName: String, file: File)(
|
||||||
|
implicit display: Show[ScopedKey[_]]
|
||||||
|
): Unit = {
|
||||||
|
val rel = relation(structure, actual)
|
||||||
|
val keyToString = display.show _
|
||||||
|
DotGraph.generateGraph(file, graphName, rel, keyToString, keyToString)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
def relation(structure: BuildStructure, actual: Boolean)(using
|
||||||
|
display: Show[ScopedKey[_]]
|
||||||
|
): Relation[ScopedKey[_], ScopedKey[_]] =
|
||||||
|
relation(structure.settings, actual)(using
|
||||||
|
structure.delegates,
|
||||||
|
structure.scopeLocal,
|
||||||
|
display,
|
||||||
|
)
|
||||||
|
|
||||||
|
private[sbt] def relation(settings: Seq[Def.Setting[_]], actual: Boolean)(using
|
||||||
|
delegates: Scope => Seq[Scope],
|
||||||
|
scopeLocal: Def.ScopeLocal,
|
||||||
|
display: Show[ScopedKey[_]]
|
||||||
|
): Relation[ScopedKey[_], ScopedKey[_]] =
|
||||||
|
val cMap = Def.flattenLocals(Def.compiled(settings, actual))
|
||||||
|
val emptyRelation = Relation.empty[ScopedKey[_], ScopedKey[_]]
|
||||||
|
cMap.foldLeft(emptyRelation) { case (r, (key, value)) =>
|
||||||
|
r + (key, value.dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
private[sbt] def showDefinitions(key: AttributeKey[_], defs: Seq[Scope])(using
|
||||||
|
display: Show[ScopedKey[_]]
|
||||||
|
): String =
|
||||||
|
showKeys(defs.map(scope => ScopedKey(scope, key)))
|
||||||
|
|
||||||
|
private[sbt] def showUses(defs: Seq[ScopedKey[_]])(using display: Show[ScopedKey[_]]): String =
|
||||||
|
showKeys(defs)
|
||||||
|
|
||||||
|
private[this] def showKeys(s: Seq[ScopedKey[_]])(using display: Show[ScopedKey[_]]): String =
|
||||||
|
s.map(display.show).sorted.mkString("\n\t", "\n\t", "\n\n")
|
||||||
|
|
||||||
|
private[sbt] def definitions(structure: BuildStructure, actual: Boolean, key: AttributeKey[_])(
|
||||||
|
using display: Show[ScopedKey[_]]
|
||||||
|
): Seq[Scope] =
|
||||||
|
relation(structure, actual)(using display)._1s.toSeq flatMap { sk =>
|
||||||
|
if (sk.key == key) sk.scope :: Nil else Nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private[sbt] def usedBy(structure: BuildStructure, actual: Boolean, key: AttributeKey[_])(using
|
||||||
|
display: Show[ScopedKey[_]]
|
||||||
|
): Seq[ScopedKey[_]] =
|
||||||
|
relation(structure, actual)(using display).all.toSeq flatMap { case (a, b) =>
|
||||||
|
if (b.key == key) List[ScopedKey[_]](a) else Nil
|
||||||
|
}
|
||||||
|
|
||||||
|
def reverseDependencies(
|
||||||
|
cMap: Map[ScopedKey[_], Flattened],
|
||||||
|
scoped: ScopedKey[_]
|
||||||
|
): Iterable[ScopedKey[_]] =
|
||||||
|
for {
|
||||||
|
(key, compiled) <- cMap
|
||||||
|
dep <- compiled.dependencies if dep == scoped
|
||||||
|
} yield key
|
||||||
|
|
||||||
|
/*
|
||||||
|
def setAll(extracted: Extracted, settings: Seq[Def.Setting[_]]): SessionSettings =
|
||||||
|
SettingCompletions.setAll(extracted, settings).session
|
||||||
|
*/
|
||||||
|
|
||||||
|
def extraBuilds(s: State): List[URI] =
|
||||||
|
getOrNil(s, ProjectExtra.extraBuildsKey)
|
||||||
|
def getOrNil[A](s: State, key: AttributeKey[List[A]]): List[A] =
|
||||||
|
s.get(key).getOrElse(Nil)
|
||||||
|
def setExtraBuilds(s: State, extra: List[URI]): State =
|
||||||
|
s.put(ProjectExtra.extraBuildsKey, extra)
|
||||||
|
def addExtraBuilds(s: State, extra: List[URI]): State =
|
||||||
|
setExtraBuilds(s, extra ::: extraBuilds(s))
|
||||||
|
def removeExtraBuilds(s: State, remove: List[URI]): State =
|
||||||
|
updateExtraBuilds(s, _.filterNot(remove.toSet))
|
||||||
|
def updateExtraBuilds(s: State, f: List[URI] => List[URI]): State =
|
||||||
|
setExtraBuilds(s, f(extraBuilds(s)))
|
||||||
|
|
||||||
|
// used by Coursier integration
|
||||||
|
private[sbt] def transitiveInterDependencies(
|
||||||
|
state: State,
|
||||||
|
projectRef: ProjectRef
|
||||||
|
): Seq[ProjectRef] = {
|
||||||
|
def dependencies(map: Map[ProjectRef, Seq[ProjectRef]], id: ProjectRef): Set[ProjectRef] = {
|
||||||
|
def helper(map: Map[ProjectRef, Seq[ProjectRef]], acc: Set[ProjectRef]): Set[ProjectRef] =
|
||||||
|
if (acc.exists(map.contains)) {
|
||||||
|
val (kept, rem) = map.partition { case (k, _) => acc(k) }
|
||||||
|
helper(rem, acc ++ kept.valuesIterator.flatten)
|
||||||
|
} else acc
|
||||||
|
helper(map - id, map.getOrElse(id, Nil).toSet)
|
||||||
|
}
|
||||||
|
val allProjectsDeps: Map[ProjectRef, Seq[ProjectRef]] =
|
||||||
|
(for {
|
||||||
|
(p, ref) <- Project.structure(state).allProjectPairs
|
||||||
|
} yield ref -> p.dependencies.map(_.project)).toMap
|
||||||
|
val deps = dependencies(allProjectsDeps.toMap, projectRef)
|
||||||
|
Project.structure(state).allProjectRefs.filter(p => deps(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
def projectReturn(s: State): List[File] = getOrNil(s, projectReturnKey)
|
||||||
|
def inPluginProject(s: State): Boolean = projectReturn(s).length > 1
|
||||||
|
def setProjectReturn(s: State, pr: List[File]): State =
|
||||||
|
s.copy(attributes = s.attributes.put(projectReturnKey, pr))
|
||||||
|
|
||||||
|
def loadAction(s: State, action: LoadAction): (State, File) =
|
||||||
|
action match
|
||||||
|
case LoadAction.Return =>
|
||||||
|
projectReturn(s) match
|
||||||
|
case _ /* current */ :: returnTo :: rest =>
|
||||||
|
(setProjectReturn(s, returnTo :: rest), returnTo)
|
||||||
|
case _ => sys.error("Not currently in a plugin definition")
|
||||||
|
|
||||||
|
case LoadAction.Current =>
|
||||||
|
val base = s.configuration.baseDirectory
|
||||||
|
projectReturn(s) match
|
||||||
|
case Nil => (setProjectReturn(s, base :: Nil), base); case x :: _ => (s, x)
|
||||||
|
|
||||||
|
case LoadAction.Plugins =>
|
||||||
|
val (newBase, oldStack) =
|
||||||
|
if Project.isProjectLoaded(s) then
|
||||||
|
(Project.extract(s).currentUnit.unit.plugins.base, projectReturn(s))
|
||||||
|
else // support changing to the definition project if it fails to load
|
||||||
|
(BuildPaths.projectStandard(s.baseDir), s.baseDir :: Nil)
|
||||||
|
val newS = setProjectReturn(s, newBase :: oldStack)
|
||||||
|
(newS, newBase)
|
||||||
|
|
||||||
|
/*
|
||||||
|
def runTask[T](
|
||||||
|
taskKey: ScopedKey[Task[T]],
|
||||||
|
state: State,
|
||||||
|
checkCycles: Boolean = false
|
||||||
|
): Option[(State, Result[T])] = {
|
||||||
|
val extracted = Project.extract(state)
|
||||||
|
val ch = EvaluateTask.cancelStrategy(extracted, extracted.structure, state)
|
||||||
|
val p = EvaluateTask.executeProgress(extracted, extracted.structure, state)
|
||||||
|
val r = EvaluateTask.restrictions(state)
|
||||||
|
val fgc = EvaluateTask.forcegc(extracted, extracted.structure)
|
||||||
|
val mfi = EvaluateTask.minForcegcInterval(extracted, extracted.structure)
|
||||||
|
runTask(taskKey, state, EvaluateTaskConfig(r, checkCycles, p, ch, fgc, mfi))
|
||||||
|
}
|
||||||
|
|
||||||
|
def runTask[T](
|
||||||
|
taskKey: ScopedKey[Task[T]],
|
||||||
|
state: State,
|
||||||
|
config: EvaluateTaskConfig
|
||||||
|
): Option[(State, Result[T])] = {
|
||||||
|
val extracted = Project.extract(state)
|
||||||
|
EvaluateTask(extracted.structure, taskKey, state, extracted.currentRef, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
def projectToRef(p: Project): ProjectReference = LocalProject(p.id)
|
||||||
|
|
||||||
|
implicit def projectToLocalProject(p: Project): LocalProject = LocalProject(p.id)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
extension [A1](in: Def.Initialize[Task[A1]])
|
||||||
|
def updateState(f: (State, A1) => State): Def.Initialize[Task[A1]] =
|
||||||
|
in(t => SessionVar.transform(t, f))
|
||||||
|
|
||||||
|
def storeAs(key: TaskKey[A1])(using f: JsonFormat[A1]): Def.Initialize[Task[A1]] =
|
||||||
|
Keys.resolvedScoped.zipWith(in) { (scoped, task) =>
|
||||||
|
SessionVar.transform(
|
||||||
|
task,
|
||||||
|
(state, value) =>
|
||||||
|
SessionVar.persistAndSet(
|
||||||
|
SessionVar.resolveContext(key, scoped.scope, state),
|
||||||
|
state,
|
||||||
|
value
|
||||||
|
)(f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def keepAs(key: TaskKey[A1]): Def.Initialize[Task[A1]] =
|
||||||
|
in.zipWith(Keys.resolvedScoped) { (t, scoped) =>
|
||||||
|
SessionVar.transform(
|
||||||
|
t,
|
||||||
|
(state, value) =>
|
||||||
|
SessionVar.set(SessionVar.resolveContext(key, scoped.scope, state), state, value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* implicitly injected to tasks that return PromiseWrap.
|
||||||
|
*/
|
||||||
|
extension [A1](in: Initialize[Task[PromiseWrap[A1]]])
|
||||||
|
def await: Def.Initialize[Task[A1]] = await(Duration.Inf)
|
||||||
|
def await(atMost: Duration): Def.Initialize[Task[A1]] =
|
||||||
|
(Def
|
||||||
|
.task {
|
||||||
|
val p = in.value
|
||||||
|
var result: Option[A1] = None
|
||||||
|
if atMost == Duration.Inf then
|
||||||
|
while result.isEmpty do
|
||||||
|
try {
|
||||||
|
result = Some(Await.result(p.underlying.future, Duration("1s")))
|
||||||
|
Thread.sleep(10)
|
||||||
|
} catch {
|
||||||
|
case _: TimeoutException => ()
|
||||||
|
}
|
||||||
|
else result = Some(Await.result(p.underlying.future, atMost))
|
||||||
|
result.get
|
||||||
|
})
|
||||||
|
.tag(Tags.Sentinel)
|
||||||
|
|
||||||
|
/*
|
||||||
|
import scala.reflect.macros._
|
||||||
|
|
||||||
|
def projectMacroImpl(c: blackbox.Context): c.Expr[Project] = {
|
||||||
|
import c.universe._
|
||||||
|
val enclosingValName = std.KeyMacro.definingValName(
|
||||||
|
c,
|
||||||
|
methodName =>
|
||||||
|
s"""$methodName must be directly assigned to a val, such as `val x = $methodName`. Alternatively, you can use `sbt.Project.apply`"""
|
||||||
|
)
|
||||||
|
val name = c.Expr[String](Literal(Constant(enclosingValName)))
|
||||||
|
reify { Project(name.splice, new File(name.splice)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit def configDependencyConstructor[T](
|
||||||
|
p: T
|
||||||
|
)(implicit ev: T => ProjectReference): Constructor =
|
||||||
|
new Constructor(p)
|
||||||
|
|
||||||
|
implicit def classpathDependency[T](
|
||||||
|
p: T
|
||||||
|
)(implicit ev: T => ProjectReference): ClasspathDependency = ClasspathDependency(p, None)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Duplicated with Structure
|
||||||
|
|
||||||
|
// These used to be in Project so that they didn't need to get imported (due to Initialize being nested in Project).
|
||||||
|
// Moving Initialize and other settings types to Def and decoupling Project, Def, and Structure means these go here for now
|
||||||
|
implicit def richInitializeTask[T](init: Initialize[Task[T]]): Scoped.RichInitializeTask[T] =
|
||||||
|
new Scoped.RichInitializeTask(init)
|
||||||
|
|
||||||
|
/*
|
||||||
|
implicit def richInitializeInputTask[T](
|
||||||
|
init: Initialize[InputTask[T]]
|
||||||
|
): Scoped.RichInitializeInputTask[T] =
|
||||||
|
new Scoped.RichInitializeInputTask(init)
|
||||||
|
|
||||||
|
implicit def richInitialize[T](i: Initialize[T]): Scoped.RichInitialize[T] =
|
||||||
|
new Scoped.RichInitialize[T](i)
|
||||||
|
|
||||||
|
implicit def richTaskSessionVar[T](init: Initialize[Task[T]]): Project.RichTaskSessionVar[T] =
|
||||||
|
new Project.RichTaskSessionVar(init)
|
||||||
|
|
||||||
|
implicit def sbtRichTaskPromise[A](
|
||||||
|
i: Initialize[Task[PromiseWrap[A]]]
|
||||||
|
): Project.RichTaskPromise[A] =
|
||||||
|
new Project.RichTaskPromise(i)
|
||||||
|
*/
|
||||||
|
end ProjectExtra
|
||||||
|
|
@ -17,7 +17,9 @@ import org.apache.ivy.core.resolve.DownloadOptions
|
||||||
import org.apache.ivy.plugins.resolver.DependencyResolver
|
import org.apache.ivy.plugins.resolver.DependencyResolver
|
||||||
import sbt.Defaults.prefix
|
import sbt.Defaults.prefix
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
import sbt.Project._
|
import sbt.Project.*
|
||||||
|
import sbt.ProjectExtra.inConfig
|
||||||
|
import sbt.ProjectExtra.richInitializeTask
|
||||||
import sbt.ScopeFilter.Make._
|
import sbt.ScopeFilter.Make._
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.coursierint.LMCoursier
|
import sbt.coursierint.LMCoursier
|
||||||
|
|
@ -159,7 +161,9 @@ object RemoteCache {
|
||||||
.withResolvers(rs)
|
.withResolvers(rs)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
) ++ inConfig(Compile)(configCacheSettings(compileArtifact(Compile, cachedCompileClassifier)))
|
) ++ inConfig(Compile)(
|
||||||
|
configCacheSettings(compileArtifact(Compile, cachedCompileClassifier))
|
||||||
|
)
|
||||||
++ inConfig(Test)(configCacheSettings(testArtifact(Test, cachedTestClassifier))))
|
++ inConfig(Test)(configCacheSettings(testArtifact(Test, cachedTestClassifier))))
|
||||||
|
|
||||||
def getResourceFilePaths() = Def.task {
|
def getResourceFilePaths() = Def.task {
|
||||||
|
|
@ -183,7 +187,7 @@ object RemoteCache {
|
||||||
if (af.exists && artp.length() > 0) {
|
if (af.exists && artp.length() > 0) {
|
||||||
JarUtils.includeInJar(artp, Vector(af -> s"META-INF/inc_compile.zip"))
|
JarUtils.includeInJar(artp, Vector(af -> s"META-INF/inc_compile.zip"))
|
||||||
}
|
}
|
||||||
val rf = getResourceFilePaths.value
|
val rf = getResourceFilePaths().value
|
||||||
if (rf.exists) {
|
if (rf.exists) {
|
||||||
JarUtils.includeInJar(artp, Vector(rf -> s"META-INF/copy-resources.txt"))
|
JarUtils.includeInJar(artp, Vector(rf -> s"META-INF/copy-resources.txt"))
|
||||||
}
|
}
|
||||||
|
|
@ -271,12 +275,12 @@ object RemoteCache {
|
||||||
val smi = scalaModuleInfo.value
|
val smi = scalaModuleInfo.value
|
||||||
val artifacts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value
|
val artifacts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value
|
||||||
val nonPom = artifacts.filterNot(isPomArtifact).toVector
|
val nonPom = artifacts.filterNot(isPomArtifact).toVector
|
||||||
val copyResources = getResourceFilePaths.value
|
val copyResources = getResourceFilePaths().value
|
||||||
m.withModule(log) { case (ivy, md, _) =>
|
m.withModule(log) { case (ivy, md, _) =>
|
||||||
val resolver = ivy.getSettings.getResolver(r.name)
|
val resolver = ivy.getSettings.getResolver(r.name)
|
||||||
if (resolver eq null) sys.error(s"undefined resolver '${r.name}'")
|
if (resolver eq null) sys.error(s"undefined resolver '${r.name}'")
|
||||||
val cross = CrossVersion(p, smi)
|
val cross = CrossVersion(p, smi)
|
||||||
val crossf: String => String = cross.getOrElse(identity _)
|
val crossf: String => String = cross.getOrElse(identity[String](_))
|
||||||
var found = false
|
var found = false
|
||||||
ids foreach { (id: String) =>
|
ids foreach { (id: String) =>
|
||||||
val v = toVersion(id)
|
val v = toVersion(id)
|
||||||
|
|
@ -12,6 +12,7 @@ import sbt.internal.util.{ AttributeKey, Dag, Types }
|
||||||
import sbt.librarymanagement.{ ConfigRef, Configuration }
|
import sbt.librarymanagement.{ ConfigRef, Configuration }
|
||||||
import Types.const
|
import Types.const
|
||||||
import Def.Initialize
|
import Def.Initialize
|
||||||
|
import sbt.Project.inScope
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
object ScopeFilter {
|
object ScopeFilter {
|
||||||
|
|
@ -64,27 +65,36 @@ object ScopeFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class SettingKeyAll[T] private[sbt] (i: Initialize[T]) {
|
final class SettingKeyAll[A] private[sbt] (i: Initialize[A]):
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the initialization in all scopes selected by the filter. These are dynamic dependencies, so
|
* Evaluates the initialization in all scopes selected by the filter. These are dynamic dependencies, so
|
||||||
* static inspections will not show them.
|
* static inspections will not show them.
|
||||||
*/
|
*/
|
||||||
def all(sfilter: => ScopeFilter): Initialize[Seq[T]] = Def.bind(getData) { data =>
|
def all(sfilter: => ScopeFilter): Initialize[Seq[A]] =
|
||||||
data.allScopes.toSeq.filter(sfilter(data)).map(s => Project.inScope(s, i)).join
|
Def.flatMap(getData) { data =>
|
||||||
}
|
data.allScopes.toSeq
|
||||||
}
|
.filter(sfilter(data))
|
||||||
final class TaskKeyAll[T] private[sbt] (i: Initialize[Task[T]]) {
|
.map(s => Project.inScope(s, i))
|
||||||
|
.join
|
||||||
|
}
|
||||||
|
end SettingKeyAll
|
||||||
|
|
||||||
|
final class TaskKeyAll[A] private[sbt] (i: Initialize[Task[A]]):
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the task in all scopes selected by the filter. These are dynamic dependencies, so
|
* Evaluates the task in all scopes selected by the filter. These are dynamic dependencies, so
|
||||||
* static inspections will not show them.
|
* static inspections will not show them.
|
||||||
*/
|
*/
|
||||||
def all(sfilter: => ScopeFilter): Initialize[Task[Seq[T]]] = Def.bind(getData) { data =>
|
def all(sfilter: => ScopeFilter): Initialize[Task[Seq[A]]] =
|
||||||
import std.TaskExtra._
|
Def.flatMap(getData) { data =>
|
||||||
data.allScopes.toSeq.filter(sfilter(data)).map(s => Project.inScope(s, i)).join(_.join)
|
import std.TaskExtra._
|
||||||
}
|
data.allScopes.toSeq
|
||||||
}
|
.filter(sfilter(data))
|
||||||
|
.map(s => Project.inScope(s, i))
|
||||||
|
.join(_.join)
|
||||||
|
}
|
||||||
|
end TaskKeyAll
|
||||||
|
|
||||||
private[sbt] val Make = new Make {}
|
private[sbt] val Make = new Make {}
|
||||||
trait Make {
|
trait Make {
|
||||||
|
|
@ -219,6 +229,7 @@ object ScopeFilter {
|
||||||
aggregate: Boolean
|
aggregate: Boolean
|
||||||
): ProjectRef => Seq[ProjectRef] =
|
): ProjectRef => Seq[ProjectRef] =
|
||||||
ref =>
|
ref =>
|
||||||
|
import sbt.ProjectExtra.getProject
|
||||||
Project.getProject(ref, structure).toList flatMap { p =>
|
Project.getProject(ref, structure).toList flatMap { p =>
|
||||||
(if (classpath) p.dependencies.map(_.project) else Nil) ++
|
(if (classpath) p.dependencies.map(_.project) else Nil) ++
|
||||||
(if (aggregate) p.aggregate else Nil)
|
(if (aggregate) p.aggregate else Nil)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import java.io.File
|
||||||
import sbt.Def._
|
import sbt.Def._
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
import sbt.nio.Keys._
|
import sbt.nio.Keys._
|
||||||
import sbt.Project._
|
import sbt.ProjectExtra.richInitializeTask
|
||||||
import sbt.ScopeFilter.Make._
|
import sbt.ScopeFilter.Make._
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.internal.inc.ModuleUtilities
|
import sbt.internal.inc.ModuleUtilities
|
||||||
|
|
@ -62,7 +62,9 @@ object ScriptedPlugin extends AutoPlugin {
|
||||||
override lazy val projectSettings: Seq[Setting[_]] = Seq(
|
override lazy val projectSettings: Seq[Setting[_]] = Seq(
|
||||||
ivyConfigurations ++= Seq(ScriptedConf, ScriptedLaunchConf),
|
ivyConfigurations ++= Seq(ScriptedConf, ScriptedLaunchConf),
|
||||||
scriptedSbt := (pluginCrossBuild / sbtVersion).value,
|
scriptedSbt := (pluginCrossBuild / sbtVersion).value,
|
||||||
sbtLauncher := getJars(ScriptedLaunchConf).map(_.get().head).value,
|
sbtLauncher := getJars(ScriptedLaunchConf)
|
||||||
|
.map(_.get().head)
|
||||||
|
.value,
|
||||||
sbtTestDirectory := sourceDirectory.value / "sbt-test",
|
sbtTestDirectory := sourceDirectory.value / "sbt-test",
|
||||||
libraryDependencies ++= (CrossVersion.partialVersion(scriptedSbt.value) match {
|
libraryDependencies ++= (CrossVersion.partialVersion(scriptedSbt.value) match {
|
||||||
case Some((0, 13)) =>
|
case Some((0, 13)) =>
|
||||||
|
|
@ -174,20 +176,21 @@ object ScriptedPlugin extends AutoPlugin {
|
||||||
(token(Space) ~> (PagedIds | testIdAsGroup)).* map (_.flatten)
|
(token(Space) ~> (PagedIds | testIdAsGroup)).* map (_.flatten)
|
||||||
}
|
}
|
||||||
|
|
||||||
private[sbt] def scriptedTask: Initialize[InputTask[Unit]] = Def.inputTask {
|
private[sbt] def scriptedTask: Initialize[InputTask[Unit]] =
|
||||||
val args = scriptedParser(sbtTestDirectory.value).parsed
|
Def.inputTask {
|
||||||
Def.unit(scriptedDependencies.value)
|
val args = scriptedParser(sbtTestDirectory.value).parsed
|
||||||
scriptedRun.value.run(
|
Def.unit(scriptedDependencies.value)
|
||||||
sbtTestDirectory.value,
|
scriptedRun.value.run(
|
||||||
scriptedBufferLog.value,
|
sbtTestDirectory.value,
|
||||||
args,
|
scriptedBufferLog.value,
|
||||||
sbtLauncher.value,
|
args,
|
||||||
Fork.javaCommand((scripted / javaHome).value, "java").getAbsolutePath,
|
sbtLauncher.value,
|
||||||
scriptedLaunchOpts.value,
|
Fork.javaCommand((scripted / javaHome).value, "java").getAbsolutePath,
|
||||||
new java.util.ArrayList[File](),
|
scriptedLaunchOpts.value,
|
||||||
scriptedParallelInstances.value
|
new java.util.ArrayList[File](),
|
||||||
)
|
scriptedParallelInstances.value
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private[this] def getJars(config: Configuration): Initialize[Task[PathFinder]] = Def.task {
|
private[this] def getJars(config: Configuration): Initialize[Task[PathFinder]] = Def.task {
|
||||||
PathFinder(Classpaths.managedJars(config, classpathTypes.value, Keys.update.value).map(_.data))
|
PathFinder(Classpaths.managedJars(config, classpathTypes.value, Keys.update.value).map(_.data))
|
||||||
|
|
@ -15,6 +15,7 @@ import Def.ScopedKey
|
||||||
import Types.Id
|
import Types.Id
|
||||||
import Keys.sessionVars
|
import Keys.sessionVars
|
||||||
import sjsonnew.JsonFormat
|
import sjsonnew.JsonFormat
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
|
|
||||||
object SessionVar {
|
object SessionVar {
|
||||||
val DefaultDataID = "data"
|
val DefaultDataID = "data"
|
||||||
|
|
|
||||||
|
|
@ -25,25 +25,28 @@ package sbt
|
||||||
* Prior to a call to `setFoo`, `getFoo` will return `None`. After a call to `setFoo`, `getFoo` will
|
* Prior to a call to `setFoo`, `getFoo` will return `None`. After a call to `setFoo`, `getFoo` will
|
||||||
* return `Some("foo")`.
|
* return `Some("foo")`.
|
||||||
*/
|
*/
|
||||||
final class StateTransform private (val transform: State => State, stateProxy: () => State) {
|
final class StateTransform private (
|
||||||
@deprecated("Exists only for binary compatibility with 1.3.x.", "1.4.0")
|
val transform: State => State,
|
||||||
private[sbt] def state: State = stateProxy()
|
stateProxy: () => State,
|
||||||
@deprecated("1.4.0", "Use the constructor that takes a transform function.")
|
) {
|
||||||
private[sbt] def this(state: State) = this((_: State) => state, () => state)
|
// @deprecated("Exists only for binary compatibility with 1.3.x.", "1.4.0")
|
||||||
|
// private[sbt] def state: State = stateProxy()
|
||||||
|
// @deprecated("1.4.0", "Use the constructor that takes a transform function.")
|
||||||
|
// private[sbt] def this(state: State) = this((_: State) => state, () => state)
|
||||||
}
|
}
|
||||||
|
|
||||||
object StateTransform {
|
object StateTransform:
|
||||||
@deprecated("Exists only for binary compatibility with 1.3.x", "1.4.0")
|
// @deprecated("Exists only for binary compatibility with 1.3.x", "1.4.0")
|
||||||
def apply(state: State): State = state
|
// def apply(state: State): State = state
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of [[StateTransform]].
|
* Create an instance of [[StateTransform]].
|
||||||
* @param transform the transformation to apply after task evaluation has completed
|
* @param transform the transformation to apply after task evaluation has completed
|
||||||
* @return the [[StateTransform]].
|
* @return the [[StateTransform]].
|
||||||
*/
|
*/
|
||||||
def apply(transform: State => State) =
|
def apply(transform: State => State): StateTransform =
|
||||||
new StateTransform(
|
new StateTransform(
|
||||||
transform,
|
transform,
|
||||||
() => throw new IllegalStateException("No state was added to the StateTransform.")
|
() => throw new IllegalStateException("No state was added to the StateTransform.")
|
||||||
)
|
)
|
||||||
}
|
end StateTransform
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import sbt.librarymanagement._
|
||||||
import sbt.librarymanagement.ivy.{ IvyConfiguration, IvyDependencyResolution }
|
import sbt.librarymanagement.ivy.{ IvyConfiguration, IvyDependencyResolution }
|
||||||
import sbt.internal.inc.classpath.ClasspathUtil
|
import sbt.internal.inc.classpath.ClasspathUtil
|
||||||
import BasicCommandStrings._, BasicKeys._
|
import BasicCommandStrings._, BasicKeys._
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
|
|
||||||
private[sbt] object TemplateCommandUtil {
|
private[sbt] object TemplateCommandUtil {
|
||||||
def templateCommand: Command =
|
def templateCommand: Command =
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ package sbt
|
||||||
import sjsonnew.JsonFormat
|
import sjsonnew.JsonFormat
|
||||||
import Def.Setting
|
import Def.Setting
|
||||||
import sbt.internal.{ BuildStructure, LoadedBuildUnit, SessionSettings }
|
import sbt.internal.{ BuildStructure, LoadedBuildUnit, SessionSettings }
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends State with setting-level knowledge.
|
* Extends State with setting-level knowledge.
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import lmcoursier.definitions.{
|
||||||
}
|
}
|
||||||
import sbt.librarymanagement._
|
import sbt.librarymanagement._
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
|
|
||||||
object CoursierArtifactsTasks {
|
object CoursierArtifactsTasks {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import sbt.librarymanagement.ivy.{
|
||||||
Credentials,
|
Credentials,
|
||||||
DirectCredentials => IvyDirectCredentials
|
DirectCredentials => IvyDirectCredentials
|
||||||
}
|
}
|
||||||
|
import sbt.ProjectExtra.transitiveInterDependencies
|
||||||
import sbt.ScopeFilter.Make._
|
import sbt.ScopeFilter.Make._
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ package coursierint
|
||||||
|
|
||||||
import sbt.librarymanagement._
|
import sbt.librarymanagement._
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
|
import sbt.ProjectExtra.transitiveInterDependencies
|
||||||
import sbt.ScopeFilter.Make._
|
import sbt.ScopeFilter.Make._
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ object LMCoursier {
|
||||||
.orElse(sys.props.get("coursier.cache").map(absoluteFile)) match {
|
.orElse(sys.props.get("coursier.cache").map(absoluteFile)) match {
|
||||||
case Some(dir) => dir
|
case Some(dir) => dir
|
||||||
case _ =>
|
case _ =>
|
||||||
if (Util.isWindows) windowsCacheDirectory
|
if Util.isWindows then windowsCacheDirectory
|
||||||
else CoursierDependencyResolution.defaultCacheLocation
|
else CoursierDependencyResolution.defaultCacheLocation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,9 @@ private[sbt] abstract class AbstractTaskExecuteProgress extends ExecuteProgress[
|
||||||
}
|
}
|
||||||
|
|
||||||
override def afterRegistered(
|
override def afterRegistered(
|
||||||
task: Task[_],
|
task: Task[Any],
|
||||||
allDeps: Iterable[Task[_]],
|
allDeps: Iterable[Task[Any]],
|
||||||
pendingDeps: Iterable[Task[_]]
|
pendingDeps: Iterable[Task[Any]]
|
||||||
): Unit = {
|
): Unit = {
|
||||||
// we need this to infer anonymous task names
|
// we need this to infer anonymous task names
|
||||||
pendingDeps foreach { t =>
|
pendingDeps foreach { t =>
|
||||||
|
|
@ -80,7 +80,7 @@ private[sbt] abstract class AbstractTaskExecuteProgress extends ExecuteProgress[
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def beforeWork(task: Task[_]): Unit = {
|
override def beforeWork(task: Task[Any]): Unit = {
|
||||||
timings.put(task, new Timer)
|
timings.put(task, new Timer)
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,20 @@ import sbt.internal.util.complete.{ DefaultParsers, Parser }
|
||||||
import Aggregation.{ KeyValue, Values }
|
import Aggregation.{ KeyValue, Values }
|
||||||
import DefaultParsers._
|
import DefaultParsers._
|
||||||
import sbt.internal.util.Types.idFun
|
import sbt.internal.util.Types.idFun
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import sbt.internal.CommandStrings.{ MultiTaskCommand, ShowCommand, PrintCommand }
|
import sbt.internal.CommandStrings.{ MultiTaskCommand, ShowCommand, PrintCommand }
|
||||||
import sbt.internal.util.{ AttributeEntry, AttributeKey, AttributeMap, IMap, Settings, Util }
|
import sbt.internal.util.{ AttributeEntry, AttributeKey, AttributeMap, IMap, Settings, Util }
|
||||||
import sbt.util.Show
|
import sbt.util.Show
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
final class ParsedKey[+A](val key: ScopedKey[A], val mask: ScopeMask, val separaters: Seq[String]):
|
final class ParsedKey(val key: ScopedKey[_], val mask: ScopeMask, val separaters: Seq[String]):
|
||||||
def this(key: ScopedKey[A], mask: ScopeMask) = this(key, mask, Nil)
|
def this(key: ScopedKey[_], mask: ScopeMask) = this(key, mask, Nil)
|
||||||
|
|
||||||
override def equals(o: Any): Boolean =
|
override def equals(o: Any): Boolean =
|
||||||
this.eq(o.asInstanceOf[AnyRef]) || (o match {
|
this.eq(o.asInstanceOf[AnyRef]) || (o match {
|
||||||
case x: ParsedKey[_] => (this.key == x.key) && (this.mask == x.mask)
|
case x: ParsedKey => (this.key == x.key) && (this.mask == x.mask)
|
||||||
case _ => false
|
case _ => false
|
||||||
})
|
})
|
||||||
override def hashCode: Int = {
|
override def hashCode: Int = {
|
||||||
37 * (37 * (37 * (17 + "sbt.internal.ParsedKey".##) + this.key.##)) + this.mask.##
|
37 * (37 * (37 * (17 + "sbt.internal.ParsedKey".##) + this.key.##)) + this.mask.##
|
||||||
|
|
@ -55,7 +56,8 @@ object Act {
|
||||||
keyMap: Map[String, AttributeKey[_]],
|
keyMap: Map[String, AttributeKey[_]],
|
||||||
data: Settings[Scope]
|
data: Settings[Scope]
|
||||||
): Parser[ScopedKey[Any]] =
|
): Parser[ScopedKey[Any]] =
|
||||||
scopedKeySelected(index, current, defaultConfigs, keyMap, data).map(_.key)
|
scopedKeySelected(index, current, defaultConfigs, keyMap, data)
|
||||||
|
.map(_.key.asInstanceOf[ScopedKey[Any]])
|
||||||
|
|
||||||
// the index should be an aggregated index for proper tab completion
|
// the index should be an aggregated index for proper tab completion
|
||||||
def scopedKeyAggregated(
|
def scopedKeyAggregated(
|
||||||
|
|
@ -72,7 +74,11 @@ object Act {
|
||||||
structure.data
|
structure.data
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
yield Aggregation.aggregate(selected.key, selected.mask, structure.extra)
|
yield Aggregation.aggregate(
|
||||||
|
selected.key.asInstanceOf[ScopedKey[Any]],
|
||||||
|
selected.mask,
|
||||||
|
structure.extra
|
||||||
|
)
|
||||||
|
|
||||||
def scopedKeyAggregatedSep(
|
def scopedKeyAggregatedSep(
|
||||||
current: ProjectRef,
|
current: ProjectRef,
|
||||||
|
|
@ -88,7 +94,7 @@ object Act {
|
||||||
)
|
)
|
||||||
yield Aggregation
|
yield Aggregation
|
||||||
.aggregate(selected.key, selected.mask, structure.extra)
|
.aggregate(selected.key, selected.mask, structure.extra)
|
||||||
.map(k => k -> selected.separaters)
|
.map(k => k.asInstanceOf[ScopedKey[Any]] -> selected.separaters)
|
||||||
|
|
||||||
def scopedKeySelected(
|
def scopedKeySelected(
|
||||||
index: KeyIndex,
|
index: KeyIndex,
|
||||||
|
|
@ -96,7 +102,7 @@ object Act {
|
||||||
defaultConfigs: Option[ResolvedReference] => Seq[String],
|
defaultConfigs: Option[ResolvedReference] => Seq[String],
|
||||||
keyMap: Map[String, AttributeKey[_]],
|
keyMap: Map[String, AttributeKey[_]],
|
||||||
data: Settings[Scope]
|
data: Settings[Scope]
|
||||||
): Parser[ParsedKey[Any]] =
|
): Parser[ParsedKey] =
|
||||||
scopedKeyFull(index, current, defaultConfigs, keyMap) flatMap { choices =>
|
scopedKeyFull(index, current, defaultConfigs, keyMap) flatMap { choices =>
|
||||||
select(choices, data)(showRelativeKey2(current))
|
select(choices, data)(showRelativeKey2(current))
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +112,7 @@ object Act {
|
||||||
current: ProjectRef,
|
current: ProjectRef,
|
||||||
defaultConfigs: Option[ResolvedReference] => Seq[String],
|
defaultConfigs: Option[ResolvedReference] => Seq[String],
|
||||||
keyMap: Map[String, AttributeKey[_]]
|
keyMap: Map[String, AttributeKey[_]]
|
||||||
): Parser[Seq[Parser[ParsedKey[Any]]]] = {
|
): Parser[Seq[Parser[ParsedKey]]] = {
|
||||||
val confParserCache
|
val confParserCache
|
||||||
: mutable.Map[Option[sbt.ResolvedReference], Parser[(ParsedAxis[String], Seq[String])]] =
|
: mutable.Map[Option[sbt.ResolvedReference], Parser[(ParsedAxis[String], Seq[String])]] =
|
||||||
mutable.Map.empty
|
mutable.Map.empty
|
||||||
|
|
@ -151,7 +157,7 @@ object Act {
|
||||||
confAmb: ParsedAxis[String],
|
confAmb: ParsedAxis[String],
|
||||||
baseMask: ScopeMask,
|
baseMask: ScopeMask,
|
||||||
baseSeps: Seq[String]
|
baseSeps: Seq[String]
|
||||||
): Seq[Parser[ParsedKey[Any]]] =
|
): Seq[Parser[ParsedKey]] =
|
||||||
for {
|
for {
|
||||||
conf <- configs(confAmb, defaultConfigs, proj, index)
|
conf <- configs(confAmb, defaultConfigs, proj, index)
|
||||||
} yield for {
|
} yield for {
|
||||||
|
|
@ -178,9 +184,9 @@ object Act {
|
||||||
key
|
key
|
||||||
)
|
)
|
||||||
|
|
||||||
def select(allKeys: Seq[Parser[ParsedKey[_]]], data: Settings[Scope])(implicit
|
def select(allKeys: Seq[Parser[ParsedKey]], data: Settings[Scope])(implicit
|
||||||
show: Show[ScopedKey[_]]
|
show: Show[ScopedKey[_]]
|
||||||
): Parser[ParsedKey[Any]] =
|
): Parser[ParsedKey] =
|
||||||
seq(allKeys) flatMap { ss =>
|
seq(allKeys) flatMap { ss =>
|
||||||
val default = ss.headOption match {
|
val default = ss.headOption match {
|
||||||
case None => noValidKeys
|
case None => noValidKeys
|
||||||
|
|
@ -188,16 +194,16 @@ object Act {
|
||||||
}
|
}
|
||||||
selectFromValid(ss filter isValid(data), default)
|
selectFromValid(ss filter isValid(data), default)
|
||||||
}
|
}
|
||||||
def selectFromValid(ss: Seq[ParsedKey[_]], default: Parser[ParsedKey[_]])(implicit
|
def selectFromValid(ss: Seq[ParsedKey], default: Parser[ParsedKey])(implicit
|
||||||
show: Show[ScopedKey[_]]
|
show: Show[ScopedKey[_]]
|
||||||
): Parser[ParsedKey[Any]] =
|
): Parser[ParsedKey] =
|
||||||
selectByTask(selectByConfig(ss)) match {
|
selectByTask(selectByConfig(ss)) match {
|
||||||
case Seq() => default
|
case Seq() => default
|
||||||
case Seq(single) => success(single)
|
case Seq(single) => success(single)
|
||||||
case multi => failure("Ambiguous keys: " + showAmbiguous(keys(multi)))
|
case multi => failure("Ambiguous keys: " + showAmbiguous(keys(multi)))
|
||||||
}
|
}
|
||||||
private[this] def keys(ss: Seq[ParsedKey[_]]): Seq[ScopedKey[_]] = ss.map(_.key)
|
private[this] def keys(ss: Seq[ParsedKey]): Seq[ScopedKey[_]] = ss.map(_.key)
|
||||||
def selectByConfig(ss: Seq[ParsedKey[_]]): Seq[ParsedKey[Any]] =
|
def selectByConfig(ss: Seq[ParsedKey]): Seq[ParsedKey] =
|
||||||
ss match {
|
ss match {
|
||||||
case Seq() => Nil
|
case Seq() => Nil
|
||||||
case Seq(x, tail @ _*) => // select the first configuration containing a valid key
|
case Seq(x, tail @ _*) => // select the first configuration containing a valid key
|
||||||
|
|
@ -206,7 +212,7 @@ object Act {
|
||||||
case xs => x +: xs
|
case xs => x +: xs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def selectByTask(ss: Seq[ParsedKey[_]]): Seq[ParsedKey[Any]] = {
|
def selectByTask(ss: Seq[ParsedKey]): Seq[ParsedKey] = {
|
||||||
val (selects, zeros) = ss.partition(_.key.scope.task.isSelect)
|
val (selects, zeros) = ss.partition(_.key.scope.task.isSelect)
|
||||||
if (zeros.nonEmpty) zeros else selects
|
if (zeros.nonEmpty) zeros else selects
|
||||||
}
|
}
|
||||||
|
|
@ -216,7 +222,7 @@ object Act {
|
||||||
def showAmbiguous(keys: Seq[ScopedKey[_]])(implicit show: Show[ScopedKey[_]]): String =
|
def showAmbiguous(keys: Seq[ScopedKey[_]])(implicit show: Show[ScopedKey[_]]): String =
|
||||||
keys.take(3).map(x => show.show(x)).mkString("", ", ", if (keys.size > 3) ", ..." else "")
|
keys.take(3).map(x => show.show(x)).mkString("", ", ", if (keys.size > 3) ", ..." else "")
|
||||||
|
|
||||||
def isValid(data: Settings[Scope])(parsed: ParsedKey[_]): Boolean = {
|
def isValid(data: Settings[Scope])(parsed: ParsedKey): Boolean = {
|
||||||
val key = parsed.key
|
val key = parsed.key
|
||||||
data.definingScope(key.scope, key.key) == Some(key.scope)
|
data.definingScope(key.scope, key.key) == Some(key.scope)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ package internal
|
||||||
|
|
||||||
import sbt.internal.util.Types.const
|
import sbt.internal.util.Types.const
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import xsbti.VirtualFile
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents how settings from various sources are automatically merged into a Project's settings.
|
* Represents how settings from various sources are automatically merged into a Project's settings.
|
||||||
|
|
@ -23,10 +24,10 @@ object AddSettings {
|
||||||
}
|
}
|
||||||
private[sbt] final object User extends AddSettings
|
private[sbt] final object User extends AddSettings
|
||||||
private[sbt] final class AutoPlugins(val include: AutoPlugin => Boolean) extends AddSettings
|
private[sbt] final class AutoPlugins(val include: AutoPlugin => Boolean) extends AddSettings
|
||||||
private[sbt] final class DefaultSbtFiles(val include: File => Boolean) extends AddSettings
|
private[sbt] final class DefaultSbtFiles(val include: VirtualFile => Boolean) extends AddSettings
|
||||||
private[sbt] final class SbtFiles(val files: Seq[File]) extends AddSettings {
|
// private[sbt] final class SbtFiles(val files: Seq[File]) extends AddSettings {
|
||||||
override def toString: String = s"SbtFiles($files)"
|
// override def toString: String = s"SbtFiles($files)"
|
||||||
}
|
// }
|
||||||
private[sbt] final object BuildScalaFiles extends AddSettings
|
private[sbt] final object BuildScalaFiles extends AddSettings
|
||||||
|
|
||||||
/** Adds all settings from autoplugins. */
|
/** Adds all settings from autoplugins. */
|
||||||
|
|
@ -51,7 +52,7 @@ object AddSettings {
|
||||||
val defaultSbtFiles: AddSettings = new DefaultSbtFiles(const(true))
|
val defaultSbtFiles: AddSettings = new DefaultSbtFiles(const(true))
|
||||||
|
|
||||||
/** Includes the settings from the .sbt files given by `files`. */
|
/** Includes the settings from the .sbt files given by `files`. */
|
||||||
def sbtFiles(files: File*): AddSettings = new SbtFiles(files)
|
// def sbtFiles(files: File*): AddSettings = new SbtFiles(files)
|
||||||
|
|
||||||
/** Includes settings automatically */
|
/** Includes settings automatically */
|
||||||
def seq(autos: AddSettings*): AddSettings = new Sequence(autos)
|
def seq(autos: AddSettings*): AddSettings = new Sequence(autos)
|
||||||
|
|
@ -69,8 +70,9 @@ object AddSettings {
|
||||||
|
|
||||||
def clearSbtFiles(a: AddSettings): AddSettings =
|
def clearSbtFiles(a: AddSettings): AddSettings =
|
||||||
tx(a) {
|
tx(a) {
|
||||||
case _: DefaultSbtFiles | _: SbtFiles => None
|
// case _: SbtFiles => None
|
||||||
case x => Some(x)
|
case _: DefaultSbtFiles => None
|
||||||
|
case x => Some(x)
|
||||||
} getOrElse seq()
|
} getOrElse seq()
|
||||||
|
|
||||||
private[sbt] def tx(a: AddSettings)(f: AddSettings => Option[AddSettings]): Option[AddSettings] =
|
private[sbt] def tx(a: AddSettings)(f: AddSettings => Option[AddSettings]): Option[AddSettings] =
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import java.text.DateFormat
|
||||||
import sbt.Def.ScopedKey
|
import sbt.Def.ScopedKey
|
||||||
import sbt.Keys.{ showSuccess, showTiming, timingFormat }
|
import sbt.Keys.{ showSuccess, showTiming, timingFormat }
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
import sbt.internal.util.complete.Parser
|
import sbt.internal.util.complete.Parser
|
||||||
import sbt.internal.util.complete.Parser.{ failure, seq, success }
|
import sbt.internal.util.complete.Parser.{ failure, seq, success }
|
||||||
import sbt.internal.util._
|
import sbt.internal.util._
|
||||||
|
|
@ -57,7 +58,7 @@ object Aggregation {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Values[T] = Seq[KeyValue[T]]
|
type Values[T] = Seq[KeyValue[T]]
|
||||||
type AnyKeys = Values[_]
|
type AnyKeys = Values[Any]
|
||||||
|
|
||||||
def seqParser[T](ps: Values[Parser[T]]): Parser[Seq[KeyValue[T]]] =
|
def seqParser[T](ps: Values[Parser[T]]): Parser[Seq[KeyValue[T]]] =
|
||||||
seq(ps.map { case KeyValue(k, p) => p.map(v => KeyValue(k, v)) })
|
seq(ps.map { case KeyValue(k, p) => p.map(v => KeyValue(k, v)) })
|
||||||
|
|
@ -219,7 +220,12 @@ object Aggregation {
|
||||||
val inputStrings = inputTasks.map(_.key).mkString("Input task(s):\n\t", "\n\t", "\n")
|
val inputStrings = inputTasks.map(_.key).mkString("Input task(s):\n\t", "\n\t", "\n")
|
||||||
val otherStrings = other.map(_.key).mkString("Task(s)/setting(s):\n\t", "\n\t", "\n")
|
val otherStrings = other.map(_.key).mkString("Task(s)/setting(s):\n\t", "\n\t", "\n")
|
||||||
failure(s"Cannot mix input tasks with plain tasks/settings. $inputStrings $otherStrings")
|
failure(s"Cannot mix input tasks with plain tasks/settings. $inputStrings $otherStrings")
|
||||||
} else applyDynamicTasks(s, maps(inputTasks)(castToAny), show)
|
} else
|
||||||
|
applyDynamicTasks(
|
||||||
|
s,
|
||||||
|
inputTasks.map { case KeyValue(k, v: InputTask[a]) => KeyValue(k, castToAny(v)) },
|
||||||
|
show
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
val base =
|
val base =
|
||||||
if (tasks.isEmpty) success(() => s)
|
if (tasks.isEmpty) success(() => s)
|
||||||
|
|
@ -233,8 +239,10 @@ object Aggregation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a hack to avoid duplicating method implementations
|
// this is a hack to avoid duplicating method implementations
|
||||||
private[this] def castToAny[T[_]](t: T[_]): T[Any] = t.asInstanceOf[T[Any]]
|
private[this] def castToAny[F[_]]: [a] => F[a] => F[Any] = [a] =>
|
||||||
|
(fa: F[a]) => fa.asInstanceOf[F[Any]]
|
||||||
|
|
||||||
private[this] def maps[T, S](vs: Values[T])(f: T => S): Values[S] =
|
private[this] def maps[T, S](vs: Values[T])(f: T => S): Values[S] =
|
||||||
vs map { case KeyValue(k, v) => KeyValue(k, f(v)) }
|
vs map { case KeyValue(k, v) => KeyValue(k, f(v)) }
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ package internal
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import Keys.{ organization, thisProject, autoGeneratedProject }
|
import Keys.{ organization, thisProject, autoGeneratedProject }
|
||||||
import Def.Setting
|
import Def.Setting
|
||||||
|
// import sbt.ProjectExtra.apply
|
||||||
import sbt.io.Hash
|
import sbt.io.Hash
|
||||||
import sbt.internal.util.Attributed
|
import sbt.internal.util.Attributed
|
||||||
import sbt.internal.inc.ReflectUtilities
|
import sbt.internal.inc.ReflectUtilities
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ package sbt
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.nio.file.Path
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
import Def.{ ScopeLocal, ScopedKey, Setting, displayFull }
|
import Def.{ ScopeLocal, ScopedKey, Setting, displayFull }
|
||||||
|
|
@ -17,6 +18,7 @@ import Scope.GlobalScope
|
||||||
import BuildStreams.Streams
|
import BuildStreams.Streams
|
||||||
import sbt.LocalRootProject
|
import sbt.LocalRootProject
|
||||||
import sbt.io.syntax._
|
import sbt.io.syntax._
|
||||||
|
import sbt.internal.inc.MappedFileConverter
|
||||||
import sbt.internal.util.{ AttributeEntry, AttributeKey, AttributeMap, Attributed, Settings }
|
import sbt.internal.util.{ AttributeEntry, AttributeKey, AttributeMap, Attributed, Settings }
|
||||||
import sbt.internal.util.Attributed.data
|
import sbt.internal.util.Attributed.data
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
|
|
@ -32,19 +34,8 @@ final class BuildStructure(
|
||||||
val delegates: Scope => Seq[Scope],
|
val delegates: Scope => Seq[Scope],
|
||||||
val scopeLocal: ScopeLocal,
|
val scopeLocal: ScopeLocal,
|
||||||
private[sbt] val compiledMap: Map[ScopedKey[_], Def.Compiled[_]],
|
private[sbt] val compiledMap: Map[ScopedKey[_], Def.Compiled[_]],
|
||||||
|
private[sbt] val converter: MappedFileConverter,
|
||||||
) {
|
) {
|
||||||
@deprecated("Used the variant that takes a compiledMap", "1.4.0")
|
|
||||||
def this(
|
|
||||||
units: Map[URI, LoadedBuildUnit],
|
|
||||||
root: URI,
|
|
||||||
settings: Seq[Setting[_]],
|
|
||||||
data: Settings[Scope],
|
|
||||||
index: StructureIndex,
|
|
||||||
streams: State => Streams,
|
|
||||||
delegates: Scope => Seq[Scope],
|
|
||||||
scopeLocal: ScopeLocal,
|
|
||||||
) = this(units, root, settings, data, index, streams, delegates, scopeLocal, Map.empty)
|
|
||||||
|
|
||||||
val extra: BuildUtil[ResolvedProject] = BuildUtil(root, units, index.keyIndex, data)
|
val extra: BuildUtil[ResolvedProject] = BuildUtil(root, units, index.keyIndex, data)
|
||||||
|
|
||||||
/** The root project for the specified build. Throws if no build or empty build. */
|
/** The root project for the specified build. Throws if no build or empty build. */
|
||||||
|
|
@ -117,8 +108,10 @@ final class LoadedBuildUnit(
|
||||||
* The classpath to use when compiling against this build unit's publicly visible code.
|
* The classpath to use when compiling against this build unit's publicly visible code.
|
||||||
* It includes build definition and plugin classes and classes for .sbt file statements and expressions.
|
* It includes build definition and plugin classes and classes for .sbt file statements and expressions.
|
||||||
*/
|
*/
|
||||||
def classpath: Seq[File] =
|
def classpath: Seq[Path] =
|
||||||
unit.definitions.target ++ unit.plugins.classpath ++ unit.definitions.dslDefinitions.classpath
|
unit.definitions.target.map(
|
||||||
|
_.toPath()
|
||||||
|
) ++ unit.plugins.classpath.map(_.toPath()) ++ unit.definitions.dslDefinitions.classpath
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class loader to use for this build unit's publicly visible code.
|
* The class loader to use for this build unit's publicly visible code.
|
||||||
|
|
@ -281,7 +274,11 @@ final class LoadedBuild(val root: URI, val units: Map[URI, LoadedBuildUnit]) {
|
||||||
private[sbt] def autos = GroupedAutoPlugins(units)
|
private[sbt] def autos = GroupedAutoPlugins(units)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class PartBuild(val root: URI, val units: Map[URI, PartBuildUnit])
|
final class PartBuild(
|
||||||
|
val root: URI,
|
||||||
|
val units: Map[URI, PartBuildUnit],
|
||||||
|
val converter: MappedFileConverter,
|
||||||
|
)
|
||||||
|
|
||||||
sealed trait BuildUnitBase { def rootProjects: Seq[String]; def buildSettings: Seq[Setting[_]] }
|
sealed trait BuildUnitBase { def rootProjects: Seq[String]; def buildSettings: Seq[Setting[_]] }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ private[sbt] object ClasspathImpl {
|
||||||
track: TrackLevel,
|
track: TrackLevel,
|
||||||
log: Logger
|
log: Logger
|
||||||
): Initialize[Task[Classpath]] =
|
): Initialize[Task[Classpath]] =
|
||||||
Def.value {
|
Def.value[Task[Classpath]] {
|
||||||
interDependencies(projectRef, deps, conf, self, data, track, false, log)(
|
interDependencies(projectRef, deps, conf, self, data, track, false, log)(
|
||||||
exportedProductsNoTracking,
|
exportedProductsNoTracking,
|
||||||
exportedProductsIfMissing,
|
exportedProductsIfMissing,
|
||||||
|
|
@ -196,7 +196,7 @@ private[sbt] object ClasspathImpl {
|
||||||
track: TrackLevel,
|
track: TrackLevel,
|
||||||
log: Logger
|
log: Logger
|
||||||
): Initialize[Task[VirtualClasspath]] =
|
): Initialize[Task[VirtualClasspath]] =
|
||||||
Def.value {
|
Def.value[Task[VirtualClasspath]] {
|
||||||
interDependencies(projectRef, deps, conf, self, data, track, false, log)(
|
interDependencies(projectRef, deps, conf, self, data, track, false, log)(
|
||||||
exportedPickles,
|
exportedPickles,
|
||||||
exportedPickles,
|
exportedPickles,
|
||||||
|
|
@ -242,7 +242,7 @@ private[sbt] object ClasspathImpl {
|
||||||
track: TrackLevel,
|
track: TrackLevel,
|
||||||
log: Logger
|
log: Logger
|
||||||
): Initialize[Task[Classpath]] =
|
): Initialize[Task[Classpath]] =
|
||||||
Def.value {
|
Def.value[Task[Classpath]] {
|
||||||
interDependencies(projectRef, deps, conf, self, data, track, false, log)(
|
interDependencies(projectRef, deps, conf, self, data, track, false, log)(
|
||||||
exportedProductJarsNoTracking,
|
exportedProductJarsNoTracking,
|
||||||
exportedProductJarsIfMissing,
|
exportedProductJarsIfMissing,
|
||||||
|
|
@ -270,7 +270,7 @@ private[sbt] object ClasspathImpl {
|
||||||
deps: BuildDependencies,
|
deps: BuildDependencies,
|
||||||
log: Logger
|
log: Logger
|
||||||
): Initialize[Task[Classpath]] =
|
): Initialize[Task[Classpath]] =
|
||||||
Def.value {
|
Def.value[Task[Classpath]] {
|
||||||
interDependencies(
|
interDependencies(
|
||||||
projectRef,
|
projectRef,
|
||||||
deps,
|
deps,
|
||||||
|
|
@ -346,7 +346,7 @@ private[sbt] object ClasspathImpl {
|
||||||
val masterConfs = names(getConfigurations(projectRef, data).toVector)
|
val masterConfs = names(getConfigurations(projectRef, data).toVector)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
ResolvedClasspathDependency(dep, confMapping) <- deps.classpath(p)
|
ClasspathDep.ResolvedClasspathDependency(dep, confMapping) <- deps.classpath(p)
|
||||||
} {
|
} {
|
||||||
val configurations = getConfigurations(dep, data)
|
val configurations = getConfigurations(dep, data)
|
||||||
val mapping =
|
val mapping =
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,14 @@ import java.nio.file.{ DirectoryNotEmptyException, Files, Path }
|
||||||
|
|
||||||
import sbt.Def._
|
import sbt.Def._
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
import sbt.Project.richInitializeTask
|
// import sbt.Project.richInitializeTask
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.io.syntax._
|
import sbt.io.syntax._
|
||||||
import sbt.nio.Keys._
|
import sbt.nio.Keys._
|
||||||
import sbt.nio.file._
|
import sbt.nio.file._
|
||||||
import sbt.nio.file.syntax._
|
import sbt.nio.file.syntax.pathToPathOps
|
||||||
|
import sbt.nio.file.Glob.{ GlobOps }
|
||||||
import sbt.util.Level
|
import sbt.util.Level
|
||||||
import sjsonnew.JsonFormat
|
import sjsonnew.JsonFormat
|
||||||
import scala.annotation.nowarn
|
import scala.annotation.nowarn
|
||||||
|
|
@ -56,7 +58,7 @@ private[sbt] object Clean {
|
||||||
val excludes = (scope / cleanKeepFiles).value.map {
|
val excludes = (scope / cleanKeepFiles).value.map {
|
||||||
// This mimics the legacy behavior of cleanFilesTask
|
// This mimics the legacy behavior of cleanFilesTask
|
||||||
case f if f.isDirectory => Glob(f, AnyPath)
|
case f if f.isDirectory => Glob(f, AnyPath)
|
||||||
case f => f.toGlob
|
case f => f.toPath.toGlob
|
||||||
} ++ (scope / cleanKeepGlobs).value
|
} ++ (scope / cleanKeepGlobs).value
|
||||||
(p: Path) => excludes.exists(_.matches(p))
|
(p: Path) => excludes.exists(_.matches(p))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package sbt
|
package sbt
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.internal.classpath.AlternativeZincUtil
|
import sbt.internal.classpath.AlternativeZincUtil
|
||||||
import sbt.internal.inc.{ ScalaInstance, ZincLmUtil }
|
import sbt.internal.inc.{ ScalaInstance, ZincLmUtil }
|
||||||
|
|
@ -66,7 +67,7 @@ object ConsoleProject {
|
||||||
val terminal = Terminal.get
|
val terminal = Terminal.get
|
||||||
// TODO - Hook up dsl classpath correctly...
|
// TODO - Hook up dsl classpath correctly...
|
||||||
(new Console(compiler))(
|
(new Console(compiler))(
|
||||||
unit.classpath,
|
unit.classpath.map(_.toFile),
|
||||||
options,
|
options,
|
||||||
initCommands,
|
initCommands,
|
||||||
cleanupCommands,
|
cleanupCommands,
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger }
|
||||||
import sbt.BasicCommandStrings._
|
import sbt.BasicCommandStrings._
|
||||||
import sbt.Def._
|
import sbt.Def._
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.internal.Continuous.{ ContinuousState, FileStampRepository }
|
import sbt.internal.Continuous.{ ContinuousState, FileStampRepository }
|
||||||
import sbt.internal.LabeledFunctions._
|
import sbt.internal.LabeledFunctions._
|
||||||
|
|
@ -972,17 +973,17 @@ private[sbt] object Continuous extends DeprecatedContinuous {
|
||||||
* @param inputs the transitive task inputs (see [[SettingsGraph]])
|
* @param inputs the transitive task inputs (see [[SettingsGraph]])
|
||||||
* @param watchSettings the [[WatchSettings]] instance for the task
|
* @param watchSettings the [[WatchSettings]] instance for the task
|
||||||
*/
|
*/
|
||||||
private final class Config private[internal] (
|
private final class Config(
|
||||||
val command: String,
|
val command: String,
|
||||||
val dynamicInputs: mutable.Set[DynamicInput],
|
val dynamicInputs: mutable.Set[DynamicInput],
|
||||||
val watchSettings: WatchSettings
|
val watchSettings: WatchSettings,
|
||||||
) {
|
):
|
||||||
def inputs() = dynamicInputs.toSeq.sorted
|
def inputs() = dynamicInputs.toSeq.sorted
|
||||||
private[sbt] def watchState(count: Int): DeprecatedWatchState =
|
private[sbt] def watchState(count: Int): DeprecatedWatchState =
|
||||||
WatchState.empty(inputs().map(_.glob)).withCount(count)
|
WatchState.empty(inputs().map(_.glob)).withCount(count)
|
||||||
|
|
||||||
def arguments(logger: Logger): Arguments = new Arguments(logger, inputs())
|
def arguments(logger: Logger): Arguments = new Arguments(logger, inputs())
|
||||||
}
|
end Config
|
||||||
|
|
||||||
private def getStartMessage(key: ScopedKey[_])(implicit e: Extracted): StartMessage = Some {
|
private def getStartMessage(key: ScopedKey[_])(implicit e: Extracted): StartMessage = Some {
|
||||||
lazy val default = key.get(watchStartMessage).getOrElse(Watch.defaultStartWatch)
|
lazy val default = key.get(watchStartMessage).getOrElse(Watch.defaultStartWatch)
|
||||||
|
|
@ -16,6 +16,7 @@ import sbt.io.{ IO, Path }
|
||||||
import sbt.io.syntax._
|
import sbt.io.syntax._
|
||||||
import sbt.Cross._
|
import sbt.Cross._
|
||||||
import sbt.Def.{ ScopedKey, Setting }
|
import sbt.Def.{ ScopedKey, Setting }
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.internal.util.complete.DefaultParsers._
|
import sbt.internal.util.complete.DefaultParsers._
|
||||||
import sbt.internal.util.AttributeKey
|
import sbt.internal.util.AttributeKey
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import java.util.concurrent.{ ConcurrentHashMap, TimeUnit }
|
||||||
import java.util.concurrent.atomic.{ AtomicLong, AtomicReference }
|
import java.util.concurrent.atomic.{ AtomicLong, AtomicReference }
|
||||||
|
|
||||||
import sbt.Def.{ Classpath, ScopedKey, Setting }
|
import sbt.Def.{ Classpath, ScopedKey, Setting }
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
import sbt.Scope.GlobalScope
|
import sbt.Scope.GlobalScope
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.internal.inc.classpath.ClasspathFilter
|
import sbt.internal.inc.classpath.ClasspathFilter
|
||||||
|
|
|
||||||
|
|
@ -14,90 +14,91 @@ import sbt.nio.Keys._
|
||||||
import sbt.nio.{ FileChanges, FileStamp }
|
import sbt.nio.{ FileChanges, FileStamp }
|
||||||
|
|
||||||
import scala.annotation.compileTimeOnly
|
import scala.annotation.compileTimeOnly
|
||||||
import scala.language.experimental.macros
|
import scala.quoted.*
|
||||||
import scala.reflect.macros.blackbox
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides extension methods to `TaskKey[T]` that can be use to fetch the input and output file
|
* Provides extension methods to `TaskKey[T]` that can be use to fetch the input and output file
|
||||||
* dependency changes for a task. Nothing in this object is intended to be called directly but,
|
* dependency changes for a task. Nothing in this object is intended to be called directly but,
|
||||||
* because there are macro definitions, some of the definitions must be public.
|
* because there are macro definitions, some of the definitions must be public.
|
||||||
*/
|
*/
|
||||||
object FileChangesMacro {
|
object FileChangesMacro:
|
||||||
private[sbt] sealed abstract class TaskOps[T](val taskKey: TaskKey[T]) {
|
|
||||||
|
extension [A](in: TaskKey[A])
|
||||||
@compileTimeOnly(
|
@compileTimeOnly(
|
||||||
"`inputFileChanges` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
"`inputFileChanges` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
||||||
)
|
)
|
||||||
def inputFileChanges: FileChanges = macro changedInputFilesImpl[T]
|
inline def inputFileChanges: FileChanges =
|
||||||
|
${ FileChangesMacro.changedInputFilesImpl[A]('in) }
|
||||||
|
|
||||||
@compileTimeOnly(
|
@compileTimeOnly(
|
||||||
"`outputFileChanges` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
"`outputFileChanges` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
||||||
)
|
)
|
||||||
def outputFileChanges: FileChanges = macro changedOutputFilesImpl[T]
|
inline def outputFileChanges: FileChanges =
|
||||||
|
${ FileChangesMacro.changedOutputFilesImpl[A]('in) }
|
||||||
|
|
||||||
@compileTimeOnly(
|
@compileTimeOnly(
|
||||||
"`inputFiles` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
"`inputFiles` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
||||||
)
|
)
|
||||||
def inputFiles: Seq[NioPath] = macro inputFilesImpl[T]
|
inline def inputFiles: Seq[NioPath] =
|
||||||
|
${ FileChangesMacro.inputFilesImpl[A]('in) }
|
||||||
|
|
||||||
@compileTimeOnly(
|
@compileTimeOnly(
|
||||||
"`outputFiles` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
"`outputFiles` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
||||||
)
|
)
|
||||||
def outputFiles: Seq[NioPath] = macro outputFilesImpl[T]
|
inline def outputFiles: Seq[NioPath] =
|
||||||
}
|
${ FileChangesMacro.outputFilesImpl[A]('in) }
|
||||||
def changedInputFilesImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[FileChanges] = {
|
|
||||||
impl[T](c)(
|
def changedInputFilesImpl[A: Type](in: Expr[TaskKey[A]])(using qctx: Quotes): Expr[FileChanges] =
|
||||||
c.universe.reify(allInputFiles),
|
impl[A](
|
||||||
c.universe.reify(changedInputFiles),
|
in = in,
|
||||||
c.universe.reify(inputFileStamps)
|
currentKey = '{ allInputFiles },
|
||||||
|
changeKey = '{ changedInputFiles },
|
||||||
|
mapKey = '{ inputFileStamps },
|
||||||
)
|
)
|
||||||
}
|
|
||||||
def changedOutputFilesImpl[T: c.WeakTypeTag](
|
def changedOutputFilesImpl[A: Type](in: Expr[TaskKey[A]])(using qctx: Quotes): Expr[FileChanges] =
|
||||||
c: blackbox.Context
|
impl[A](
|
||||||
): c.Expr[FileChanges] = {
|
in = in,
|
||||||
impl[T](c)(
|
currentKey = '{ allOutputFiles },
|
||||||
c.universe.reify(allOutputFiles),
|
changeKey = '{ changedOutputFiles },
|
||||||
c.universe.reify(changedOutputFiles),
|
mapKey = '{ outputFileStamps },
|
||||||
c.universe.reify(outputFileStamps)
|
|
||||||
)
|
)
|
||||||
}
|
|
||||||
def rescope[T](left: TaskKey[_], right: TaskKey[T]): TaskKey[T] =
|
def rescope[A](left: TaskKey[_], right: TaskKey[A]): TaskKey[A] =
|
||||||
Scoped.scopedTask(left.scope.copy(task = Select(left.key)), right.key)
|
Scoped.scopedTask(left.scope.copy(task = Select(left.key)), right.key)
|
||||||
def rescope[T](left: Scope, right: TaskKey[T]): TaskKey[T] =
|
|
||||||
|
def rescope[A](left: Scope, right: TaskKey[A]): TaskKey[A] =
|
||||||
Scoped.scopedTask(left, right.key)
|
Scoped.scopedTask(left, right.key)
|
||||||
private def impl[T: c.WeakTypeTag](
|
|
||||||
c: blackbox.Context
|
private def impl[A: Type](
|
||||||
)(
|
in: Expr[TaskKey[A]],
|
||||||
currentKey: c.Expr[TaskKey[Seq[NioPath]]],
|
currentKey: Expr[TaskKey[Seq[NioPath]]],
|
||||||
changeKey: c.Expr[TaskKey[Seq[(NioPath, FileStamp)] => FileChanges]],
|
changeKey: Expr[TaskKey[Seq[(NioPath, FileStamp)] => FileChanges]],
|
||||||
mapKey: c.Expr[TaskKey[Seq[(NioPath, FileStamp)]]]
|
mapKey: Expr[TaskKey[Seq[(NioPath, FileStamp)]]],
|
||||||
): c.Expr[FileChanges] = {
|
)(using qctx: Quotes): Expr[FileChanges] =
|
||||||
import c.universe._
|
import qctx.reflect.*
|
||||||
val taskScope = getTaskScope(c)
|
val taskScope = getTaskScope[A](in)
|
||||||
reify {
|
'{
|
||||||
val changes = rescope(taskScope.splice, changeKey.splice).value
|
val ts: Scope = $taskScope
|
||||||
val current = rescope(taskScope.splice, currentKey.splice).value
|
val changes = rescope[Seq[(NioPath, FileStamp)] => FileChanges](ts, $changeKey).value
|
||||||
import sbt.nio.FileStamp.Formats._
|
val current = rescope[Seq[NioPath]](ts, $currentKey).value
|
||||||
val previous = Previous.runtimeInEnclosingTask(rescope(taskScope.splice, mapKey.splice)).value
|
import sbt.nio.FileStamp.Formats.*
|
||||||
|
val previous =
|
||||||
|
Previous.runtimeInEnclosingTask(rescope[Seq[(NioPath, FileStamp)]](ts, $mapKey)).value
|
||||||
previous.map(changes).getOrElse(FileChanges.noPrevious(current))
|
previous.map(changes).getOrElse(FileChanges.noPrevious(current))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
def inputFilesImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[Seq[NioPath]] = {
|
def inputFilesImpl[A: Type](in: Expr[TaskKey[A]])(using qctx: Quotes): Expr[Seq[NioPath]] =
|
||||||
val taskKey = getTaskScope(c)
|
val ts = getTaskScope[A](in)
|
||||||
c.universe.reify(rescope(taskKey.splice, allInputFiles).value)
|
'{ rescope[Seq[NioPath]]($ts, allInputFiles).value }
|
||||||
}
|
|
||||||
def outputFilesImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[Seq[NioPath]] = {
|
def outputFilesImpl[A: Type](in: Expr[TaskKey[A]])(using qctx: Quotes): Expr[Seq[NioPath]] =
|
||||||
val taskKey = getTaskScope(c)
|
val ts = getTaskScope[A](in)
|
||||||
c.universe.reify(rescope(taskKey.splice, allOutputFiles).value)
|
'{ rescope[Seq[NioPath]]($ts, allOutputFiles).value }
|
||||||
}
|
|
||||||
private def getTaskScope[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[sbt.Scope] = {
|
private def getTaskScope[A: Type](in: Expr[TaskKey[A]])(using qctx: Quotes): Expr[sbt.Scope] =
|
||||||
import c.universe._
|
'{
|
||||||
val taskTpe = c.weakTypeOf[TaskKey[T]]
|
if $in.scope.task.toOption.isDefined then $in.scope
|
||||||
lazy val err = "Couldn't expand file change macro."
|
else $in.scope.copy(task = sbt.Select($in.key))
|
||||||
c.macroApplication match {
|
|
||||||
case Select(Apply(_, k :: Nil), _) if k.tpe <:< taskTpe =>
|
|
||||||
val expr = c.Expr[TaskKey[T]](k)
|
|
||||||
c.universe.reify {
|
|
||||||
if (expr.splice.scope.task.toOption.isDefined) expr.splice.scope
|
|
||||||
else expr.splice.scope.copy(task = sbt.Select(expr.splice.key))
|
|
||||||
}
|
|
||||||
case _ => c.abort(c.enclosingPosition, err)
|
|
||||||
}
|
}
|
||||||
}
|
end FileChangesMacro
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import sbt.internal.util.Attributed
|
||||||
import Def.{ ScopedKey, Setting }
|
import Def.{ ScopedKey, Setting }
|
||||||
import Keys._
|
import Keys._
|
||||||
import Configurations.{ Compile, Runtime }
|
import Configurations.{ Compile, Runtime }
|
||||||
|
import sbt.ProjectExtra.{ extract, runUnloadHooks, setProject }
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import org.apache.ivy.core.module.{ descriptor, id }
|
import org.apache.ivy.core.module.{ descriptor, id }
|
||||||
|
|
@ -80,8 +81,6 @@ object GlobalPlugin {
|
||||||
val intcp = (Runtime / internalDependencyClasspath).value
|
val intcp = (Runtime / internalDependencyClasspath).value
|
||||||
val prods = (Runtime / exportedProducts).value
|
val prods = (Runtime / exportedProducts).value
|
||||||
val depMap = projectDescriptors.value + ivyModule.value.dependencyMapping(state.log)
|
val depMap = projectDescriptors.value + ivyModule.value.dependencyMapping(state.log)
|
||||||
// If we reference it directly (if it's an executionRoot) then it forces an update, which is not what we want.
|
|
||||||
val updateReport = Def.taskDyn { Def.task { update.value } }.value
|
|
||||||
|
|
||||||
GlobalPluginData(
|
GlobalPluginData(
|
||||||
projectID.value,
|
projectID.value,
|
||||||
|
|
@ -90,7 +89,7 @@ object GlobalPlugin {
|
||||||
resolvers.value.toVector,
|
resolvers.value.toVector,
|
||||||
(Runtime / fullClasspath).value,
|
(Runtime / fullClasspath).value,
|
||||||
(prods ++ intcp).distinct
|
(prods ++ intcp).distinct
|
||||||
)(updateReport)
|
)(updateReport.value)
|
||||||
}
|
}
|
||||||
val resolvedTaskInit = taskInit mapReferenced Project.mapScope(Scope replaceThis p)
|
val resolvedTaskInit = taskInit mapReferenced Project.mapScope(Scope replaceThis p)
|
||||||
val task = resolvedTaskInit evaluate data
|
val task = resolvedTaskInit evaluate data
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import Def.ScopedKey
|
||||||
import Types.idFun
|
import Types.idFun
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import Scope.Global
|
import Scope.Global
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
|
|
||||||
object Inspect {
|
object Inspect {
|
||||||
sealed trait Mode
|
sealed trait Mode
|
||||||
|
|
@ -87,14 +88,16 @@ object Inspect {
|
||||||
import extracted._
|
import extracted._
|
||||||
option match {
|
option match {
|
||||||
case Details(actual) =>
|
case Details(actual) =>
|
||||||
Project.details(structure, actual, sk.scope, sk.key)
|
Project.details(extracted.structure, actual, sk.scope, sk.key)
|
||||||
case DependencyTreeMode =>
|
case DependencyTreeMode =>
|
||||||
val basedir = new File(Project.session(s).current.build)
|
val basedir = new File(Project.session(s).current.build)
|
||||||
Project.settingGraph(structure, basedir, sk).dependsAscii(get(sbt.Keys.asciiGraphWidth))
|
Project
|
||||||
|
.settingGraph(extracted.structure, basedir, sk)
|
||||||
|
.dependsAscii(get(sbt.Keys.asciiGraphWidth))
|
||||||
case UsesMode =>
|
case UsesMode =>
|
||||||
Project.showUses(Project.usedBy(structure, true, sk.key))
|
Project.showUses(Project.usedBy(extracted.structure, true, sk.key))
|
||||||
case DefinitionsMode =>
|
case DefinitionsMode =>
|
||||||
Project.showDefinitions(sk.key, Project.definitions(structure, true, sk.key))
|
Project.showDefinitions(sk.key, Project.definitions(extracted.structure, true, sk.key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ private[sbt] object InternalDependencies {
|
||||||
val projectDependencies = buildDependencies.value.classpath.get(ref).toSeq.flatten
|
val projectDependencies = buildDependencies.value.classpath.get(ref).toSeq.flatten
|
||||||
val applicableConfigs = allConfigs + "*"
|
val applicableConfigs = allConfigs + "*"
|
||||||
((ref -> allConfigs) +:
|
((ref -> allConfigs) +:
|
||||||
projectDependencies.flatMap { case ResolvedClasspathDependency(p, rawConfigs) =>
|
projectDependencies.flatMap { case ClasspathDep.ResolvedClasspathDependency(p, rawConfigs) =>
|
||||||
val configs = rawConfigs.getOrElse("*->compile").split(";").flatMap { config =>
|
val configs = rawConfigs.getOrElse("*->compile").split(";").flatMap { config =>
|
||||||
config.split("->") match {
|
config.split("->") match {
|
||||||
case Array(n, c) if applicableConfigs.contains(n) => Some(c)
|
case Array(n, c) if applicableConfigs.contains(n) => Some(c)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import Configurations.Compile
|
||||||
import Def.Setting
|
import Def.Setting
|
||||||
import Keys._
|
import Keys._
|
||||||
import Scope.Global
|
import Scope.Global
|
||||||
|
import sbt.ProjectExtra.{ extract, setProject }
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
|
|
||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,7 @@ private[sbt] final class KeyIndex0(val data: BuildIndex) extends ExtendableKeyIn
|
||||||
case _ => (None, None)
|
case _ => (None, None)
|
||||||
}
|
}
|
||||||
private[this] def optConfigs(project: Option[ResolvedReference]): Seq[Option[String]] =
|
private[this] def optConfigs(project: Option[ResolvedReference]): Seq[Option[String]] =
|
||||||
None +: (configs(project).toSeq map some.fn)
|
None +: (configs(project).toSeq.map(some[String]))
|
||||||
|
|
||||||
def addAggregated(scoped: ScopedKey[_], extra: BuildUtil[_]): ExtendableKeyIndex =
|
def addAggregated(scoped: ScopedKey[_], extra: BuildUtil[_]): ExtendableKeyIndex =
|
||||||
if (validID(scoped.key.label)) {
|
if (validID(scoped.key.label)) {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import sbt.librarymanagement.syntax._
|
||||||
import sbt.util.{ CacheStore, CacheStoreFactory, Level, Logger, Tracked }
|
import sbt.util.{ CacheStore, CacheStoreFactory, Level, Logger, Tracked }
|
||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
import sbt.io.syntax._
|
import sbt.io.syntax._
|
||||||
import sbt.Project.richInitializeTask
|
import sbt.ProjectExtra.richInitializeTask
|
||||||
import sjsonnew.JsonFormat
|
import sjsonnew.JsonFormat
|
||||||
import scala.compat.Platform.EOL
|
import scala.compat.Platform.EOL
|
||||||
import scala.concurrent.duration.FiniteDuration
|
import scala.concurrent.duration.FiniteDuration
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import Keys._
|
||||||
import Def.{ Setting, ScopedKey }
|
import Def.{ Setting, ScopedKey }
|
||||||
import sbt.internal.util.{ FilePosition, NoPosition, SourcePosition }
|
import sbt.internal.util.{ FilePosition, NoPosition, SourcePosition }
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import ProjectExtra.{ extract, scopedKeyData }
|
||||||
import Scope.Global
|
import Scope.Global
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.Def._
|
import sbt.Def._
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,13 @@ import sbt.BuildPaths._
|
||||||
import sbt.Def.{ ScopeLocal, ScopedKey, Setting, isDummy }
|
import sbt.Def.{ ScopeLocal, ScopedKey, Setting, isDummy }
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
import sbt.Project.inScope
|
import sbt.Project.inScope
|
||||||
|
import sbt.ProjectExtra.{ checkTargets, prefixConfigs, setProject, showLoadingKey, structure }
|
||||||
import sbt.Scope.GlobalScope
|
import sbt.Scope.GlobalScope
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.compiler.{ Eval, EvalReporter }
|
import sbt.internal.{ Eval, EvalReporter }
|
||||||
import sbt.internal.BuildStreams._
|
import sbt.internal.BuildStreams._
|
||||||
import sbt.internal.inc.classpath.ClasspathUtil
|
import sbt.internal.inc.classpath.ClasspathUtil
|
||||||
import sbt.internal.inc.{ ScalaInstance, ZincLmUtil, ZincUtil }
|
import sbt.internal.inc.{ MappedFileConverter, ScalaInstance, ZincLmUtil, ZincUtil }
|
||||||
import sbt.internal.server.BuildServerEvalReporter
|
import sbt.internal.server.BuildServerEvalReporter
|
||||||
import sbt.internal.util.Attributed.data
|
import sbt.internal.util.Attributed.data
|
||||||
import sbt.internal.util.Types.const
|
import sbt.internal.util.Types.const
|
||||||
|
|
@ -27,13 +28,14 @@ import sbt.librarymanagement.ivy.{ InlineIvyConfiguration, IvyDependencyResoluti
|
||||||
import sbt.librarymanagement.{ Configuration, Configurations, Resolver }
|
import sbt.librarymanagement.{ Configuration, Configurations, Resolver }
|
||||||
import sbt.nio.Settings
|
import sbt.nio.Settings
|
||||||
import sbt.util.{ Logger, Show }
|
import sbt.util.{ Logger, Show }
|
||||||
|
import xsbti.VirtualFile
|
||||||
import xsbti.compile.{ ClasspathOptionsUtil, Compilers }
|
import xsbti.compile.{ ClasspathOptionsUtil, Compilers }
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
import java.nio.file.{ Path, Paths }
|
||||||
import scala.annotation.{ nowarn, tailrec }
|
import scala.annotation.{ nowarn, tailrec }
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.tools.nsc.reporters.ConsoleReporter
|
// import scala.tools.nsc.reporters.ConsoleReporter
|
||||||
|
|
||||||
private[sbt] object Load {
|
private[sbt] object Load {
|
||||||
// note that there is State passed in but not pulled out
|
// note that there is State passed in but not pulled out
|
||||||
|
|
@ -68,6 +70,13 @@ private[sbt] object Load {
|
||||||
val scalaProvider = app.provider.scalaProvider
|
val scalaProvider = app.provider.scalaProvider
|
||||||
val launcher = scalaProvider.launcher
|
val launcher = scalaProvider.launcher
|
||||||
val stagingDirectory = getStagingDirectory(state, globalBase).getCanonicalFile
|
val stagingDirectory = getStagingDirectory(state, globalBase).getCanonicalFile
|
||||||
|
val javaHome = Paths.get(sys.props("java.home"))
|
||||||
|
val rootPaths = Map(
|
||||||
|
"BASE" -> baseDirectory.toPath,
|
||||||
|
"SBT_BOOT" -> launcher.bootDirectory.toPath,
|
||||||
|
"IVY_HOME" -> launcher.ivyHome.toPath,
|
||||||
|
"JAVA_HOME" -> javaHome,
|
||||||
|
)
|
||||||
val loader = getClass.getClassLoader
|
val loader = getClass.getClassLoader
|
||||||
val classpath = Attributed.blankSeq(provider.mainClasspath ++ scalaProvider.jars)
|
val classpath = Attributed.blankSeq(provider.mainClasspath ++ scalaProvider.jars)
|
||||||
val ivyConfiguration =
|
val ivyConfiguration =
|
||||||
|
|
@ -115,6 +124,7 @@ private[sbt] object Load {
|
||||||
inject,
|
inject,
|
||||||
None,
|
None,
|
||||||
Nil,
|
Nil,
|
||||||
|
converter = MappedFileConverter(rootPaths, false),
|
||||||
log
|
log
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -139,28 +149,33 @@ private[sbt] object Load {
|
||||||
): LoadBuildConfiguration = {
|
): LoadBuildConfiguration = {
|
||||||
val globalPluginsDir = getGlobalPluginsDirectory(state, globalBase)
|
val globalPluginsDir = getGlobalPluginsDirectory(state, globalBase)
|
||||||
val withGlobal = loadGlobal(state, base, globalPluginsDir, rawConfig)
|
val withGlobal = loadGlobal(state, base, globalPluginsDir, rawConfig)
|
||||||
val globalSettings = configurationSources(getGlobalSettingsDirectory(state, globalBase))
|
val globalSettings: Seq[VirtualFile] =
|
||||||
|
configurationSources(getGlobalSettingsDirectory(state, globalBase))
|
||||||
|
.map(x => rawConfig.converter.toVirtualFile(x.toPath))
|
||||||
loadGlobalSettings(base, globalBase, globalSettings, withGlobal)
|
loadGlobalSettings(base, globalBase, globalSettings, withGlobal)
|
||||||
}
|
}
|
||||||
|
|
||||||
def loadGlobalSettings(
|
def loadGlobalSettings(
|
||||||
base: File,
|
base: File,
|
||||||
globalBase: File,
|
globalBase: File,
|
||||||
files: Seq[File],
|
files: Seq[VirtualFile],
|
||||||
config: LoadBuildConfiguration
|
config: LoadBuildConfiguration
|
||||||
): LoadBuildConfiguration = {
|
): LoadBuildConfiguration =
|
||||||
val compiled: ClassLoader => Seq[Setting[_]] =
|
val compiled: ClassLoader => Seq[Setting[_]] =
|
||||||
if (files.isEmpty || base == globalBase) const(Nil)
|
if (files.isEmpty || base == globalBase) const(Nil)
|
||||||
else buildGlobalSettings(globalBase, files, config)
|
else buildGlobalSettings(globalBase, files, config)
|
||||||
config.copy(injectSettings = config.injectSettings.copy(projectLoaded = compiled))
|
config.copy(injectSettings = config.injectSettings.copy(projectLoaded = compiled))
|
||||||
}
|
|
||||||
|
|
||||||
def buildGlobalSettings(
|
def buildGlobalSettings(
|
||||||
base: File,
|
base: File,
|
||||||
files: Seq[File],
|
files: Seq[VirtualFile],
|
||||||
config: LoadBuildConfiguration
|
config: LoadBuildConfiguration
|
||||||
): ClassLoader => Seq[Setting[_]] = {
|
): ClassLoader => Seq[Setting[_]] = {
|
||||||
val eval = mkEval(data(config.globalPluginClasspath), base, defaultEvalOptions)
|
val eval = mkEval(
|
||||||
|
classpath = data(config.globalPluginClasspath).map(_.toPath()),
|
||||||
|
base = base,
|
||||||
|
options = defaultEvalOptions,
|
||||||
|
)
|
||||||
|
|
||||||
val imports =
|
val imports =
|
||||||
BuildUtil.baseImports ++ config.detectedGlobalPlugins.imports
|
BuildUtil.baseImports ++ config.detectedGlobalPlugins.imports
|
||||||
|
|
@ -254,7 +269,7 @@ private[sbt] object Load {
|
||||||
if (settings.size > 10000) {
|
if (settings.size > 10000) {
|
||||||
log.info(s"resolving key references (${settings.size} settings) ...")
|
log.info(s"resolving key references (${settings.size} settings) ...")
|
||||||
}
|
}
|
||||||
Def.makeWithCompiledMap(settings)(
|
Def.makeWithCompiledMap(settings)(using
|
||||||
delegates,
|
delegates,
|
||||||
config.scopeLocal,
|
config.scopeLocal,
|
||||||
Project.showLoadingKey(loaded)
|
Project.showLoadingKey(loaded)
|
||||||
|
|
@ -274,7 +289,8 @@ private[sbt] object Load {
|
||||||
streams,
|
streams,
|
||||||
delegates,
|
delegates,
|
||||||
config.scopeLocal,
|
config.scopeLocal,
|
||||||
cMap
|
cMap,
|
||||||
|
config.converter,
|
||||||
)
|
)
|
||||||
(rootEval, bs)
|
(rootEval, bs)
|
||||||
}
|
}
|
||||||
|
|
@ -285,11 +301,12 @@ private[sbt] object Load {
|
||||||
// 3. resolvedScoped is replaced with the defining key as a value
|
// 3. resolvedScoped is replaced with the defining key as a value
|
||||||
// Note: this must be idempotent.
|
// Note: this must be idempotent.
|
||||||
def finalTransforms(ss: Seq[Setting[_]]): Seq[Setting[_]] = {
|
def finalTransforms(ss: Seq[Setting[_]]): Seq[Setting[_]] = {
|
||||||
def mapSpecial(to: ScopedKey[_]) = λ[ScopedKey ~> ScopedKey]((key: ScopedKey[_]) =>
|
def mapSpecial(to: ScopedKey[_]): [a] => ScopedKey[a] => ScopedKey[a] =
|
||||||
if (key.key == streams.key) {
|
[a] =>
|
||||||
ScopedKey(Scope.fillTaskAxis(Scope.replaceThis(to.scope)(key.scope), to.key), key.key)
|
(key: ScopedKey[a]) =>
|
||||||
} else key
|
if key.key == streams.key then
|
||||||
)
|
ScopedKey(Scope.fillTaskAxis(Scope.replaceThis(to.scope)(key.scope), to.key), key.key)
|
||||||
|
else key
|
||||||
def setDefining[T] =
|
def setDefining[T] =
|
||||||
(key: ScopedKey[T], value: T) =>
|
(key: ScopedKey[T], value: T) =>
|
||||||
value match {
|
value match {
|
||||||
|
|
@ -297,12 +314,12 @@ private[sbt] object Load {
|
||||||
case ik: InputTask[t] => ik.mapTask(tk => setDefinitionKey(tk, key)).asInstanceOf[T]
|
case ik: InputTask[t] => ik.mapTask(tk => setDefinitionKey(tk, key)).asInstanceOf[T]
|
||||||
case _ => value
|
case _ => value
|
||||||
}
|
}
|
||||||
def setResolved(defining: ScopedKey[_]) = λ[ScopedKey ~> Option]((key: ScopedKey[_]) =>
|
def setResolved(defining: ScopedKey[_]): [a] => ScopedKey[a] => Option[a] =
|
||||||
key.key match {
|
[a] =>
|
||||||
case resolvedScoped.key => Some(defining.asInstanceOf[A1$])
|
(key: ScopedKey[a]) =>
|
||||||
case _ => None
|
key.key match
|
||||||
}
|
case resolvedScoped.key => Some(defining.asInstanceOf[a])
|
||||||
)
|
case _ => None
|
||||||
ss.map(s =>
|
ss.map(s =>
|
||||||
s mapConstant setResolved(s.key) mapReferenced mapSpecial(s.key) mapInit setDefining
|
s mapConstant setResolved(s.key) mapReferenced mapSpecial(s.key) mapInit setDefining
|
||||||
)
|
)
|
||||||
|
|
@ -340,7 +357,7 @@ private[sbt] object Load {
|
||||||
): BuildStructure = {
|
): BuildStructure = {
|
||||||
val transformed = finalTransforms(newSettings)
|
val transformed = finalTransforms(newSettings)
|
||||||
val (cMap, newData) =
|
val (cMap, newData) =
|
||||||
Def.makeWithCompiledMap(transformed)(structure.delegates, structure.scopeLocal, display)
|
Def.makeWithCompiledMap(transformed)(using structure.delegates, structure.scopeLocal, display)
|
||||||
def extra(index: KeyIndex) = BuildUtil(structure.root, structure.units, index, newData)
|
def extra(index: KeyIndex) = BuildUtil(structure.root, structure.units, index, newData)
|
||||||
val newIndex = structureIndex(newData, transformed, extra, structure.units)
|
val newIndex = structureIndex(newData, transformed, extra, structure.units)
|
||||||
val newStreams = mkStreams(structure.units, structure.root, newData)
|
val newStreams = mkStreams(structure.units, structure.root, newData)
|
||||||
|
|
@ -354,6 +371,7 @@ private[sbt] object Load {
|
||||||
delegates = structure.delegates,
|
delegates = structure.delegates,
|
||||||
scopeLocal = structure.scopeLocal,
|
scopeLocal = structure.scopeLocal,
|
||||||
compiledMap = cMap,
|
compiledMap = cMap,
|
||||||
|
converter = structure.converter,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -421,39 +439,51 @@ private[sbt] object Load {
|
||||||
|
|
||||||
def mkEval(unit: BuildUnit): Eval = {
|
def mkEval(unit: BuildUnit): Eval = {
|
||||||
val defs = unit.definitions
|
val defs = unit.definitions
|
||||||
mkEval(defs.target ++ unit.plugins.classpath, defs.base, unit.plugins.pluginData.scalacOptions)
|
mkEval(
|
||||||
|
(defs.target ++ unit.plugins.classpath).map(_.toPath()),
|
||||||
|
defs.base,
|
||||||
|
unit.plugins.pluginData.scalacOptions,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def mkEval(classpath: Seq[File], base: File, options: Seq[String]): Eval =
|
def mkEval(classpath: Seq[Path], base: File, options: Seq[String]): Eval =
|
||||||
mkEval(classpath, base, options, EvalReporter.console)
|
mkEval(classpath, base, options, () => EvalReporter.console)
|
||||||
|
|
||||||
def mkEval(
|
def mkEval(
|
||||||
classpath: Seq[File],
|
classpath: Seq[Path],
|
||||||
base: File,
|
base: File,
|
||||||
options: Seq[String],
|
options: Seq[String],
|
||||||
mkReporter: scala.tools.nsc.Settings => EvalReporter
|
mkReporter: () => EvalReporter,
|
||||||
): Eval =
|
): Eval =
|
||||||
new Eval(options, classpath, mkReporter, Some(evalOutputDirectory(base)))
|
new Eval(
|
||||||
|
nonCpOptions = options,
|
||||||
|
classpath = classpath,
|
||||||
|
backingDir = Option(evalOutputDirectory(base).toPath()),
|
||||||
|
mkReporter = Option(() => (mkReporter(): dotty.tools.dotc.reporting.Reporter)),
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will clean up left-over files in the config-classes directory if they are no longer used.
|
* This will clean up left-over files in the config-classes directory if they are no longer used.
|
||||||
*
|
*
|
||||||
* @param base The base directory for the build, should match the one passed into `mkEval` method.
|
* @param base The base directory for the build, should match the one passed into `mkEval` method.
|
||||||
*/
|
*/
|
||||||
def cleanEvalClasses(base: File, keep: Seq[File]): Unit = {
|
def cleanEvalClasses(base: File, keep: Seq[Path]): Unit = {
|
||||||
val baseTarget = evalOutputDirectory(base)
|
val baseTarget = evalOutputDirectory(base)
|
||||||
val keepSet = keep.map(_.getCanonicalPath).toSet
|
val keepSet = keep.map(_.toAbsolutePath().normalize()).toSet
|
||||||
// If there are no keeper files, this may be because cache was up-to-date and
|
// If there are no keeper files, this may be because cache was up-to-date and
|
||||||
// the files aren't properly returned, even though they should be.
|
// the files aren't properly returned, even though they should be.
|
||||||
// TODO - figure out where the caching of whether or not to generate classfiles occurs, and
|
// TODO - figure out where the caching of whether or not to generate classfiles occurs, and
|
||||||
// put cleanups there, perhaps.
|
// put cleanups there, perhaps.
|
||||||
if (keepSet.nonEmpty) {
|
if (keepSet.nonEmpty) {
|
||||||
def keepFile(f: File) = keepSet(f.getCanonicalPath)
|
def keepFile(f: Path) = keepSet(f.toAbsolutePath().normalize())
|
||||||
import sbt.io.syntax._
|
import sbt.io.syntax._
|
||||||
val existing = (baseTarget.allPaths.get).filterNot(_.isDirectory)
|
val existing = (baseTarget.allPaths
|
||||||
|
.get())
|
||||||
|
.filterNot(_.isDirectory)
|
||||||
|
.map(_.toPath())
|
||||||
val toDelete = existing.filterNot(keepFile)
|
val toDelete = existing.filterNot(keepFile)
|
||||||
if (toDelete.nonEmpty) {
|
if (toDelete.nonEmpty) {
|
||||||
IO.delete(toDelete)
|
IO.delete(toDelete.map(_.toFile()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -472,7 +502,7 @@ private[sbt] object Load {
|
||||||
val newConfig: LoadBuildConfiguration =
|
val newConfig: LoadBuildConfiguration =
|
||||||
config.copy(pluginManagement = manager, extraBuilds = Nil)
|
config.copy(pluginManagement = manager, extraBuilds = Nil)
|
||||||
val loader = builtinLoader(s, newConfig)
|
val loader = builtinLoader(s, newConfig)
|
||||||
loadURI(IO.directoryURI(root), loader, config.extraBuilds.toList)
|
loadURI(IO.directoryURI(root), loader, config.extraBuilds.toList, newConfig.converter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -492,12 +522,17 @@ private[sbt] object Load {
|
||||||
BuildLoader(components, fail, s, config)
|
BuildLoader(components, fail, s, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def loadURI(uri: URI, loader: BuildLoader, extra: List[URI]): PartBuild = {
|
private def loadURI(
|
||||||
|
uri: URI,
|
||||||
|
loader: BuildLoader,
|
||||||
|
extra: List[URI],
|
||||||
|
converter: MappedFileConverter,
|
||||||
|
): PartBuild = {
|
||||||
IO.assertAbsolute(uri)
|
IO.assertAbsolute(uri)
|
||||||
val (referenced, map, newLoaders) = loadAll(uri +: extra, Map.empty, loader, Map.empty)
|
val (referenced, map, newLoaders) = loadAll(uri +: extra, Map.empty, loader, Map.empty)
|
||||||
checkAll(referenced, map)
|
checkAll(referenced, map)
|
||||||
val build = new PartBuild(uri, map)
|
val build = PartBuild(uri, map, converter)
|
||||||
newLoaders transformAll build
|
newLoaders.transformAll(build)
|
||||||
}
|
}
|
||||||
|
|
||||||
def addOverrides(unit: BuildUnit, loaders: BuildLoader): BuildLoader =
|
def addOverrides(unit: BuildUnit, loaders: BuildLoader): BuildLoader =
|
||||||
|
|
@ -703,20 +738,27 @@ private[sbt] object Load {
|
||||||
|
|
||||||
// NOTE - because we create an eval here, we need a clean-eval later for this URI.
|
// NOTE - because we create an eval here, we need a clean-eval later for this URI.
|
||||||
lazy val eval = timed("Load.loadUnit: mkEval", log) {
|
lazy val eval = timed("Load.loadUnit: mkEval", log) {
|
||||||
def mkReporter(settings: scala.tools.nsc.Settings): EvalReporter =
|
def mkReporter() = EvalReporter.console
|
||||||
plugs.pluginData.buildTarget match {
|
// todo:
|
||||||
case None => EvalReporter.console(settings)
|
// def mkReporter(settings: scala.tools.nsc.Settings): EvalReporter =
|
||||||
case Some(buildTarget) =>
|
// plugs.pluginData.buildTarget match {
|
||||||
new BuildServerEvalReporter(buildTarget, new ConsoleReporter(settings))
|
// case None => EvalReporter.console // (settings)
|
||||||
}
|
// case Some(buildTarget) =>
|
||||||
mkEval(plugs.classpath, defDir, plugs.pluginData.scalacOptions, mkReporter)
|
// new BuildServerEvalReporter(buildTarget, new ConsoleReporter(settings))
|
||||||
|
// }
|
||||||
|
mkEval(
|
||||||
|
classpath = plugs.classpath.map(_.toPath()),
|
||||||
|
defDir,
|
||||||
|
plugs.pluginData.scalacOptions,
|
||||||
|
mkReporter,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val initialProjects =
|
val initialProjects =
|
||||||
defsScala.flatMap(b => projectsFromBuild(b, normBase)) ++ buildLevelExtraProjects
|
defsScala.flatMap(b => projectsFromBuild(b, normBase)) ++ buildLevelExtraProjects
|
||||||
|
|
||||||
val hasRootAlreadyDefined = defsScala.exists(_.rootProject.isDefined)
|
val hasRootAlreadyDefined = defsScala.exists(_.rootProject.isDefined)
|
||||||
|
|
||||||
val memoSettings = new mutable.HashMap[File, LoadedSbtFile]
|
val memoSettings = new mutable.HashMap[VirtualFile, LoadedSbtFile]
|
||||||
def loadProjects(ps: Seq[Project], createRoot: Boolean) =
|
def loadProjects(ps: Seq[Project], createRoot: Boolean) =
|
||||||
loadTransitive(
|
loadTransitive(
|
||||||
ps,
|
ps,
|
||||||
|
|
@ -731,7 +773,8 @@ private[sbt] object Load {
|
||||||
uri,
|
uri,
|
||||||
config.pluginManagement.context,
|
config.pluginManagement.context,
|
||||||
Nil,
|
Nil,
|
||||||
s.get(BasicKeys.extraMetaSbtFiles).getOrElse(Nil)
|
s.get(BasicKeys.extraMetaSbtFiles).getOrElse(Nil),
|
||||||
|
converter = config.converter,
|
||||||
)
|
)
|
||||||
val loadedProjectsRaw = timed("Load.loadUnit: loadedProjectsRaw", log) {
|
val loadedProjectsRaw = timed("Load.loadUnit: loadedProjectsRaw", log) {
|
||||||
loadProjects(initialProjects, !hasRootAlreadyDefined)
|
loadProjects(initialProjects, !hasRootAlreadyDefined)
|
||||||
|
|
@ -817,7 +860,7 @@ private[sbt] object Load {
|
||||||
// Lame hackery to keep track of our state.
|
// Lame hackery to keep track of our state.
|
||||||
private[this] case class LoadedProjects(
|
private[this] case class LoadedProjects(
|
||||||
projects: Seq[Project],
|
projects: Seq[Project],
|
||||||
generatedConfigClassFiles: Seq[File]
|
generatedConfigClassFiles: Seq[Path],
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -857,17 +900,18 @@ private[sbt] object Load {
|
||||||
eval: () => Eval,
|
eval: () => Eval,
|
||||||
injectSettings: InjectSettings,
|
injectSettings: InjectSettings,
|
||||||
acc: Seq[Project],
|
acc: Seq[Project],
|
||||||
memoSettings: mutable.Map[File, LoadedSbtFile],
|
memoSettings: mutable.Map[VirtualFile, LoadedSbtFile],
|
||||||
log: Logger,
|
log: Logger,
|
||||||
makeOrDiscoverRoot: Boolean,
|
makeOrDiscoverRoot: Boolean,
|
||||||
buildUri: URI,
|
buildUri: URI,
|
||||||
context: PluginManagement.Context,
|
context: PluginManagement.Context,
|
||||||
generatedConfigClassFiles: Seq[File],
|
generatedConfigClassFiles: Seq[Path],
|
||||||
extraSbtFiles: Seq[File]
|
extraSbtFiles: Seq[VirtualFile],
|
||||||
|
converter: MappedFileConverter,
|
||||||
): LoadedProjects =
|
): LoadedProjects =
|
||||||
/*timed(s"Load.loadTransitive(${ newProjects.map(_.id) })", log)*/ {
|
/*timed(s"Load.loadTransitive(${ newProjects.map(_.id) })", log)*/ {
|
||||||
|
|
||||||
def load(newProjects: Seq[Project], acc: Seq[Project], generated: Seq[File]) = {
|
def load(newProjects: Seq[Project], acc: Seq[Project], generated: Seq[Path]) = {
|
||||||
loadTransitive(
|
loadTransitive(
|
||||||
newProjects,
|
newProjects,
|
||||||
buildBase,
|
buildBase,
|
||||||
|
|
@ -881,7 +925,8 @@ private[sbt] object Load {
|
||||||
buildUri,
|
buildUri,
|
||||||
context,
|
context,
|
||||||
generated,
|
generated,
|
||||||
Nil
|
Nil,
|
||||||
|
converter,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -894,7 +939,7 @@ private[sbt] object Load {
|
||||||
val extraFiles =
|
val extraFiles =
|
||||||
if (base == buildBase && isMetaBuildContext(context)) extraSbtFiles
|
if (base == buildBase && isMetaBuildContext(context)) extraSbtFiles
|
||||||
else Nil
|
else Nil
|
||||||
discoverProjects(auto, base, extraFiles, plugins, eval, memoSettings)
|
discoverProjects(auto, base, extraFiles, plugins, eval, memoSettings, converter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step two:
|
// Step two:
|
||||||
|
|
@ -903,8 +948,8 @@ private[sbt] object Load {
|
||||||
// c. Finalize a project with all its settings/configuration.
|
// c. Finalize a project with all its settings/configuration.
|
||||||
def finalizeProject(
|
def finalizeProject(
|
||||||
p: Project,
|
p: Project,
|
||||||
files: Seq[File],
|
files: Seq[VirtualFile],
|
||||||
extraFiles: Seq[File],
|
extraFiles: Seq[VirtualFile],
|
||||||
expand: Boolean
|
expand: Boolean
|
||||||
): (Project, Seq[Project]) = {
|
): (Project, Seq[Project]) = {
|
||||||
val configFiles = files.flatMap(f => memoSettings.get(f))
|
val configFiles = files.flatMap(f => memoSettings.get(f))
|
||||||
|
|
@ -913,7 +958,16 @@ private[sbt] object Load {
|
||||||
try plugins.detected.deducePluginsFromProject(p1, log)
|
try plugins.detected.deducePluginsFromProject(p1, log)
|
||||||
catch { case e: AutoPluginException => throw translateAutoPluginException(e, p) }
|
catch { case e: AutoPluginException => throw translateAutoPluginException(e, p) }
|
||||||
val p2 =
|
val p2 =
|
||||||
resolveProject(p1, autoPlugins, plugins, injectSettings, memoSettings, extraFiles, log)
|
resolveProject(
|
||||||
|
p1,
|
||||||
|
autoPlugins,
|
||||||
|
plugins,
|
||||||
|
injectSettings,
|
||||||
|
memoSettings,
|
||||||
|
extraFiles,
|
||||||
|
converter,
|
||||||
|
log
|
||||||
|
)
|
||||||
val projectLevelExtra =
|
val projectLevelExtra =
|
||||||
if (expand) {
|
if (expand) {
|
||||||
autoPlugins.flatMap(
|
autoPlugins.flatMap(
|
||||||
|
|
@ -1004,9 +1058,9 @@ private[sbt] object Load {
|
||||||
private[this] case class DiscoveredProjects(
|
private[this] case class DiscoveredProjects(
|
||||||
root: Option[Project],
|
root: Option[Project],
|
||||||
nonRoot: Seq[Project],
|
nonRoot: Seq[Project],
|
||||||
sbtFiles: Seq[File],
|
sbtFiles: Seq[VirtualFile],
|
||||||
extraSbtFiles: Seq[File],
|
extraSbtFiles: Seq[VirtualFile],
|
||||||
generatedFiles: Seq[File]
|
generatedFiles: Seq[Path]
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1028,8 +1082,9 @@ private[sbt] object Load {
|
||||||
projectPlugins: Seq[AutoPlugin],
|
projectPlugins: Seq[AutoPlugin],
|
||||||
loadedPlugins: LoadedPlugins,
|
loadedPlugins: LoadedPlugins,
|
||||||
globalUserSettings: InjectSettings,
|
globalUserSettings: InjectSettings,
|
||||||
memoSettings: mutable.Map[File, LoadedSbtFile],
|
memoSettings: mutable.Map[VirtualFile, LoadedSbtFile],
|
||||||
extraSbtFiles: Seq[File],
|
extraSbtFiles: Seq[VirtualFile],
|
||||||
|
converter: MappedFileConverter,
|
||||||
log: Logger
|
log: Logger
|
||||||
): Project =
|
): Project =
|
||||||
timed(s"Load.resolveProject(${p.id})", log) {
|
timed(s"Load.resolveProject(${p.id})", log) {
|
||||||
|
|
@ -1040,35 +1095,37 @@ private[sbt] object Load {
|
||||||
val allSettings = {
|
val allSettings = {
|
||||||
// TODO - This mechanism of applying settings could be off... It's in two places now...
|
// TODO - This mechanism of applying settings could be off... It's in two places now...
|
||||||
lazy val defaultSbtFiles = configurationSources(p.base)
|
lazy val defaultSbtFiles = configurationSources(p.base)
|
||||||
lazy val sbtFiles = defaultSbtFiles ++ extraSbtFiles
|
.map(_.toPath())
|
||||||
|
.map(converter.toVirtualFile)
|
||||||
|
lazy val sbtFiles: Seq[VirtualFile] = defaultSbtFiles ++ extraSbtFiles
|
||||||
// Filter the AutoPlugin settings we included based on which ones are
|
// Filter the AutoPlugin settings we included based on which ones are
|
||||||
// intended in the AddSettings.AutoPlugins filter.
|
// intended in the AddSettings.AutoPlugins filter.
|
||||||
def autoPluginSettings(f: AutoPlugins) =
|
def autoPluginSettings(f: AutoPlugins) =
|
||||||
projectPlugins.filter(f.include).flatMap(_.projectSettings)
|
projectPlugins.filter(f.include).flatMap(_.projectSettings)
|
||||||
// Grab all the settings we already loaded from sbt files
|
// Grab all the settings we already loaded from sbt files
|
||||||
def settings(files: Seq[File]): Seq[Setting[_]] = {
|
def settings(files: Seq[VirtualFile]): Seq[Setting[_]] = {
|
||||||
if (files.nonEmpty)
|
if (files.nonEmpty)
|
||||||
log.info(
|
log.info(
|
||||||
s"${files.map(_.getName).mkString(s"loading settings for project ${p.id} from ", ",", " ...")}"
|
s"${files.map(_.name()).mkString(s"loading settings for project ${p.id} from ", ",", " ...")}"
|
||||||
)
|
)
|
||||||
for {
|
for {
|
||||||
file <- files
|
file <- files
|
||||||
config <- (memoSettings get file).toSeq
|
config <- memoSettings.get(file).toSeq
|
||||||
setting <- config.settings
|
setting <- config.settings
|
||||||
} yield setting
|
} yield setting
|
||||||
}
|
}
|
||||||
// Expand the AddSettings instance into a real Seq[Setting[_]] we'll use on the project
|
// Expand the AddSettings instance into a real Seq[Setting[_]] we'll use on the project
|
||||||
def expandSettings(auto: AddSettings): Seq[Setting[_]] = auto match {
|
def expandSettings(auto: AddSettings): Seq[Setting[_]] =
|
||||||
case BuildScalaFiles => p.settings
|
auto match
|
||||||
case User => globalUserSettings.cachedProjectLoaded(loadedPlugins.loader)
|
case BuildScalaFiles => p.settings
|
||||||
case sf: SbtFiles => settings(sf.files.map(f => IO.resolve(p.base, f)))
|
case User => globalUserSettings.cachedProjectLoaded(loadedPlugins.loader)
|
||||||
case sf: DefaultSbtFiles => settings(sbtFiles.filter(sf.include))
|
// case sf: SbtFiles => settings(sf.files.map(f => IO.resolve(p.base, f)))
|
||||||
case p: AutoPlugins => autoPluginSettings(p)
|
case sf: DefaultSbtFiles => settings(sbtFiles.filter(sf.include))
|
||||||
case q: Sequence =>
|
case p: AutoPlugins => autoPluginSettings(p)
|
||||||
q.sequence.foldLeft(Seq.empty[Setting[_]]) { (b, add) =>
|
case q: Sequence =>
|
||||||
b ++ expandSettings(add)
|
q.sequence.foldLeft(Seq.empty[Setting[_]]) { (b, add) =>
|
||||||
}
|
b ++ expandSettings(add)
|
||||||
}
|
}
|
||||||
val auto = AddSettings.allDefaults
|
val auto = AddSettings.allDefaults
|
||||||
expandSettings(auto)
|
expandSettings(auto)
|
||||||
}
|
}
|
||||||
|
|
@ -1089,14 +1146,17 @@ private[sbt] object Load {
|
||||||
private[this] def discoverProjects(
|
private[this] def discoverProjects(
|
||||||
auto: AddSettings,
|
auto: AddSettings,
|
||||||
projectBase: File,
|
projectBase: File,
|
||||||
extraSbtFiles: Seq[File],
|
extraSbtFiles: Seq[VirtualFile],
|
||||||
loadedPlugins: LoadedPlugins,
|
loadedPlugins: LoadedPlugins,
|
||||||
eval: () => Eval,
|
eval: () => Eval,
|
||||||
memoSettings: mutable.Map[File, LoadedSbtFile]
|
memoSettings: mutable.Map[VirtualFile, LoadedSbtFile],
|
||||||
|
converter: MappedFileConverter,
|
||||||
): DiscoveredProjects = {
|
): DiscoveredProjects = {
|
||||||
|
|
||||||
// Default sbt files to read, if needed
|
// Default sbt files to read, if needed
|
||||||
lazy val defaultSbtFiles = configurationSources(projectBase)
|
lazy val defaultSbtFiles = configurationSources(projectBase)
|
||||||
|
.map(_.toPath)
|
||||||
|
.map(converter.toVirtualFile)
|
||||||
lazy val sbtFiles = defaultSbtFiles ++ extraSbtFiles
|
lazy val sbtFiles = defaultSbtFiles ++ extraSbtFiles
|
||||||
|
|
||||||
// Classloader of the build
|
// Classloader of the build
|
||||||
|
|
@ -1105,11 +1165,11 @@ private[sbt] object Load {
|
||||||
// How to load an individual file for use later.
|
// How to load an individual file for use later.
|
||||||
// TODO - We should import vals defined in other sbt files here, if we wish to
|
// TODO - We should import vals defined in other sbt files here, if we wish to
|
||||||
// share. For now, build.sbt files have their own unique namespace.
|
// share. For now, build.sbt files have their own unique namespace.
|
||||||
def loadSettingsFile(src: File): LoadedSbtFile =
|
def loadSettingsFile(src: VirtualFile): LoadedSbtFile =
|
||||||
EvaluateConfigurations.evaluateSbtFile(
|
EvaluateConfigurations.evaluateSbtFile(
|
||||||
eval(),
|
eval(),
|
||||||
src,
|
src,
|
||||||
IO.readLines(src),
|
IO.readStream(src.input()).linesIterator.toList,
|
||||||
loadedPlugins.detected.imports,
|
loadedPlugins.detected.imports,
|
||||||
0
|
0
|
||||||
)(loader)
|
)(loader)
|
||||||
|
|
@ -1119,7 +1179,7 @@ private[sbt] object Load {
|
||||||
}
|
}
|
||||||
// Loads a given file, or pulls from the cache.
|
// Loads a given file, or pulls from the cache.
|
||||||
|
|
||||||
def memoLoadSettingsFile(src: File): LoadedSbtFile =
|
def memoLoadSettingsFile(src: VirtualFile): LoadedSbtFile =
|
||||||
memoSettings.getOrElse(
|
memoSettings.getOrElse(
|
||||||
src, {
|
src, {
|
||||||
val lf = loadSettingsFile(src)
|
val lf = loadSettingsFile(src)
|
||||||
|
|
@ -1129,20 +1189,31 @@ private[sbt] object Load {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Loads a set of sbt files, sorted by their lexical name (current behavior of sbt).
|
// Loads a set of sbt files, sorted by their lexical name (current behavior of sbt).
|
||||||
def loadFiles(fs: Seq[File]): LoadedSbtFile =
|
def loadFiles(fs: Seq[VirtualFile]): LoadedSbtFile =
|
||||||
merge(fs.sortBy(_.getName).map(memoLoadSettingsFile))
|
merge(
|
||||||
|
fs.sortBy(_.name())
|
||||||
|
.map(memoLoadSettingsFile)
|
||||||
|
)
|
||||||
|
|
||||||
// Finds all the build files associated with this project
|
// Finds all the build files associated with this project
|
||||||
import AddSettings.{ DefaultSbtFiles, SbtFiles, Sequence }
|
import AddSettings.{ DefaultSbtFiles, Sequence }
|
||||||
def associatedFiles(auto: AddSettings): Seq[File] = auto match {
|
def associatedFiles(auto: AddSettings): Seq[VirtualFile] =
|
||||||
case sf: SbtFiles => sf.files.map(f => IO.resolve(projectBase, f)).filterNot(_.isHidden)
|
auto match
|
||||||
case sf: DefaultSbtFiles => sbtFiles.filter(sf.include).filterNot(_.isHidden)
|
// case sf: SbtFiles =>
|
||||||
case q: Sequence =>
|
// sf.files
|
||||||
q.sequence.foldLeft(Seq.empty[File]) { (b, add) =>
|
// .map(f => IO.resolve(projectBase, f))
|
||||||
b ++ associatedFiles(add)
|
// .filterNot(_.isHidden)
|
||||||
}
|
// .map(_.toPath)
|
||||||
case _ => Seq.empty
|
case sf: DefaultSbtFiles =>
|
||||||
}
|
sbtFiles
|
||||||
|
// .filter(sf.include)
|
||||||
|
// .filterNot(_.isHidden)
|
||||||
|
// .map(_.toPath)
|
||||||
|
case q: Sequence =>
|
||||||
|
q.sequence.foldLeft(Seq.empty[VirtualFile]) { (b, add) =>
|
||||||
|
b ++ associatedFiles(add)
|
||||||
|
}
|
||||||
|
case _ => Seq.empty
|
||||||
val rawFiles = associatedFiles(auto)
|
val rawFiles = associatedFiles(auto)
|
||||||
val loadedFiles = loadFiles(rawFiles)
|
val loadedFiles = loadFiles(rawFiles)
|
||||||
val rawProjects = loadedFiles.projects
|
val rawProjects = loadedFiles.projects
|
||||||
|
|
@ -1223,7 +1294,7 @@ private[sbt] object Load {
|
||||||
|
|
||||||
def plugins(dir: File, s: State, config: LoadBuildConfiguration): LoadedPlugins = {
|
def plugins(dir: File, s: State, config: LoadBuildConfiguration): LoadedPlugins = {
|
||||||
val context = config.pluginManagement.context
|
val context = config.pluginManagement.context
|
||||||
val extraSbtFiles: Seq[File] =
|
val extraSbtFiles: Seq[VirtualFile] =
|
||||||
if (isMetaBuildContext(context)) s.get(BasicKeys.extraMetaSbtFiles).getOrElse(Nil)
|
if (isMetaBuildContext(context)) s.get(BasicKeys.extraMetaSbtFiles).getOrElse(Nil)
|
||||||
else Nil
|
else Nil
|
||||||
if (hasDefinition(dir) || extraSbtFiles.nonEmpty)
|
if (hasDefinition(dir) || extraSbtFiles.nonEmpty)
|
||||||
|
|
@ -1237,7 +1308,7 @@ private[sbt] object Load {
|
||||||
|
|
||||||
def hasDefinition(dir: File): Boolean = {
|
def hasDefinition(dir: File): Boolean = {
|
||||||
import sbt.io.syntax._
|
import sbt.io.syntax._
|
||||||
(dir * -GlobFilter(DefaultTargetName)).get.nonEmpty
|
(dir * -GlobFilter(DefaultTargetName)).get().nonEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
def noPlugins(dir: File, config: LoadBuildConfiguration): LoadedPlugins =
|
def noPlugins(dir: File, config: LoadBuildConfiguration): LoadedPlugins =
|
||||||
|
|
@ -1310,7 +1381,7 @@ private[sbt] object Load {
|
||||||
else {
|
else {
|
||||||
// Load only the dependency classpath for the common plugin classloader
|
// Load only the dependency classpath for the common plugin classloader
|
||||||
val loader = manager.loader
|
val loader = manager.loader
|
||||||
loader.add(Path.toURLs(data(dependencyClasspath)))
|
loader.add(sbt.io.Path.toURLs(data(dependencyClasspath)))
|
||||||
loader
|
loader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1425,6 +1496,7 @@ final case class LoadBuildConfiguration(
|
||||||
injectSettings: Load.InjectSettings,
|
injectSettings: Load.InjectSettings,
|
||||||
globalPlugin: Option[GlobalPlugin],
|
globalPlugin: Option[GlobalPlugin],
|
||||||
extraBuilds: Seq[URI],
|
extraBuilds: Seq[URI],
|
||||||
|
converter: MappedFileConverter,
|
||||||
log: Logger
|
log: Logger
|
||||||
) {
|
) {
|
||||||
lazy val globalPluginClasspath: Def.Classpath =
|
lazy val globalPluginClasspath: Def.Classpath =
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ package internal
|
||||||
|
|
||||||
import sbt.Def.ScopedKey
|
import sbt.Def.ScopedKey
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
|
import sbt.ProjectExtra.showContextKey
|
||||||
import sbt.Scope.Global
|
import sbt.Scope.Global
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.internal.util.MainAppender._
|
import sbt.internal.util.MainAppender._
|
||||||
|
|
|
||||||
|
|
@ -25,23 +25,23 @@ object Output {
|
||||||
final val DefaultTail = "> "
|
final val DefaultTail = "> "
|
||||||
|
|
||||||
def last(
|
def last(
|
||||||
keys: Values[_],
|
keys: Values[Any],
|
||||||
streams: Streams,
|
streams: Streams,
|
||||||
printLines: Seq[String] => Unit,
|
printLines: Seq[String] => Unit,
|
||||||
sid: Option[String]
|
sid: Option[String]
|
||||||
)(implicit display: Show[ScopedKey[_]]): Unit =
|
)(using display: Show[ScopedKey[_]]): Unit =
|
||||||
printLines(flatLines(lastLines(keys, streams, sid))(idFun))
|
printLines(flatLines(lastLines(keys, streams, sid))(idFun))
|
||||||
|
|
||||||
def last(file: File, printLines: Seq[String] => Unit, tailDelim: String = DefaultTail): Unit =
|
def last(file: File, printLines: Seq[String] => Unit, tailDelim: String = DefaultTail): Unit =
|
||||||
printLines(tailLines(file, tailDelim))
|
printLines(tailLines(file, tailDelim))
|
||||||
|
|
||||||
def lastGrep(
|
def lastGrep(
|
||||||
keys: Values[_],
|
keys: Values[Any],
|
||||||
streams: Streams,
|
streams: Streams,
|
||||||
patternString: String,
|
patternString: String,
|
||||||
printLines: Seq[String] => Unit
|
printLines: Seq[String] => Unit
|
||||||
)(implicit display: Show[ScopedKey[_]]): Unit = {
|
)(using display: Show[ScopedKey[_]]): Unit = {
|
||||||
val pattern = Pattern compile patternString
|
val pattern = Pattern.compile(patternString)
|
||||||
val lines = flatLines(lastLines(keys, streams))(_ flatMap showMatches(pattern))
|
val lines = flatLines(lastLines(keys, streams))(_ flatMap showMatches(pattern))
|
||||||
printLines(lines)
|
printLines(lines)
|
||||||
}
|
}
|
||||||
|
|
@ -68,7 +68,7 @@ object Output {
|
||||||
}
|
}
|
||||||
|
|
||||||
def lastLines(
|
def lastLines(
|
||||||
keys: Values[_],
|
keys: Values[Any],
|
||||||
streams: Streams,
|
streams: Streams,
|
||||||
sid: Option[String] = None
|
sid: Option[String] = None
|
||||||
): Values[Seq[String]] = {
|
): Values[Seq[String]] = {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ object PluginDiscovery {
|
||||||
|
|
||||||
/** Discovers and loads the sbt-plugin-related top-level modules from the classpath and source analysis in `data` and using the provided class `loader`. */
|
/** Discovers and loads the sbt-plugin-related top-level modules from the classpath and source analysis in `data` and using the provided class `loader`. */
|
||||||
def discoverAll(data: PluginData, loader: ClassLoader): DetectedPlugins = {
|
def discoverAll(data: PluginData, loader: ClassLoader): DetectedPlugins = {
|
||||||
def discover[T](resource: String)(implicit classTag: reflect.ClassTag[T]) =
|
def discover[T](resource: String)(implicit manifest: Manifest[T]) =
|
||||||
binarySourceModules[T](data, loader, resource)
|
binarySourceModules[T](data, loader, resource)
|
||||||
import Paths._
|
import Paths._
|
||||||
// TODO - Fix this once we can autodetect AutoPlugins defined by sbt itself.
|
// TODO - Fix this once we can autodetect AutoPlugins defined by sbt itself.
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ package internal
|
||||||
import sbt.internal.util.{ AttributeKey, Dag, Relation, Util }
|
import sbt.internal.util.{ AttributeKey, Dag, Relation, Util }
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
|
|
||||||
|
import sbt.ProjectExtra.*
|
||||||
import Def.Setting
|
import Def.Setting
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import Plugins._
|
import Plugins._
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ package internal
|
||||||
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import sbt.internal.util.complete, complete.{ DefaultParsers, Parser }, DefaultParsers._
|
import sbt.internal.util.complete, complete.{ DefaultParsers, Parser }, DefaultParsers._
|
||||||
import sbt.compiler.Eval
|
import sbt.internal.Eval
|
||||||
import Keys.sessionSettings
|
import Keys.sessionSettings
|
||||||
import Project.updateCurrent
|
import sbt.ProjectExtra.{ extract, updateCurrent }
|
||||||
|
|
||||||
object ProjectNavigation {
|
object ProjectNavigation {
|
||||||
def command(s: State): Parser[() => State] =
|
def command(s: State): Parser[() => State] =
|
||||||
|
|
@ -21,12 +21,12 @@ object ProjectNavigation {
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ProjectNavigation(s: State) {
|
final class ProjectNavigation(s: State) {
|
||||||
val extracted: Extracted = Project extract s
|
val extracted: Extracted = Project.extract(s)
|
||||||
import extracted.{ currentRef, structure, session }
|
import extracted.{ currentRef, structure, session }
|
||||||
|
|
||||||
def setProject(nuri: URI, nid: String): State = {
|
def setProject(nuri: URI, nid: String): State = {
|
||||||
val neval = if (currentRef.build == nuri) session.currentEval else mkEval(nuri)
|
val neval = if (currentRef.build == nuri) session.currentEval else mkEval(nuri)
|
||||||
updateCurrent(s.put(sessionSettings, session.setCurrent(nuri, nid, neval)))
|
Project.updateCurrent(s.put(sessionSettings, session.setCurrent(nuri, nid, neval)))
|
||||||
}
|
}
|
||||||
|
|
||||||
def mkEval(nuri: URI): () => Eval = Load.lazyEval(structure.units(nuri).unit)
|
def mkEval(nuri: URI): () => Eval = Load.lazyEval(structure.units(nuri).unit)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import Keys._
|
||||||
import EvaluateConfigurations.{ evaluateConfiguration => evaluate }
|
import EvaluateConfigurations.{ evaluateConfiguration => evaluate }
|
||||||
import Configurations.Compile
|
import Configurations.Compile
|
||||||
import Scope.Global
|
import Scope.Global
|
||||||
|
import sbt.ProjectExtra.{ extract, setProject }
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
|
|
||||||
import sbt.io.{ Hash, IO }
|
import sbt.io.{ Hash, IO }
|
||||||
|
|
@ -46,10 +47,11 @@ object Script {
|
||||||
val (eval, structure) = Load.defaultLoad(state, base, state.log)
|
val (eval, structure) = Load.defaultLoad(state, base, state.log)
|
||||||
val session = Load.initialSession(structure, eval)
|
val session = Load.initialSession(structure, eval)
|
||||||
val extracted = Project.extract(session, structure)
|
val extracted = Project.extract(session, structure)
|
||||||
import extracted._
|
val vf = structure.converter.toVirtualFile(script.toPath())
|
||||||
|
import extracted.*
|
||||||
|
|
||||||
val embeddedSettings = blocks(script).flatMap { block =>
|
val embeddedSettings = blocks(script).flatMap { block =>
|
||||||
evaluate(eval(), script, block.lines, currentUnit.imports, block.offset + 1)(currentLoader)
|
evaluate(eval(), vf, block.lines, currentUnit.imports, block.offset + 1)(currentLoader)
|
||||||
}
|
}
|
||||||
val scriptAsSource = (Compile / sources) := script :: Nil
|
val scriptAsSource = (Compile / sources) := script :: Nil
|
||||||
val asScript = scalacOptions ++= Seq("-Xscript", script.getName.stripSuffix(".scala"))
|
val asScript = scalacOptions ++= Seq("-Xscript", script.getName.stripSuffix(".scala"))
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,11 @@ import sbt.internal.util.{ complete, LineRange, RangePosition, Types }
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
import Def.{ ScopedKey, Setting }
|
import Def.{ ScopedKey, Setting }
|
||||||
import Types.Endo
|
|
||||||
import compiler.Eval
|
|
||||||
|
|
||||||
import SessionSettings._
|
import SessionSettings._
|
||||||
|
import sbt.ProjectExtra.{ extract, getProject, session, structure }
|
||||||
import sbt.internal.parser.SbtRefactorings
|
import sbt.internal.parser.SbtRefactorings
|
||||||
|
|
||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -93,19 +91,24 @@ final case class SessionSettings(
|
||||||
private[this] def merge(map: SessionMap): Seq[Setting[_]] =
|
private[this] def merge(map: SessionMap): Seq[Setting[_]] =
|
||||||
map.values.toSeq.flatten[SessionSetting].map(_._1)
|
map.values.toSeq.flatten[SessionSetting].map(_._1)
|
||||||
|
|
||||||
private[this] def modify(map: SessionMap, onSeq: Endo[Seq[SessionSetting]]): SessionMap = {
|
private[this] def modify(
|
||||||
|
map: SessionMap,
|
||||||
|
onSeq: Seq[SessionSetting] => Seq[SessionSetting],
|
||||||
|
): SessionMap = {
|
||||||
val cur = current
|
val cur = current
|
||||||
map.updated(cur, onSeq(map.getOrElse(cur, Nil)))
|
map.updated(cur, onSeq(map.getOrElse(cur, Nil)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object SessionSettings {
|
object SessionSettings:
|
||||||
|
|
||||||
/** A session setting is simply a tuple of a Setting[_] and the strings which define it. */
|
/** A session setting is simply a tuple of a Setting[_] and the strings which define it. */
|
||||||
type SessionSetting = (Setting[_], Seq[String])
|
type SessionSetting = sbt.internal.parser.SbtRefactorings.SessionSetting
|
||||||
|
// (Setting[_], Seq[String])
|
||||||
|
|
||||||
type SessionMap = Map[ProjectRef, Seq[SessionSetting]]
|
type SessionMap = Map[ProjectRef, Seq[SessionSetting]]
|
||||||
type SbtConfigFile = (File, Seq[String])
|
type SbtConfigFile = sbt.internal.parser.SbtRefactorings.SbtConfigFile
|
||||||
|
// (File, Seq[String])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will re-evaluate all Setting[_]'s on this session against the current build state and
|
* This will re-evaluate all Setting[_]'s on this session against the current build state and
|
||||||
|
|
@ -133,14 +136,12 @@ object SessionSettings {
|
||||||
* @param f A function which takes the current SessionSettings and returns the new build state.
|
* @param f A function which takes the current SessionSettings and returns the new build state.
|
||||||
* @return The new build state
|
* @return The new build state
|
||||||
*/
|
*/
|
||||||
def withSettings(s: State)(f: SessionSettings => State): State = {
|
def withSettings(s: State)(f: SessionSettings => State): State =
|
||||||
val extracted = Project extract s
|
val extracted = Project.extract(s)
|
||||||
import extracted._
|
if (extracted.session.append.isEmpty) {
|
||||||
if (session.append.isEmpty) {
|
|
||||||
s.log.info("No session settings defined.")
|
s.log.info("No session settings defined.")
|
||||||
s
|
s
|
||||||
} else f(session)
|
} else f(extracted.session)
|
||||||
}
|
|
||||||
|
|
||||||
/** Adds `s` to a strings when needed. Maybe one day we'll care about non-english languages. */
|
/** Adds `s` to a strings when needed. Maybe one day we'll care about non-english languages. */
|
||||||
def pluralize(size: Int, of: String) = size.toString + (if (size == 1) of else (of + "s"))
|
def pluralize(size: Int, of: String) = size.toString + (if (size == 1) of else (of + "s"))
|
||||||
|
|
@ -356,4 +357,4 @@ save, save-all
|
||||||
case c: Clear => if (c.all) clearAllSettings(s) else clearSettings(s)
|
case c: Clear => if (c.all) clearAllSettings(s) else clearSettings(s)
|
||||||
case r: Remove => removeSettings(s, r.ranges)
|
case r: Remove => removeSettings(s, r.ranges)
|
||||||
}
|
}
|
||||||
}
|
end SessionSettings
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import sbt.internal.util.{ AttributeKey, complete, Relation, Settings, Types, Ut
|
||||||
import sbt.util.Show
|
import sbt.util.Show
|
||||||
import sbt.librarymanagement.Configuration
|
import sbt.librarymanagement.Configuration
|
||||||
|
|
||||||
import Project._
|
import ProjectExtra.{ relation }
|
||||||
import Def.{ ScopedKey, Setting }
|
import Def.{ ScopedKey, Setting }
|
||||||
import Scope.Global
|
import Scope.Global
|
||||||
import Types.idFun
|
import Types.idFun
|
||||||
|
|
@ -41,13 +41,13 @@ private[sbt] object SettingCompletions {
|
||||||
*/
|
*/
|
||||||
def setAll(extracted: Extracted, settings: Seq[Setting[_]]): SetResult = {
|
def setAll(extracted: Extracted, settings: Seq[Setting[_]]): SetResult = {
|
||||||
import extracted._
|
import extracted._
|
||||||
val r = relation(extracted.structure, true)
|
val r = Project.relation(extracted.structure, true)
|
||||||
val allDefs = Def
|
val allDefs = Def
|
||||||
.flattenLocals(
|
.flattenLocals(
|
||||||
Def.compiled(extracted.structure.settings, true)(
|
Def.compiled(extracted.structure.settings, true)(using
|
||||||
structure.delegates,
|
structure.delegates,
|
||||||
structure.scopeLocal,
|
structure.scopeLocal,
|
||||||
implicitly[Show[ScopedKey[_]]]
|
implicitly[Show[ScopedKey[_]]],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.keys
|
.keys
|
||||||
|
|
@ -81,10 +81,10 @@ private[sbt] object SettingCompletions {
|
||||||
val append =
|
val append =
|
||||||
Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, settings)
|
Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, settings)
|
||||||
val newSession = session.appendSettings(append map (a => (a, arg.split('\n').toList)))
|
val newSession = session.appendSettings(append map (a => (a, arg.split('\n').toList)))
|
||||||
val r = relation(newSession.mergeSettings, true)(
|
val r = Project.relation(newSession.mergeSettings, true)(using
|
||||||
structure.delegates,
|
structure.delegates,
|
||||||
structure.scopeLocal,
|
structure.scopeLocal,
|
||||||
implicitly
|
summon[Show[ScopedKey[_]]],
|
||||||
)
|
)
|
||||||
setResult(newSession, r, append)
|
setResult(newSession, r, append)
|
||||||
}
|
}
|
||||||
|
|
@ -12,16 +12,16 @@ import sbt.util.Show
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
import Def.{ ScopedKey, compiled, flattenLocals }
|
import Def.{ ScopedKey, compiled, flattenLocals }
|
||||||
|
|
||||||
import Predef.{ any2stringadd => _, _ }
|
import Predef.{ any2stringadd => _, _ }
|
||||||
|
import sbt.ProjectExtra.scopedKeyData
|
||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
|
|
||||||
object SettingGraph {
|
object SettingGraph {
|
||||||
def apply(structure: BuildStructure, basedir: File, scoped: ScopedKey[_], generation: Int)(
|
def apply(structure: BuildStructure, basedir: File, scoped: ScopedKey[_], generation: Int)(using
|
||||||
implicit display: Show[ScopedKey[_]]
|
display: Show[ScopedKey[_]]
|
||||||
): SettingGraph = {
|
): SettingGraph = {
|
||||||
val cMap = flattenLocals(
|
val cMap = flattenLocals(
|
||||||
compiled(structure.settings, false)(structure.delegates, structure.scopeLocal, display)
|
compiled(structure.settings, false)(using structure.delegates, structure.scopeLocal, display)
|
||||||
)
|
)
|
||||||
def loop(scoped: ScopedKey[_], generation: Int): SettingGraph = {
|
def loop(scoped: ScopedKey[_], generation: Int): SettingGraph = {
|
||||||
val key = scoped.key
|
val key = scoped.key
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ private[sbt] class TaskProgress(
|
||||||
}
|
}
|
||||||
Util.ignoreResult(pending.add(executor.submit(runnable)))
|
Util.ignoreResult(pending.add(executor.submit(runnable)))
|
||||||
}
|
}
|
||||||
override def beforeWork(task: Task[_]): Unit =
|
override def beforeWork(task: Task[Any]): Unit =
|
||||||
if (!closed.get) {
|
if (!closed.get) {
|
||||||
super.beforeWork(task)
|
super.beforeWork(task)
|
||||||
reportLoop.get match {
|
reportLoop.get match {
|
||||||
|
|
@ -108,7 +108,7 @@ private[sbt] class TaskProgress(
|
||||||
logger.debug(s"called beforeWork for ${taskName(task)} after task progress was closed")
|
logger.debug(s"called beforeWork for ${taskName(task)} after task progress was closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
override def afterReady(task: Task[_]): Unit =
|
override def afterReady(task: Task[Any]): Unit =
|
||||||
if (!closed.get) {
|
if (!closed.get) {
|
||||||
try {
|
try {
|
||||||
Util.ignoreResult(executor.submit((() => {
|
Util.ignoreResult(executor.submit((() => {
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ private[sbt] final class TaskTimings(reportOnShutdown: Boolean, logger: Logger)
|
||||||
start = System.nanoTime
|
start = System.nanoTime
|
||||||
}
|
}
|
||||||
|
|
||||||
override def afterReady(task: Task[_]): Unit = ()
|
override def afterReady(task: Task[Any]): Unit = ()
|
||||||
override def afterCompleted[T](task: Task[T], result: Result[T]): Unit = ()
|
override def afterCompleted[T](task: Task[T], result: Result[T]): Unit = ()
|
||||||
override def afterAllCompleted(results: RMap[Task, Result]): Unit =
|
override def afterAllCompleted(results: RMap[Task, Result]): Unit =
|
||||||
if (!reportOnShutdown) {
|
if (!reportOnShutdown) {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ private[sbt] final class TaskTraceEvent
|
||||||
private[this] val console = ConsoleOut.systemOut
|
private[this] val console = ConsoleOut.systemOut
|
||||||
|
|
||||||
override def initial(): Unit = ()
|
override def initial(): Unit = ()
|
||||||
override def afterReady(task: Task[_]): Unit = ()
|
override def afterReady(task: Task[Any]): Unit = ()
|
||||||
override def afterCompleted[T](task: Task[T], result: Result[T]): Unit = ()
|
override def afterCompleted[T](task: Task[T], result: Result[T]): Unit = ()
|
||||||
override def afterAllCompleted(results: RMap[Task, Result]): Unit = ()
|
override def afterAllCompleted(results: RMap[Task, Result]): Unit = ()
|
||||||
override def stop(): Unit = ()
|
override def stop(): Unit = ()
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@
|
||||||
* Licensed under Apache License 2.0 (see LICENSE)
|
* Licensed under Apache License 2.0 (see LICENSE)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sbt.internal
|
package sbt
|
||||||
|
package internal
|
||||||
|
|
||||||
import sbt.Def._
|
import sbt.Def._
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
import sbt.Project.richInitializeTask
|
// import sbt.Project.richInitializeTask
|
||||||
import sbt._
|
import sbt.ProjectExtra.{ delegates, extract, richInitializeTask }
|
||||||
import sbt.internal.io.Source
|
import sbt.internal.io.Source
|
||||||
import sbt.internal.nio.Globs
|
import sbt.internal.nio.Globs
|
||||||
import sbt.internal.util.AttributeMap
|
import sbt.internal.util.AttributeMap
|
||||||
|
|
@ -59,22 +60,26 @@ private[sbt] object WatchTransitiveDependencies {
|
||||||
scopedKey: ScopedKey[_],
|
scopedKey: ScopedKey[_],
|
||||||
extracted: Extracted,
|
extracted: Extracted,
|
||||||
compiledMap: CompiledMap
|
compiledMap: CompiledMap
|
||||||
): Def.Initialize[Task[Arguments]] = Def.task {
|
): Def.Initialize[Task[Arguments]] =
|
||||||
val log = (streamsManager map { mgr =>
|
import sbt.TupleSyntax.*
|
||||||
val stream = mgr(scopedKey)
|
(
|
||||||
stream.open()
|
(streamsManager map { mgr =>
|
||||||
stream
|
val stream = mgr(scopedKey)
|
||||||
}).value.log
|
stream.open()
|
||||||
val configs = (internalDependencyConfigurations in scopedKey.scope).value
|
stream
|
||||||
new Arguments(
|
}).toTaskable,
|
||||||
scopedKey,
|
(internalDependencyConfigurations in scopedKey.scope).toTaskable,
|
||||||
extracted,
|
state,
|
||||||
compiledMap,
|
).mapN { case (log, configs, st) =>
|
||||||
log,
|
new Arguments(
|
||||||
configs,
|
scopedKey,
|
||||||
state.value
|
extracted,
|
||||||
)
|
compiledMap,
|
||||||
}
|
log.log,
|
||||||
|
configs,
|
||||||
|
st
|
||||||
|
)
|
||||||
|
}
|
||||||
private val ShowTransitive = "(?:show)?(?:[ ]*)(.*)/(?:[ ]*)transitive(?:Inputs|Globs|Triggers)".r
|
private val ShowTransitive = "(?:show)?(?:[ ]*)(.*)/(?:[ ]*)transitive(?:Inputs|Globs|Triggers)".r
|
||||||
private def arguments: Def.Initialize[Task[Arguments]] =
|
private def arguments: Def.Initialize[Task[Arguments]] =
|
||||||
Def
|
Def
|
||||||
|
|
@ -149,8 +154,8 @@ private[sbt] object WatchTransitiveDependencies {
|
||||||
case Some(k) =>
|
case Some(k) =>
|
||||||
k.work match {
|
k.work match {
|
||||||
// Avoid extracted.runTask if possible.
|
// Avoid extracted.runTask if possible.
|
||||||
case Pure(w, _) => Some(Right(w().map(_.toGlob)))
|
case Action.Pure(w, _) => Some(Right(w().map(_.toGlob)))
|
||||||
case _ => Some(Left(s))
|
case _ => Some(Left(s))
|
||||||
}
|
}
|
||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,21 +13,26 @@ import java.io.File
|
||||||
import sjsonnew._
|
import sjsonnew._
|
||||||
import scala.collection.mutable.{ HashMap, MultiMap, Set }
|
import scala.collection.mutable.{ HashMap, MultiMap, Set }
|
||||||
|
|
||||||
private[sbt] case class GraphModuleId(organization: String, name: String, version: String) {
|
private[sbt] case class GraphModuleId(
|
||||||
|
organization: String,
|
||||||
|
name: String,
|
||||||
|
version: String,
|
||||||
|
) {
|
||||||
def idString: String = organization + ":" + name + ":" + version
|
def idString: String = organization + ":" + name + ":" + version
|
||||||
}
|
}
|
||||||
|
|
||||||
private[sbt] object GraphModuleId {
|
private[sbt] object GraphModuleId:
|
||||||
import sjsonnew.BasicJsonProtocol.StringJsonFormat
|
import sjsonnew.BasicJsonProtocol.StringJsonFormat
|
||||||
implicit val graphModuleIdIso = LList.iso[GraphModuleId, String :*: String :*: String :*: LNil](
|
given graphModuleIdIso: IsoLList.Aux[GraphModuleId, String :*: String :*: String :*: LNil] =
|
||||||
{ (m: GraphModuleId) =>
|
LList.iso[GraphModuleId, String :*: String :*: String :*: LNil](
|
||||||
("organization", m.organization) :*: ("name", m.name) :*: ("version", m.version) :*: LNil
|
{ (m: GraphModuleId) =>
|
||||||
},
|
("organization", m.organization) :*: ("name", m.name) :*: ("version", m.version) :*: LNil
|
||||||
{ case (_, organization) :*: (_, name) :*: (_, version) :*: LNil =>
|
},
|
||||||
GraphModuleId(organization, name, version)
|
{ case (_, organization) :*: (_, name) :*: (_, version) :*: LNil =>
|
||||||
}
|
GraphModuleId(organization, name, version)
|
||||||
)
|
}
|
||||||
}
|
)
|
||||||
|
end GraphModuleId
|
||||||
|
|
||||||
private[sbt] case class Module(
|
private[sbt] case class Module(
|
||||||
id: GraphModuleId,
|
id: GraphModuleId,
|
||||||
|
|
@ -36,15 +41,21 @@ private[sbt] case class Module(
|
||||||
evictedByVersion: Option[String] = None,
|
evictedByVersion: Option[String] = None,
|
||||||
jarFile: Option[File] = None,
|
jarFile: Option[File] = None,
|
||||||
error: Option[String] = None
|
error: Option[String] = None
|
||||||
) {
|
):
|
||||||
def hadError: Boolean = error.isDefined
|
def hadError: Boolean = error.isDefined
|
||||||
def isUsed: Boolean = !isEvicted
|
def isUsed: Boolean = !isEvicted
|
||||||
def isEvicted: Boolean = evictedByVersion.isDefined
|
def isEvicted: Boolean = evictedByVersion.isDefined
|
||||||
}
|
end Module
|
||||||
|
|
||||||
private[sbt] object Module {
|
private[sbt] object Module:
|
||||||
import sjsonnew.BasicJsonProtocol._
|
import sjsonnew.BasicJsonProtocol.*
|
||||||
implicit val moduleIso = LList.iso[
|
given moduleIso: IsoLList.Aux[
|
||||||
|
Module,
|
||||||
|
GraphModuleId :*: Option[String] :*: String :*:
|
||||||
|
Option[
|
||||||
|
String
|
||||||
|
] :*: Option[File] :*: Option[String] :*: LNil
|
||||||
|
] = LList.iso[
|
||||||
Module,
|
Module,
|
||||||
GraphModuleId :*: Option[String] :*: String :*:
|
GraphModuleId :*: Option[String] :*: String :*:
|
||||||
Option[
|
Option[
|
||||||
|
|
@ -52,24 +63,24 @@ private[sbt] object Module {
|
||||||
] :*: Option[File] :*: Option[String] :*: LNil
|
] :*: Option[File] :*: Option[String] :*: LNil
|
||||||
](
|
](
|
||||||
{ (m: Module) =>
|
{ (m: Module) =>
|
||||||
("id", m.id) :*: ("license", m.license) :*: ("extraInfo", m.extraInfo) :*:
|
("id", m.id) :*:
|
||||||
("evictedByVersion", m.evictedByVersion) :*: (
|
("license", m.license) :*:
|
||||||
"jarFile",
|
("extraInfo", m.extraInfo) :*:
|
||||||
m.jarFile
|
("evictedByVersion", m.evictedByVersion) :*:
|
||||||
) :*: ("error", m.error) :*: LNil
|
("jarFile", m.jarFile) :*:
|
||||||
|
("error", m.error) :*: LNil
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case (_, id) :*: (_, license) :*: (_, extraInfo) :*: (_, evictedByVersion) :*: (
|
case (_, id) :*:
|
||||||
_,
|
(_, license) :*:
|
||||||
jarFile
|
(_, extraInfo) :*:
|
||||||
) :*: (
|
(_, evictedByVersion) :*:
|
||||||
_,
|
(_, jarFile) :*:
|
||||||
error
|
(_, error) :*: LNil =>
|
||||||
) :*: LNil =>
|
|
||||||
Module(id, license, extraInfo, evictedByVersion, jarFile, error)
|
Module(id, license, extraInfo, evictedByVersion, jarFile, error)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
end Module
|
||||||
|
|
||||||
private[sbt] case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) {
|
private[sbt] case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) {
|
||||||
lazy val modules: Map[GraphModuleId, Module] =
|
lazy val modules: Map[GraphModuleId, Module] =
|
||||||
|
|
@ -98,16 +109,17 @@ private[sbt] case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) {
|
||||||
nodes.filter(n => !edges.exists(_._2 == n.id)).sortBy(_.id.idString)
|
nodes.filter(n => !edges.exists(_._2 == n.id)).sortBy(_.id.idString)
|
||||||
}
|
}
|
||||||
|
|
||||||
private[sbt] object ModuleGraph {
|
private[sbt] object ModuleGraph:
|
||||||
val empty = ModuleGraph(Seq.empty, Seq.empty)
|
val empty = ModuleGraph(Seq.empty, Seq.empty)
|
||||||
|
|
||||||
import BasicJsonProtocol._
|
import BasicJsonProtocol._
|
||||||
implicit val moduleGraphIso = LList.iso[ModuleGraph, Vector[Module] :*: Vector[Edge] :*: LNil](
|
given moduleGraphIso: IsoLList.Aux[ModuleGraph, Vector[Module] :*: Vector[Edge] :*: LNil] =
|
||||||
{ (g: ModuleGraph) =>
|
LList.iso[ModuleGraph, Vector[Module] :*: Vector[Edge] :*: LNil](
|
||||||
("nodes", g.nodes.toVector) :*: ("edges", g.edges.toVector) :*: LNil
|
{ (g: ModuleGraph) =>
|
||||||
},
|
("nodes", g.nodes.toVector) :*: ("edges", g.edges.toVector) :*: LNil
|
||||||
{ case (_, nodes: Vector[Module]) :*: (_, edges: Vector[Edge]) :*: LNil =>
|
},
|
||||||
ModuleGraph(nodes, edges)
|
{ case (_, nodes: Vector[Module]) :*: (_, edges: Vector[Edge]) :*: LNil =>
|
||||||
}
|
ModuleGraph(nodes, edges)
|
||||||
)
|
}
|
||||||
}
|
)
|
||||||
|
end ModuleGraph
|
||||||
|
|
@ -22,6 +22,7 @@ import sbt.Keys.{
|
||||||
publishConfiguration,
|
publishConfiguration,
|
||||||
useCoursier
|
useCoursier
|
||||||
}
|
}
|
||||||
|
import sbt.ProjectExtra.richInitializeTask
|
||||||
import sbt.librarymanagement.PublishConfiguration
|
import sbt.librarymanagement.PublishConfiguration
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
import scala.xml.{ Node, PrefixedAttribute }
|
import scala.xml.{ Node, PrefixedAttribute }
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,11 @@
|
||||||
|
|
||||||
package sbt.internal.server
|
package sbt.internal.server
|
||||||
|
|
||||||
|
import dotty.tools.dotc.core.Contexts.Context
|
||||||
|
import dotty.tools.dotc.reporting.{ Diagnostic => ScalaDiagnostic }
|
||||||
|
import dotty.tools.dotc.reporting.Reporter
|
||||||
import sbt.StandardMain.exchange
|
import sbt.StandardMain.exchange
|
||||||
import sbt.compiler.ForwardingReporter
|
import sbt.internal.ForwardingReporter
|
||||||
import sbt.internal.bsp
|
import sbt.internal.bsp
|
||||||
import sbt.internal.bsp.{
|
import sbt.internal.bsp.{
|
||||||
BuildTargetIdentifier,
|
BuildTargetIdentifier,
|
||||||
|
|
@ -21,16 +24,14 @@ import sbt.internal.bsp.{
|
||||||
|
|
||||||
import java.nio.file.{ Files, Path, Paths }
|
import java.nio.file.{ Files, Path, Paths }
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.reflect.internal.Reporter
|
|
||||||
import scala.reflect.internal.util.{ DefinedPosition, Position }
|
|
||||||
import scala.tools.nsc.reporters.FilteringReporter
|
|
||||||
import sbt.internal.bsp.codec.JsonProtocol._
|
import sbt.internal.bsp.codec.JsonProtocol._
|
||||||
|
|
||||||
class BuildServerEvalReporter(buildTarget: BuildTargetIdentifier, delegate: FilteringReporter)
|
class BuildServerEvalReporter(buildTarget: BuildTargetIdentifier, delegate: Reporter)
|
||||||
extends ForwardingReporter(delegate) {
|
extends ForwardingReporter(delegate):
|
||||||
private val problemsByFile = mutable.Map[Path, Vector[Diagnostic]]()
|
private val problemsByFile = mutable.Map[Path, Vector[Diagnostic]]()
|
||||||
|
|
||||||
override def doReport(pos: Position, msg: String, severity: Severity): Unit = {
|
override def doReport(dia: ScalaDiagnostic)(using Context): Unit = {
|
||||||
|
/*
|
||||||
for {
|
for {
|
||||||
filePath <- if (pos.source.file.exists) Some(Paths.get(pos.source.file.path)) else None
|
filePath <- if (pos.source.file.exists) Some(Paths.get(pos.source.file.path)) else None
|
||||||
range <- convertToRange(pos)
|
range <- convertToRange(pos)
|
||||||
|
|
@ -47,10 +48,12 @@ class BuildServerEvalReporter(buildTarget: BuildTargetIdentifier, delegate: Filt
|
||||||
)
|
)
|
||||||
exchange.notifyEvent("build/publishDiagnostics", params)
|
exchange.notifyEvent("build/publishDiagnostics", params)
|
||||||
}
|
}
|
||||||
super.doReport(pos, msg, severity)
|
*/
|
||||||
|
super.doReport(dia)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def finalReport(sourceName: String): Unit = {
|
/*
|
||||||
|
def finalReport(sourceName: String): Unit = {
|
||||||
val filePath = Paths.get(sourceName)
|
val filePath = Paths.get(sourceName)
|
||||||
if (Files.exists(filePath)) {
|
if (Files.exists(filePath)) {
|
||||||
val diagnostics = problemsByFile.getOrElse(filePath, Vector())
|
val diagnostics = problemsByFile.getOrElse(filePath, Vector())
|
||||||
|
|
@ -90,4 +93,5 @@ class BuildServerEvalReporter(buildTarget: BuildTargetIdentifier, delegate: Filt
|
||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
|
end BuildServerEvalReporter
|
||||||
|
|
@ -13,8 +13,10 @@ import java.net.URI
|
||||||
import sbt.BuildPaths.{ configurationSources, projectStandard }
|
import sbt.BuildPaths.{ configurationSources, projectStandard }
|
||||||
import sbt.BuildSyntax._
|
import sbt.BuildSyntax._
|
||||||
import sbt.Def._
|
import sbt.Def._
|
||||||
|
import sbt.Def.{ parsed }
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
import sbt.Project._
|
import sbt.Project._
|
||||||
|
import sbt.ProjectExtra.richInitializeTask
|
||||||
import sbt.ScopeFilter.Make._
|
import sbt.ScopeFilter.Make._
|
||||||
import sbt.Scoped.richTaskSeq
|
import sbt.Scoped.richTaskSeq
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
|
|
@ -61,6 +63,15 @@ object BuildServerProtocol {
|
||||||
|
|
||||||
private val bspReload = "bspReload"
|
private val bspReload = "bspReload"
|
||||||
|
|
||||||
|
private lazy val targetIdentifierParser: Parser[Seq[BuildTargetIdentifier]] =
|
||||||
|
Def
|
||||||
|
.spaceDelimited()
|
||||||
|
.map { xs =>
|
||||||
|
xs.map { uri =>
|
||||||
|
BuildTargetIdentifier(URI.create(uri))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lazy val commands: Seq[Command] = Seq(
|
lazy val commands: Seq[Command] = Seq(
|
||||||
Command.single(bspReload) { (state, reqId) =>
|
Command.single(bspReload) { (state, reqId) =>
|
||||||
try {
|
try {
|
||||||
|
|
@ -114,137 +125,177 @@ object BuildServerProtocol {
|
||||||
})
|
})
|
||||||
.value,
|
.value,
|
||||||
// https://github.com/build-server-protocol/build-server-protocol/blob/master/docs/specification.md#build-target-sources-request
|
// https://github.com/build-server-protocol/build-server-protocol/blob/master/docs/specification.md#build-target-sources-request
|
||||||
bspBuildTargetSources := bspInputTask { (state, _, workspace, filter) =>
|
bspBuildTargetSources := (Def
|
||||||
// run the worker task concurrently
|
.input((s: State) => targetIdentifierParser)
|
||||||
Def.task {
|
.flatMapTask { targets =>
|
||||||
val items = bspBuildTargetSourcesItem.result.all(filter).value
|
val s = state.value
|
||||||
val buildItems = workspace.builds.map { case (id, loadedBuildUnit) =>
|
// val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
|
||||||
val base = loadedBuildUnit.localBase
|
val workspace = bspFullWorkspace.value.filter(targets)
|
||||||
val sbtFiles = configurationSources(base)
|
val filter = ScopeFilter.in(workspace.scopes.values.toList)
|
||||||
val pluginData = loadedBuildUnit.unit.plugins.pluginData
|
// run the worker task concurrently
|
||||||
val dirs = pluginData.unmanagedSourceDirectories
|
Def.task {
|
||||||
val sourceFiles = getStandaloneSourceFiles(pluginData.unmanagedSources, dirs)
|
val items = bspBuildTargetSourcesItem.result.all(filter).value
|
||||||
val managedDirs = pluginData.managedSourceDirectories
|
val buildItems = workspace.builds.map { case (id, loadedBuildUnit) =>
|
||||||
val managedSourceFiles =
|
val base = loadedBuildUnit.localBase
|
||||||
getStandaloneSourceFiles(pluginData.managedSources, managedDirs)
|
val sbtFiles = configurationSources(base)
|
||||||
val items =
|
val pluginData = loadedBuildUnit.unit.plugins.pluginData
|
||||||
dirs.map(toSourceItem(SourceItemKind.Directory, generated = false)) ++
|
val dirs = pluginData.unmanagedSourceDirectories
|
||||||
sourceFiles.map(toSourceItem(SourceItemKind.File, generated = false)) ++
|
val sourceFiles = getStandaloneSourceFiles(pluginData.unmanagedSources, dirs)
|
||||||
managedDirs.map(toSourceItem(SourceItemKind.Directory, generated = true)) ++
|
val managedDirs = pluginData.managedSourceDirectories
|
||||||
managedSourceFiles.map(toSourceItem(SourceItemKind.File, generated = true)) ++
|
val managedSourceFiles =
|
||||||
sbtFiles.map(toSourceItem(SourceItemKind.File, generated = false))
|
getStandaloneSourceFiles(pluginData.managedSources, managedDirs)
|
||||||
Value(SourcesItem(id, items.toVector))
|
val items =
|
||||||
|
dirs.map(toSourceItem(SourceItemKind.Directory, generated = false)) ++
|
||||||
|
sourceFiles.map(toSourceItem(SourceItemKind.File, generated = false)) ++
|
||||||
|
managedDirs.map(toSourceItem(SourceItemKind.Directory, generated = true)) ++
|
||||||
|
managedSourceFiles.map(toSourceItem(SourceItemKind.File, generated = true)) ++
|
||||||
|
sbtFiles.map(toSourceItem(SourceItemKind.File, generated = false))
|
||||||
|
Result.Value(SourcesItem(id, items.toVector))
|
||||||
|
}
|
||||||
|
val successfulItems = anyOrThrow(items ++ buildItems)
|
||||||
|
val result = SourcesResult(successfulItems.toVector)
|
||||||
|
s.respondEvent(result)
|
||||||
}
|
}
|
||||||
val successfulItems = anyOrThrow(items ++ buildItems)
|
})
|
||||||
val result = SourcesResult(successfulItems.toVector)
|
.value,
|
||||||
state.respondEvent(result)
|
|
||||||
}
|
|
||||||
}.evaluated,
|
|
||||||
bspBuildTargetSources / aggregate := false,
|
bspBuildTargetSources / aggregate := false,
|
||||||
bspBuildTargetResources := bspInputTask { (state, _, workspace, filter) =>
|
bspBuildTargetResources := (Def
|
||||||
workspace.warnIfBuildsNonEmpty(Method.Resources, state.log)
|
.input((s: State) => targetIdentifierParser)
|
||||||
// run the worker task concurrently
|
.flatMapTask { targets =>
|
||||||
Def.task {
|
val s = state.value
|
||||||
val items = bspBuildTargetResourcesItem.result.all(filter).value
|
val workspace = bspFullWorkspace.value.filter(targets)
|
||||||
val successfulItems = anyOrThrow(items)
|
workspace.warnIfBuildsNonEmpty(Method.Resources, s.log)
|
||||||
val result = ResourcesResult(successfulItems.toVector)
|
val filter = ScopeFilter.in(workspace.scopes.values.toList)
|
||||||
state.respondEvent(result)
|
// run the worker task concurrently
|
||||||
}
|
Def.task {
|
||||||
}.evaluated,
|
val items = bspBuildTargetResourcesItem.result.all(filter).value
|
||||||
bspBuildTargetResources / aggregate := false,
|
val successfulItems = anyOrThrow(items)
|
||||||
bspBuildTargetDependencySources := bspInputTask { (state, _, workspace, filter) =>
|
val result = ResourcesResult(successfulItems.toVector)
|
||||||
// run the worker task concurrently
|
s.respondEvent(result)
|
||||||
Def.task {
|
|
||||||
import sbt.internal.bsp.codec.JsonProtocol._
|
|
||||||
val items = bspBuildTargetDependencySourcesItem.result.all(filter).value
|
|
||||||
val successfulItems = anyOrThrow(items)
|
|
||||||
val result = DependencySourcesResult(successfulItems.toVector)
|
|
||||||
state.respondEvent(result)
|
|
||||||
}
|
|
||||||
}.evaluated,
|
|
||||||
bspBuildTargetDependencySources / aggregate := false,
|
|
||||||
bspBuildTargetOutputPaths := bspInputTask { (state, _, workspace, filter) =>
|
|
||||||
Def.task {
|
|
||||||
import sbt.internal.bsp.codec.JsonProtocol._
|
|
||||||
val items = bspBuildTargetOutputPathsItem.result.all(filter).value
|
|
||||||
val successfulItems = anyOrThrow(items)
|
|
||||||
val result = OutputPathsResult(successfulItems.toVector)
|
|
||||||
state.respondEvent(result)
|
|
||||||
}
|
|
||||||
}.evaluated,
|
|
||||||
bspBuildTargetOutputPaths / aggregate := false,
|
|
||||||
bspBuildTargetCompile := bspInputTask { (state, _, workspace, filter) =>
|
|
||||||
workspace.warnIfBuildsNonEmpty(Method.Compile, state.log)
|
|
||||||
Def.task {
|
|
||||||
val statusCodes = Keys.bspBuildTargetCompileItem.result.all(filter).value
|
|
||||||
val aggregatedStatusCode = allOrThrow(statusCodes) match {
|
|
||||||
case Seq() => StatusCode.Success
|
|
||||||
case codes => codes.max
|
|
||||||
}
|
}
|
||||||
state.respondEvent(BspCompileResult(None, aggregatedStatusCode))
|
})
|
||||||
}
|
.value,
|
||||||
}.evaluated,
|
bspBuildTargetResources / aggregate := false,
|
||||||
|
bspBuildTargetDependencySources := (Def
|
||||||
|
.input((s: State) => targetIdentifierParser)
|
||||||
|
.flatMapTask { targets =>
|
||||||
|
val s = state.value
|
||||||
|
val workspace = bspFullWorkspace.value.filter(targets)
|
||||||
|
val filter = ScopeFilter.in(workspace.scopes.values.toList)
|
||||||
|
// run the worker task concurrently
|
||||||
|
Def.task {
|
||||||
|
import sbt.internal.bsp.codec.JsonProtocol._
|
||||||
|
val items = bspBuildTargetDependencySourcesItem.result.all(filter).value
|
||||||
|
val successfulItems = anyOrThrow(items)
|
||||||
|
val result = DependencySourcesResult(successfulItems.toVector)
|
||||||
|
s.respondEvent(result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.value,
|
||||||
|
bspBuildTargetDependencySources / aggregate := false,
|
||||||
|
bspBuildTargetCompile := (Def
|
||||||
|
.input((s: State) => targetIdentifierParser)
|
||||||
|
.flatMapTask { targets =>
|
||||||
|
val s: State = state.value
|
||||||
|
val workspace = bspFullWorkspace.value.filter(targets)
|
||||||
|
workspace.warnIfBuildsNonEmpty(Method.Compile, s.log)
|
||||||
|
val filter = ScopeFilter.in(workspace.scopes.values.toList)
|
||||||
|
Def.task {
|
||||||
|
val statusCodes = Keys.bspBuildTargetCompileItem.result.all(filter).value
|
||||||
|
val aggregatedStatusCode = allOrThrow(statusCodes) match {
|
||||||
|
case Seq() => StatusCode.Success
|
||||||
|
case codes => codes.max
|
||||||
|
}
|
||||||
|
s.respondEvent(BspCompileResult(None, aggregatedStatusCode))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.value,
|
||||||
bspBuildTargetCompile / aggregate := false,
|
bspBuildTargetCompile / aggregate := false,
|
||||||
bspBuildTargetTest := bspTestTask.evaluated,
|
bspBuildTargetTest := bspTestTask.evaluated,
|
||||||
bspBuildTargetTest / aggregate := false,
|
bspBuildTargetTest / aggregate := false,
|
||||||
bspBuildTargetCleanCache := bspInputTask { (state, targets, workspace, filter) =>
|
bspBuildTargetCleanCache := (Def
|
||||||
workspace.warnIfBuildsNonEmpty(Method.CleanCache, state.log)
|
.input((s: State) => targetIdentifierParser)
|
||||||
Def.task {
|
.flatMapTask { targets =>
|
||||||
val results = Keys.clean.result.all(filter).value
|
val s: State = state.value
|
||||||
val successes = anyOrThrow(results).size
|
val workspace = bspFullWorkspace.value.filter(targets)
|
||||||
|
workspace.warnIfBuildsNonEmpty(Method.CleanCache, s.log)
|
||||||
|
val filter = ScopeFilter.in(workspace.scopes.values.toList)
|
||||||
|
Def.task {
|
||||||
|
val results = Keys.clean.result.all(filter).value
|
||||||
|
val successes = anyOrThrow(results).size
|
||||||
|
|
||||||
// When asking to Rebuild Project, IntelliJ sends the root build as an additional target, however it is
|
// When asking to Rebuild Project, IntelliJ sends the root build as an additional target, however it is
|
||||||
// not returned as part of the results. In this case, there's 1 build entry in the workspace, and we're
|
// not returned as part of the results. In this case, there's 1 build entry in the workspace, and we're
|
||||||
// checking that the executed results plus this entry is equal to the total number of targets.
|
// checking that the executed results plus this entry is equal to the total number of targets.
|
||||||
// When rebuilding a single module, the root build isn't sent, just the requested targets.
|
// When rebuilding a single module, the root build isn't sent, just the requested targets.
|
||||||
val cleaned = successes + workspace.builds.size == targets.size
|
val cleaned = successes + workspace.builds.size == targets.size
|
||||||
state.respondEvent(CleanCacheResult(None, cleaned))
|
s.respondEvent(CleanCacheResult(None, cleaned))
|
||||||
}
|
|
||||||
}.evaluated,
|
|
||||||
bspBuildTargetCleanCache / aggregate := false,
|
|
||||||
bspBuildTargetScalacOptions := bspInputTask { (state, _, workspace, filter) =>
|
|
||||||
val builds = workspace.builds
|
|
||||||
Def.task {
|
|
||||||
val items = bspBuildTargetScalacOptionsItem.result.all(filter).value
|
|
||||||
val appProvider = appConfiguration.value.provider()
|
|
||||||
val sbtJars = appProvider.mainClasspath()
|
|
||||||
val buildItems = builds.map { build =>
|
|
||||||
val plugins: LoadedPlugins = build._2.unit.plugins
|
|
||||||
val scalacOptions = plugins.pluginData.scalacOptions
|
|
||||||
val pluginClassPath = plugins.classpath
|
|
||||||
val classpath = (pluginClassPath ++ sbtJars).map(_.toURI).toVector
|
|
||||||
val item = ScalacOptionsItem(
|
|
||||||
build._1,
|
|
||||||
scalacOptions.toVector,
|
|
||||||
classpath,
|
|
||||||
new File(build._2.localBase, "project/target").toURI
|
|
||||||
)
|
|
||||||
Value(item)
|
|
||||||
}
|
}
|
||||||
val successfulItems = anyOrThrow(items ++ buildItems)
|
})
|
||||||
val result = ScalacOptionsResult(successfulItems.toVector)
|
.value,
|
||||||
state.respondEvent(result)
|
bspBuildTargetCleanCache / aggregate := false,
|
||||||
}
|
bspBuildTargetScalacOptions := (Def
|
||||||
}.evaluated,
|
.input((s: State) => targetIdentifierParser)
|
||||||
|
.flatMapTask { targets =>
|
||||||
|
val s = state.value
|
||||||
|
val workspace = bspFullWorkspace.value.filter(targets)
|
||||||
|
val builds = workspace.builds
|
||||||
|
|
||||||
|
val filter = ScopeFilter.in(workspace.scopes.values.toList)
|
||||||
|
Def.task {
|
||||||
|
val items = bspBuildTargetScalacOptionsItem.result.all(filter).value
|
||||||
|
val appProvider = appConfiguration.value.provider()
|
||||||
|
val sbtJars = appProvider.mainClasspath()
|
||||||
|
val buildItems = builds.map { build =>
|
||||||
|
val plugins: LoadedPlugins = build._2.unit.plugins
|
||||||
|
val scalacOptions = plugins.pluginData.scalacOptions
|
||||||
|
val pluginClassPath = plugins.classpath
|
||||||
|
val classpath = (pluginClassPath ++ sbtJars).map(_.toURI).toVector
|
||||||
|
val item = ScalacOptionsItem(
|
||||||
|
build._1,
|
||||||
|
scalacOptions.toVector,
|
||||||
|
classpath,
|
||||||
|
new File(build._2.localBase, "project/target").toURI
|
||||||
|
)
|
||||||
|
Result.Value(item)
|
||||||
|
}
|
||||||
|
val successfulItems = anyOrThrow(items ++ buildItems)
|
||||||
|
val result = ScalacOptionsResult(successfulItems.toVector)
|
||||||
|
s.respondEvent(result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.value,
|
||||||
bspBuildTargetScalacOptions / aggregate := false,
|
bspBuildTargetScalacOptions / aggregate := false,
|
||||||
bspScalaTestClasses := bspInputTask { (state, _, workspace, filter) =>
|
bspScalaTestClasses := (Def
|
||||||
workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, state.log)
|
.input((s: State) => targetIdentifierParser)
|
||||||
Def.task {
|
.flatMapTask { targets =>
|
||||||
val items = bspScalaTestClassesItem.result.all(filter).value
|
val s = state.value
|
||||||
val successfulItems = anyOrThrow(items).flatten.toVector
|
val workspace = bspFullWorkspace.value.filter(targets)
|
||||||
val result = ScalaTestClassesResult(successfulItems.toVector, None)
|
workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, s.log)
|
||||||
state.respondEvent(result)
|
val filter = ScopeFilter.in(workspace.scopes.values.toList)
|
||||||
}
|
Def.task {
|
||||||
}.evaluated,
|
val items = bspScalaTestClassesItem.result.all(filter).value
|
||||||
bspScalaMainClasses := bspInputTask { (state, _, workspace, filter) =>
|
val successfulItems = anyOrThrow(items)
|
||||||
workspace.warnIfBuildsNonEmpty(Method.ScalaMainClasses, state.log)
|
val result = ScalaTestClassesResult(successfulItems.toVector, None)
|
||||||
Def.task {
|
s.respondEvent(result)
|
||||||
val items = bspScalaMainClassesItem.result.all(filter).value
|
}
|
||||||
val successfulItems = anyOrThrow(items)
|
})
|
||||||
val result = ScalaMainClassesResult(successfulItems.toVector, None)
|
.value,
|
||||||
state.respondEvent(result)
|
bspScalaMainClasses := (Def
|
||||||
}
|
.input((s: State) => targetIdentifierParser)
|
||||||
}.evaluated,
|
.flatMapTask { targets =>
|
||||||
|
val s = state.value
|
||||||
|
val workspace = bspFullWorkspace.value.filter(targets)
|
||||||
|
workspace.warnIfBuildsNonEmpty(Method.ScalaMainClasses, s.log)
|
||||||
|
val filter = ScopeFilter.in(workspace.scopes.values.toList)
|
||||||
|
Def.task {
|
||||||
|
val items = bspScalaMainClassesItem.result.all(filter).value
|
||||||
|
val successfulItems = anyOrThrow(items)
|
||||||
|
val result = ScalaMainClassesResult(successfulItems.toVector, None)
|
||||||
|
s.respondEvent(result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.value,
|
||||||
bspScalaMainClasses / aggregate := false
|
bspScalaMainClasses / aggregate := false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -555,15 +606,13 @@ object BuildServerProtocol {
|
||||||
if setting.key.key.label == Keys.bspTargetIdentifier.key.label
|
if setting.key.key.label == Keys.bspTargetIdentifier.key.label
|
||||||
} yield Scope.replaceThis(Scope.Global.in(ref))(setting.key.scope)
|
} yield Scope.replaceThis(Scope.Global.in(ref))(setting.key.scope)
|
||||||
|
|
||||||
Def.setting {
|
import sbt.TupleSyntax.*
|
||||||
val targetIds = scopes
|
t2ToApp2(
|
||||||
.map(_ / Keys.bspTargetIdentifier)
|
(
|
||||||
.join
|
scopes.map(_ / Keys.bspTargetIdentifier).join,
|
||||||
.value
|
scopes.map(_ / Keys.bspEnabled).join,
|
||||||
val bspEnabled = scopes
|
)
|
||||||
.map(_ / Keys.bspEnabled)
|
) { case ((targetIds: Seq[BuildTargetIdentifier], bspEnabled: Seq[Boolean])) =>
|
||||||
.join
|
|
||||||
.value
|
|
||||||
val buildsMap =
|
val buildsMap =
|
||||||
mutable.HashMap[BuildTargetIdentifier, mutable.ListBuffer[BuildTargetIdentifier]]()
|
mutable.HashMap[BuildTargetIdentifier, mutable.ListBuffer[BuildTargetIdentifier]]()
|
||||||
|
|
||||||
|
|
@ -879,8 +928,8 @@ object BuildServerProtocol {
|
||||||
Def.task {
|
Def.task {
|
||||||
val state = Keys.state.value
|
val state = Keys.state.value
|
||||||
val statusCode = resultTask.value match {
|
val statusCode = resultTask.value match {
|
||||||
case Value(_) => StatusCode.Success
|
case Result.Value(_) => StatusCode.Success
|
||||||
case Inc(_) => StatusCode.Error
|
case Result.Inc(_) => StatusCode.Error
|
||||||
}
|
}
|
||||||
val _ = state.respondEvent(TestResult(testParams.originId, statusCode))
|
val _ = state.respondEvent(TestResult(testParams.originId, statusCode))
|
||||||
}
|
}
|
||||||
|
|
@ -1013,15 +1062,15 @@ object BuildServerProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def anyOrThrow[T](results: Seq[Result[T]]): Seq[T] = {
|
private def anyOrThrow[T](results: Seq[Result[T]]): Seq[T] = {
|
||||||
val successes = results.collect { case Value(v) => v }
|
val successes = results.collect { case Result.Value(v) => v }
|
||||||
val errors = results.collect { case Inc(cause) => cause }
|
val errors = results.collect { case Result.Inc(cause) => cause }
|
||||||
if (successes.nonEmpty || errors.isEmpty) successes
|
if (successes.nonEmpty || errors.isEmpty) successes
|
||||||
else throw Incomplete(None, causes = errors)
|
else throw Incomplete(None, causes = errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def allOrThrow[T](results: Seq[Result[T]]): Seq[T] = {
|
private def allOrThrow[T](results: Seq[Result[T]]): Seq[T] = {
|
||||||
val successes = results.collect { case Value(v) => v }
|
val successes = results.collect { case Result.Value(v) => v }
|
||||||
val errors = results.collect { case Inc(cause) => cause }
|
val errors = results.collect { case Result.Inc(cause) => cause }
|
||||||
if (errors.isEmpty) successes
|
if (errors.isEmpty) successes
|
||||||
else throw Incomplete(None, causes = errors)
|
else throw Incomplete(None, causes = errors)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ import scala.annotation.{ nowarn, tailrec }
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
import scala.concurrent.{ ExecutionContext, Future }
|
import scala.concurrent.{ ExecutionContext, Future }
|
||||||
import scala.reflect.NameTransformer
|
import scala.reflect.NameTransformer
|
||||||
import scala.tools.reflect.{ ToolBox, ToolBoxError }
|
|
||||||
import scala.util.matching.Regex
|
import scala.util.matching.Regex
|
||||||
|
|
||||||
import sjsonnew.JsonFormat
|
import sjsonnew.JsonFormat
|
||||||
|
|
@ -25,6 +24,7 @@ import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter }
|
||||||
|
|
||||||
import sbt.internal.inc.{ Analysis, MixedAnalyzingCompiler }
|
import sbt.internal.inc.{ Analysis, MixedAnalyzingCompiler }
|
||||||
import sbt.internal.inc.JavaInterfaceUtil._
|
import sbt.internal.inc.JavaInterfaceUtil._
|
||||||
|
import sbt.internal.parser.SbtParser
|
||||||
import sbt.internal.protocol.JsonRpcResponseError
|
import sbt.internal.protocol.JsonRpcResponseError
|
||||||
import sbt.internal.protocol.codec.JsonRPCProtocol
|
import sbt.internal.protocol.codec.JsonRPCProtocol
|
||||||
import sbt.internal.langserver
|
import sbt.internal.langserver
|
||||||
|
|
@ -48,21 +48,7 @@ private[sbt] object Definition {
|
||||||
}
|
}
|
||||||
|
|
||||||
object textProcessor {
|
object textProcessor {
|
||||||
private val isIdentifier = {
|
private val isIdentifier: String => Boolean = SbtParser.isIdentifier
|
||||||
lazy val tb =
|
|
||||||
scala.reflect.runtime.universe
|
|
||||||
.runtimeMirror(this.getClass.getClassLoader)
|
|
||||||
.mkToolBox()
|
|
||||||
import tb._
|
|
||||||
lazy val check = parse _ andThen compile _
|
|
||||||
(identifier: String) =>
|
|
||||||
try {
|
|
||||||
check(s"val $identifier = 0; val ${identifier}${identifier} = $identifier")
|
|
||||||
true
|
|
||||||
} catch {
|
|
||||||
case _: ToolBoxError => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def findInBackticks(line: String, point: Int): Option[String] = {
|
private def findInBackticks(line: String, point: Int): Option[String] = {
|
||||||
val (even, odd) = line.zipWithIndex
|
val (even, odd) = line.zipWithIndex
|
||||||
|
|
@ -295,7 +281,7 @@ private[sbt] object Definition {
|
||||||
analysis.relations.definesClass(className) ++
|
analysis.relations.definesClass(className) ++
|
||||||
analysis.relations.libraryDefinesClass(className)
|
analysis.relations.libraryDefinesClass(className)
|
||||||
}
|
}
|
||||||
.flatMap { classFile: VirtualFileRef =>
|
.flatMap { (classFile: VirtualFileRef) =>
|
||||||
val x = converter.toPath(classFile)
|
val x = converter.toPath(classFile)
|
||||||
textProcessor.markPosition(x, sym).collect { case (uri, line, from, to) =>
|
textProcessor.markPosition(x, sym).collect { case (uri, line, from, to) =>
|
||||||
Location(
|
Location(
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import java.util.concurrent.{
|
||||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
||||||
|
|
||||||
import sbt.BasicCommandStrings.{ Shutdown, TerminateAction }
|
import sbt.BasicCommandStrings.{ Shutdown, TerminateAction }
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
import sbt.internal.langserver.{ CancelRequestParams, ErrorCodes, LogMessageParams, MessageType }
|
import sbt.internal.langserver.{ CancelRequestParams, ErrorCodes, LogMessageParams, MessageType }
|
||||||
import sbt.internal.protocol.{
|
import sbt.internal.protocol.{
|
||||||
JsonRpcNotificationMessage,
|
JsonRpcNotificationMessage,
|
||||||
|
|
@ -745,7 +746,7 @@ final class NetworkChannel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private class NetworkTerminal
|
private class NetworkTerminal
|
||||||
extends TerminalImpl(writeableInputStream, outputStream, errorStream, name) {
|
extends TerminalImpl(writeableInputStream, outputStream, errorStream, name) { term =>
|
||||||
private[this] val pending = new AtomicBoolean(false)
|
private[this] val pending = new AtomicBoolean(false)
|
||||||
private[this] val closed = new AtomicBoolean(false)
|
private[this] val closed = new AtomicBoolean(false)
|
||||||
private[this] val properties = new AtomicReference[TerminalPropertiesResponse]
|
private[this] val properties = new AtomicReference[TerminalPropertiesResponse]
|
||||||
|
|
@ -755,7 +756,7 @@ final class NetworkChannel(
|
||||||
if (alive.get) {
|
if (alive.get) {
|
||||||
if (!pending.get && Option(lastUpdate.get).fold(true)(d => (d + 1.second).isOverdue)) {
|
if (!pending.get && Option(lastUpdate.get).fold(true)(d => (d + 1.second).isOverdue)) {
|
||||||
pending.set(true)
|
pending.set(true)
|
||||||
val queue = VirtualTerminal.sendTerminalPropertiesQuery(name, jsonRpcRequest)
|
val queue = VirtualTerminal.sendTerminalPropertiesQuery(term.name, jsonRpcRequest)
|
||||||
val update: Runnable = () => {
|
val update: Runnable = () => {
|
||||||
queue.poll(5, java.util.concurrent.TimeUnit.SECONDS) match {
|
queue.poll(5, java.util.concurrent.TimeUnit.SECONDS) match {
|
||||||
case null =>
|
case null =>
|
||||||
|
|
@ -767,7 +768,7 @@ final class NetworkChannel(
|
||||||
pending.notifyAll()
|
pending.notifyAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new Thread(update, s"network-terminal-$name-update") {
|
new Thread(update, s"network-terminal-${term.name}-update") {
|
||||||
setDaemon(true)
|
setDaemon(true)
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
@ -829,7 +830,11 @@ final class NetworkChannel(
|
||||||
): Option[T] = {
|
): Option[T] = {
|
||||||
if (closed.get) None
|
if (closed.get) None
|
||||||
else {
|
else {
|
||||||
val queue = VirtualTerminal.sendTerminalCapabilitiesQuery(name, jsonRpcRequest, query)
|
val queue = VirtualTerminal.sendTerminalCapabilitiesQuery(
|
||||||
|
term.name,
|
||||||
|
jsonRpcRequest[TerminalCapabilitiesQuery],
|
||||||
|
query
|
||||||
|
)
|
||||||
Some(result(queue.take))
|
Some(result(queue.take))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -856,8 +861,8 @@ final class NetworkChannel(
|
||||||
if (closed.get) Map.empty
|
if (closed.get) Map.empty
|
||||||
else {
|
else {
|
||||||
val queue = VirtualTerminal.sendTerminalAttributesQuery(
|
val queue = VirtualTerminal.sendTerminalAttributesQuery(
|
||||||
name,
|
term.name,
|
||||||
jsonRpcRequest
|
jsonRpcRequest[TerminalAttributesQuery]
|
||||||
)
|
)
|
||||||
try {
|
try {
|
||||||
val a = queue.take
|
val a = queue.take
|
||||||
|
|
@ -879,13 +884,18 @@ final class NetworkChannel(
|
||||||
lflag = attributes.getOrElse("lflag", ""),
|
lflag = attributes.getOrElse("lflag", ""),
|
||||||
cchars = attributes.getOrElse("cchars", ""),
|
cchars = attributes.getOrElse("cchars", ""),
|
||||||
)
|
)
|
||||||
val queue = VirtualTerminal.setTerminalAttributesCommand(name, jsonRpcRequest, attrs)
|
val queue = VirtualTerminal.setTerminalAttributesCommand(
|
||||||
|
term.name,
|
||||||
|
jsonRpcRequest[TerminalSetAttributesCommand],
|
||||||
|
attrs
|
||||||
|
)
|
||||||
try queue.take
|
try queue.take
|
||||||
catch { case _: InterruptedException => }
|
catch { case _: InterruptedException => }
|
||||||
}
|
}
|
||||||
override private[sbt] def getSizeImpl: (Int, Int) =
|
override private[sbt] def getSizeImpl: (Int, Int) =
|
||||||
if (!closed.get) {
|
if (!closed.get) {
|
||||||
val queue = VirtualTerminal.getTerminalSize(name, jsonRpcRequest)
|
val queue =
|
||||||
|
VirtualTerminal.getTerminalSize(term.name, jsonRpcRequest[TerminalGetSizeQuery])
|
||||||
val res =
|
val res =
|
||||||
try queue.take
|
try queue.take
|
||||||
catch { case _: InterruptedException => TerminalGetSizeResponse(1, 1) }
|
catch { case _: InterruptedException => TerminalGetSizeResponse(1, 1) }
|
||||||
|
|
@ -894,14 +904,19 @@ final class NetworkChannel(
|
||||||
override def setSize(width: Int, height: Int): Unit =
|
override def setSize(width: Int, height: Int): Unit =
|
||||||
if (!closed.get) {
|
if (!closed.get) {
|
||||||
val size = TerminalSetSizeCommand(width, height)
|
val size = TerminalSetSizeCommand(width, height)
|
||||||
val queue = VirtualTerminal.setTerminalSize(name, jsonRpcRequest, size)
|
val queue =
|
||||||
|
VirtualTerminal.setTerminalSize(term.name, jsonRpcRequest[TerminalSetSizeCommand], size)
|
||||||
try queue.take
|
try queue.take
|
||||||
catch { case _: InterruptedException => }
|
catch { case _: InterruptedException => }
|
||||||
}
|
}
|
||||||
private[this] def setRawMode(toggle: Boolean): Unit = {
|
private[this] def setRawMode(toggle: Boolean): Unit = {
|
||||||
if (!closed.get || false) {
|
if (!closed.get || false) {
|
||||||
val raw = TerminalSetRawModeCommand(toggle)
|
val raw = TerminalSetRawModeCommand(toggle)
|
||||||
val queue = VirtualTerminal.setTerminalRawMode(name, jsonRpcRequest, raw)
|
val queue = VirtualTerminal.setTerminalRawMode(
|
||||||
|
term.name,
|
||||||
|
jsonRpcRequest[TerminalSetRawModeCommand],
|
||||||
|
raw
|
||||||
|
)
|
||||||
try queue.take
|
try queue.take
|
||||||
catch { case _: InterruptedException => }
|
catch { case _: InterruptedException => }
|
||||||
}
|
}
|
||||||
|
|
@ -911,13 +926,14 @@ final class NetworkChannel(
|
||||||
override def setEchoEnabled(toggle: Boolean): Unit =
|
override def setEchoEnabled(toggle: Boolean): Unit =
|
||||||
if (!closed.get) {
|
if (!closed.get) {
|
||||||
val echo = TerminalSetEchoCommand(toggle)
|
val echo = TerminalSetEchoCommand(toggle)
|
||||||
val queue = VirtualTerminal.setTerminalEcho(name, jsonRpcRequest, echo)
|
val queue =
|
||||||
|
VirtualTerminal.setTerminalEcho(term.name, jsonRpcRequest[TerminalSetEchoCommand], echo)
|
||||||
try queue.take
|
try queue.take
|
||||||
catch { case _: InterruptedException => () }
|
catch { case _: InterruptedException => () }
|
||||||
}
|
}
|
||||||
|
|
||||||
override def flush(): Unit = doFlush()
|
override def flush(): Unit = doFlush()
|
||||||
override def toString: String = s"NetworkTerminal($name)"
|
override def toString: String = s"NetworkTerminal(${term.name})"
|
||||||
override def close(): Unit = if (closed.compareAndSet(false, true)) {
|
override def close(): Unit = if (closed.compareAndSet(false, true)) {
|
||||||
val threads = blockedThreads.synchronized {
|
val threads = blockedThreads.synchronized {
|
||||||
val t = blockedThreads.asScala.toVector
|
val t = blockedThreads.asScala.toVector
|
||||||
|
|
@ -961,7 +977,7 @@ object NetworkChannel {
|
||||||
|
|
||||||
// direct comparison on strings and
|
// direct comparison on strings and
|
||||||
// remove hotspring unicode added character for numbers
|
// remove hotspring unicode added character for numbers
|
||||||
if (checkId || force) {
|
if (checkId() || force) {
|
||||||
runningEngine.cancelAndShutdown()
|
runningEngine.cancelAndShutdown()
|
||||||
Right(runningExecId)
|
Right(runningExecId)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import java.nio.file.Path
|
||||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
||||||
import sbt.BasicCommandStrings.{ RebootCommand, Shutdown, TerminateAction }
|
import sbt.BasicCommandStrings.{ RebootCommand, Shutdown, TerminateAction }
|
||||||
import sbt.Keys.{ baseDirectory, pollInterval, state }
|
import sbt.Keys.{ baseDirectory, pollInterval, state }
|
||||||
|
import sbt.ProjectExtra.extract
|
||||||
import sbt.Scope.Global
|
import sbt.Scope.Global
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.internal.CommandStrings.LoadProject
|
import sbt.internal.CommandStrings.LoadProject
|
||||||
|
|
@ -16,6 +16,7 @@ import sbt.io.IO
|
||||||
import sbt.nio.file.FileAttributes
|
import sbt.nio.file.FileAttributes
|
||||||
import sjsonnew.{ Builder, JsonFormat, Unbuilder, deserializationError }
|
import sjsonnew.{ Builder, JsonFormat, Unbuilder, deserializationError }
|
||||||
import xsbti.compile.analysis.{ Stamp => XStamp }
|
import xsbti.compile.analysis.{ Stamp => XStamp }
|
||||||
|
import org.checkerframework.checker.units.qual.A
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A trait that indicates what file stamping implementation should be used to track the state of
|
* A trait that indicates what file stamping implementation should be used to track the state of
|
||||||
|
|
@ -49,15 +50,14 @@ sealed trait FileStamp
|
||||||
* Provides json formatters for [[FileStamp]].
|
* Provides json formatters for [[FileStamp]].
|
||||||
*/
|
*/
|
||||||
object FileStamp {
|
object FileStamp {
|
||||||
private[sbt] type Id[T] = T
|
private[sbt] type Id[A] = A
|
||||||
|
|
||||||
private[sbt] implicit class Ops(val fileStamp: FileStamp) {
|
extension (fileStamp: FileStamp)
|
||||||
private[sbt] def stamp: XStamp = fileStamp match {
|
private[sbt] def stamp: XStamp =
|
||||||
case f: FileHashImpl => f.xstamp
|
fileStamp match
|
||||||
case LastModified(time) => new IncLastModified(time)
|
case f: FileHashImpl => f.xstamp
|
||||||
case _ => EmptyStamp
|
case LastModified(time) => new IncLastModified(time)
|
||||||
}
|
case _ => EmptyStamp
|
||||||
}
|
|
||||||
|
|
||||||
private[sbt] def apply(path: Path, fileStamper: FileStamper): Option[FileStamp] =
|
private[sbt] def apply(path: Path, fileStamper: FileStamper): Option[FileStamp] =
|
||||||
fileStamper match {
|
fileStamper match {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import sbt.util.{ Level, Logger }
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
import scala.collection.immutable.StringOps
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import scala.util.control.NonFatal
|
import scala.util.control.NonFatal
|
||||||
|
|
||||||
|
|
@ -505,7 +506,9 @@ object Watch {
|
||||||
val opts = distinctOptions(options).sortBy(_.input)
|
val opts = distinctOptions(options).sortBy(_.input)
|
||||||
val alignmentLength = opts.map(_.display.length).max + 1
|
val alignmentLength = opts.map(_.display.length).max + 1
|
||||||
val formatted =
|
val formatted =
|
||||||
opts.map(o => s"${o.display}${" " * (alignmentLength - o.display.length)}: ${o.description}")
|
opts.map(o =>
|
||||||
|
s"${o.display}${StringOps(" ") * (alignmentLength - o.display.length)}: ${o.description}"
|
||||||
|
)
|
||||||
s"Options:\n${formatted.mkString(" ", "\n ", "")}"
|
s"Options:\n${formatted.mkString(" ", "\n ", "")}"
|
||||||
}
|
}
|
||||||
private def distinctOptions(options: Seq[InputOption]): Seq[InputOption] = {
|
private def distinctOptions(options: Seq[InputOption]): Seq[InputOption] = {
|
||||||
|
|
@ -535,7 +538,8 @@ object Watch {
|
||||||
(count: Int, project: ProjectRef, commands: Seq[String]) =>
|
(count: Int, project: ProjectRef, commands: Seq[String]) =>
|
||||||
{
|
{
|
||||||
val countStr = s"$count. "
|
val countStr = s"$count. "
|
||||||
Some(s"$countStr${waitMessage(project, commands).mkString(s"\n${" " * countStr.length}")}")
|
Some(s"$countStr${waitMessage(project, commands)
|
||||||
|
.mkString(s"\n${StringOps(" ") * countStr.length}")}")
|
||||||
}
|
}
|
||||||
}.label("Watched.defaultStartWatch")
|
}.label("Watched.defaultStartWatch")
|
||||||
|
|
||||||
|
|
@ -14,6 +14,8 @@ import sbt.Def._
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.Project._
|
import sbt.Project._
|
||||||
|
import sbt.ProjectExtra.storeAs
|
||||||
|
import sbt.ProjectExtra.richInitializeTask
|
||||||
import sbt.internal.graph._
|
import sbt.internal.graph._
|
||||||
import sbt.internal.graph.backend.SbtUpdateReport
|
import sbt.internal.graph.backend.SbtUpdateReport
|
||||||
import sbt.internal.graph.rendering.{ DagreHTML, TreeView }
|
import sbt.internal.graph.rendering.{ DagreHTML, TreeView }
|
||||||
|
|
@ -40,7 +42,7 @@ object DependencyTreeSettings {
|
||||||
.withCachedResolution(false),
|
.withCachedResolution(false),
|
||||||
dependencyTreeIgnoreMissingUpdate / ivyConfiguration := {
|
dependencyTreeIgnoreMissingUpdate / ivyConfiguration := {
|
||||||
// inTask will make sure the new definition will pick up `updateOptions in dependencyTreeIgnoreMissingUpdate`
|
// inTask will make sure the new definition will pick up `updateOptions in dependencyTreeIgnoreMissingUpdate`
|
||||||
inTask(dependencyTreeIgnoreMissingUpdate, Classpaths.mkIvyConfiguration).value
|
Project.inTask(dependencyTreeIgnoreMissingUpdate, Classpaths.mkIvyConfiguration).value
|
||||||
},
|
},
|
||||||
dependencyTreeIgnoreMissingUpdate / ivyModule := {
|
dependencyTreeIgnoreMissingUpdate / ivyModule := {
|
||||||
// concatenating & inlining ivySbt & ivyModule default task implementations, as `SbtAccess.inTask` does
|
// concatenating & inlining ivySbt & ivyModule default task implementations, as `SbtAccess.inTask` does
|
||||||
|
|
@ -54,7 +56,7 @@ object DependencyTreeSettings {
|
||||||
.withMissingOk(true),
|
.withMissingOk(true),
|
||||||
dependencyTreeIgnoreMissingUpdate := {
|
dependencyTreeIgnoreMissingUpdate := {
|
||||||
// inTask will make sure the new definition will pick up `ivyModule/updateConfiguration in ignoreMissingUpdate`
|
// inTask will make sure the new definition will pick up `ivyModule/updateConfiguration in ignoreMissingUpdate`
|
||||||
inTask(dependencyTreeIgnoreMissingUpdate, Classpaths.updateTask).value
|
Project.inTask(dependencyTreeIgnoreMissingUpdate, Classpaths.updateTask).value
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ import Def.{ Setting, settingKey }
|
||||||
import Defaults._
|
import Defaults._
|
||||||
import Keys._
|
import Keys._
|
||||||
import KeyRanks._
|
import KeyRanks._
|
||||||
import sbt.Project.inConfig
|
import sbt.ProjectExtra.inConfig
|
||||||
import sbt.internal._
|
import sbt.internal._
|
||||||
import sbt.io.syntax._
|
import sbt.io.syntax._
|
||||||
import sbt.librarymanagement.Configurations.{ IntegrationTest, Test }
|
import sbt.librarymanagement.Configurations.{ IntegrationTest, Test }
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ package sbt
|
||||||
package plugins
|
package plugins
|
||||||
|
|
||||||
import sbt.PluginTrigger.AllRequirements
|
import sbt.PluginTrigger.AllRequirements
|
||||||
import sbt.Project._
|
import sbt.ProjectExtra.*
|
||||||
import sbt.librarymanagement.Configurations.{ Compile, Test }
|
import sbt.librarymanagement.Configurations.{ Compile, Test }
|
||||||
|
|
||||||
object MiniDependencyTreePlugin extends AutoPlugin {
|
object MiniDependencyTreePlugin extends AutoPlugin {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import Keys._
|
||||||
import sbt.internal.SysProp
|
import sbt.internal.SysProp
|
||||||
import sbt.librarymanagement.syntax._
|
import sbt.librarymanagement.syntax._
|
||||||
import sbt.librarymanagement.{ Configuration, CrossVersion }
|
import sbt.librarymanagement.{ Configuration, CrossVersion }
|
||||||
import Project.inConfig
|
import ProjectExtra.inConfig
|
||||||
import sbt.internal.inc.ScalaInstance
|
import sbt.internal.inc.ScalaInstance
|
||||||
import sbt.ScopeFilter.Make._
|
import sbt.ScopeFilter.Make._
|
||||||
|
|
||||||
|
|
@ -11,6 +11,7 @@ import sbt.Def.{ ScopedKey, displayFull, displayMasked }
|
||||||
import sbt.internal.TestBuild._
|
import sbt.internal.TestBuild._
|
||||||
import sbt.internal.util.complete.Parser
|
import sbt.internal.util.complete.Parser
|
||||||
import sbt.internal.{ Resolve, TestBuild }
|
import sbt.internal.{ Resolve, TestBuild }
|
||||||
|
import sbt.ProjectExtra.equalKeys
|
||||||
import hedgehog._
|
import hedgehog._
|
||||||
import hedgehog.core.{ ShrinkLimit, SuccessCount }
|
import hedgehog.core.{ ShrinkLimit, SuccessCount }
|
||||||
import hedgehog.runner._
|
import hedgehog.runner._
|
||||||
|
|
@ -64,7 +65,7 @@ object ParseKey extends Properties {
|
||||||
val expected = resolve(structure, key, mask)
|
val expected = resolve(structure, key, mask)
|
||||||
parseCheck(structure, key, mask, showZeroConfig)(sk =>
|
parseCheck(structure, key, mask, showZeroConfig)(sk =>
|
||||||
hedgehog.Result
|
hedgehog.Result
|
||||||
.assert(Project.equal(sk, expected, mask))
|
.assert(Project.equalKeys(sk, expected, mask))
|
||||||
.log(s"$sk.key == $expected.key: ${sk.key == expected.key}")
|
.log(s"$sk.key == $expected.key: ${sk.key == expected.key}")
|
||||||
.log(s"${sk.scope} == ${expected.scope}: ${Scope.equal(sk.scope, expected.scope, mask)}")
|
.log(s"${sk.scope} == ${expected.scope}: ${Scope.equal(sk.scope, expected.scope, mask)}")
|
||||||
).log(s"Expected: ${displayFull(expected)}")
|
).log(s"Expected: ${displayFull(expected)}")
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@
|
||||||
|
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
|
/*
|
||||||
import java.io._
|
import java.io._
|
||||||
|
|
||||||
import sbt.internal._
|
import sbt.internal._
|
||||||
|
import sbt.internal.inc.MappedFileConverter
|
||||||
import sbt.internal.util.{
|
import sbt.internal.util.{
|
||||||
AttributeEntry,
|
AttributeEntry,
|
||||||
AttributeMap,
|
AttributeMap,
|
||||||
|
|
@ -90,7 +92,7 @@ object FakeState {
|
||||||
val settings: Seq[Def.Setting[_]] = Nil
|
val settings: Seq[Def.Setting[_]] = Nil
|
||||||
|
|
||||||
val currentProject = Map(testProject.base.toURI -> testProject.id)
|
val currentProject = Map(testProject.base.toURI -> testProject.id)
|
||||||
val currentEval: () => sbt.compiler.Eval = () => Load.mkEval(Nil, base, Nil)
|
val currentEval: () => Eval = () => Load.mkEval(Nil, base, Nil)
|
||||||
val sessionSettings =
|
val sessionSettings =
|
||||||
SessionSettings(base.toURI, currentProject, Nil, Map.empty, Nil, currentEval)
|
SessionSettings(base.toURI, currentProject, Nil, Map.empty, Nil, currentEval)
|
||||||
|
|
||||||
|
|
@ -98,7 +100,7 @@ object FakeState {
|
||||||
val scopeLocal: Def.ScopeLocal = _ => Nil
|
val scopeLocal: Def.ScopeLocal = _ => Nil
|
||||||
|
|
||||||
val (cMap, data: Settings[Scope]) =
|
val (cMap, data: Settings[Scope]) =
|
||||||
Def.makeWithCompiledMap(settings)(delegates, scopeLocal, Def.showFullKey)
|
Def.makeWithCompiledMap(settings)(using delegates, scopeLocal, Def.showFullKey)
|
||||||
val extra: KeyIndex => BuildUtil[_] = (keyIndex) =>
|
val extra: KeyIndex => BuildUtil[_] = (keyIndex) =>
|
||||||
BuildUtil(base.toURI, Map.empty, keyIndex, data)
|
BuildUtil(base.toURI, Map.empty, keyIndex, data)
|
||||||
val structureIndex: StructureIndex =
|
val structureIndex: StructureIndex =
|
||||||
|
|
@ -138,6 +140,7 @@ object FakeState {
|
||||||
delegates,
|
delegates,
|
||||||
scopeLocal,
|
scopeLocal,
|
||||||
cMap,
|
cMap,
|
||||||
|
MappedFileConverter.empty,
|
||||||
)
|
)
|
||||||
|
|
||||||
val attributes = AttributeMap.empty ++ AttributeMap(
|
val attributes = AttributeMap.empty ++ AttributeMap(
|
||||||
|
|
@ -165,3 +168,4 @@ object FakeState {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
* Licensed under Apache License 2.0 (see LICENSE)
|
* Licensed under Apache License 2.0 (see LICENSE)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
|
|
@ -106,3 +107,4 @@ object AI {
|
||||||
override def requires = A && !Q
|
override def requires = A && !Q
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ package sbt
|
||||||
import scala.util.control.NonFatal
|
import scala.util.control.NonFatal
|
||||||
import org.scalacheck._
|
import org.scalacheck._
|
||||||
import Prop._
|
import Prop._
|
||||||
import Project.project
|
import sbt.BuildSyntax.project
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class ProjectDefs {
|
class ProjectDefs {
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,10 @@ object TagsTest extends Properties("Tags") {
|
||||||
def size: Gen[Size] =
|
def size: Gen[Size] =
|
||||||
for (i <- Arbitrary.arbitrary[Int] if i != Int.MinValue) yield Size(math.abs(i))
|
for (i <- Arbitrary.arbitrary[Int] if i != Int.MinValue) yield Size(math.abs(i))
|
||||||
|
|
||||||
implicit def aTagMap = Arbitrary(tagMap)
|
implicit def aTagMap: Arbitrary[Map[Tag, Int]] = Arbitrary(tagMap)
|
||||||
implicit def aTagAndFrequency = Arbitrary(tagAndFrequency)
|
implicit def aTagAndFrequency: Arbitrary[(Tag, Int)] = Arbitrary(tagAndFrequency)
|
||||||
implicit def aTag = Arbitrary(tag)
|
implicit def aTag: Arbitrary[Tag] = Arbitrary(tag)
|
||||||
implicit def aSize = Arbitrary(size)
|
implicit def aSize: Arbitrary[Size] = Arbitrary(size)
|
||||||
|
|
||||||
property("exclusive allows all groups without the exclusive tag") = forAll {
|
property("exclusive allows all groups without the exclusive tag") = forAll {
|
||||||
(tm: TagMap, tag: Tag) =>
|
(tm: TagMap, tag: Tag) =>
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue