Settings as a Map[ScopedKey[x], x]

Settings0 used to be a Map[Scope, AttributeMap], and is now a
Map[ScopedKey[x], x].
This is better because we don't need to decompose all ScopedKey[x]
into a Scope and an AttributeKey[x], for recomposing it back later,
which duplicates all ScopedKey[x]. It reduces the number of long-living
ScopedKey[x] by 8%, and the total number of instances by 1.4%.

Also it improves the performance of Settings0, which was responsible of
2.95% of the total CPU time, and is now responsible of 0.41%.
This commit is contained in:
Adrien Piquerez 2024-11-11 13:49:14 +01:00
parent 661f1fa216
commit f4f185a1c1
34 changed files with 312 additions and 388 deletions

View File

@ -9,19 +9,12 @@
package sbt package sbt
package internal package internal
import sbt.internal.util.{ import sbt.internal.util.{ AttributeKey, LineRange, MessageOnlyException, RangePosition }
AttributeEntry,
AttributeKey,
LineRange,
MessageOnlyException,
RangePosition,
Settings
}
import java.io.File 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, Settings }
import Scope.GlobalScope import Scope.GlobalScope
import sbt.SlashSyntax0.given import sbt.SlashSyntax0.given
import sbt.internal.parser.SbtParser import sbt.internal.parser.SbtParser
@ -351,15 +344,9 @@ object BuildUtilLite:
end BuildUtilLite end BuildUtilLite
object Index { object Index {
def taskToKeyMap(data: Settings[Scope]): Map[Task[?], ScopedKey[Task[?]]] = { def taskToKeyMap(data: Settings): Map[Task[?], ScopedKey[Task[?]]] =
data.data.collect { case (key, value: Task[?]) =>
val pairs = data.scopes flatMap (scope => (value, key.asInstanceOf[ScopedKey[Task[?]]])
data.data(scope).entries collect { case AttributeEntry(key, value: Task[_]) =>
(value, ScopedKey(scope, key.asInstanceOf[AttributeKey[Task[?]]]))
}
)
pairs.toMap[Task[?], ScopedKey[Task[?]]]
} }
def allKeys(settings: Seq[Setting[?]]): Set[ScopedKey[?]] = { def allKeys(settings: Seq[Setting[?]]): Set[ScopedKey[?]] = {
@ -372,9 +359,6 @@ object Index {
result.asScala.toSet result.asScala.toSet
} }
def attributeKeys(settings: Settings[Scope]): Set[AttributeKey[?]] =
settings.data.values.flatMap(_.keys).toSet[AttributeKey[?]]
def stringToKeyMap(settings: Set[AttributeKey[?]]): Map[String, AttributeKey[?]] = def stringToKeyMap(settings: Set[AttributeKey[?]]): Map[String, AttributeKey[?]] =
stringToKeyMap0(settings)(_.label) stringToKeyMap0(settings)(_.label)
@ -396,19 +380,17 @@ object Index {
private type TriggerMap = collection.mutable.HashMap[TaskId[?], Seq[TaskId[?]]] private type TriggerMap = collection.mutable.HashMap[TaskId[?], Seq[TaskId[?]]]
def triggers(ss: Settings[Scope]): Triggers = { def triggers(ss: Settings): Triggers = {
val runBefore = new TriggerMap val runBefore = new TriggerMap
val triggeredBy = new TriggerMap val triggeredBy = new TriggerMap
for ss.values.collect { case base: Task[?] =>
a <- ss.data.values
case AttributeEntry(_, base: Task[?]) <- a.entries
do
def update(map: TriggerMap, key: AttributeKey[Seq[Task[?]]]): Unit = def update(map: TriggerMap, key: AttributeKey[Seq[Task[?]]]): Unit =
base.info.attributes.get(key).getOrElse(Seq.empty).foreach { task => base.info.attributes.get(key).getOrElse(Seq.empty).foreach { task =>
map(task) = base +: map.getOrElse(task, Nil) map(task) = base +: map.getOrElse(task, Nil)
} }
update(runBefore, Def.runBefore) update(runBefore, Def.runBefore)
update(triggeredBy, Def.triggeredBy) update(triggeredBy, Def.triggeredBy)
}
val onComplete = (GlobalScope / Def.onComplete).get(ss).getOrElse(() => ()) val onComplete = (GlobalScope / Def.onComplete).get(ss).getOrElse(() => ())
new Triggers(runBefore, triggeredBy, map => { onComplete(); map }) new Triggers(runBefore, triggeredBy, map => { onComplete(); map })
} }

View File

@ -54,7 +54,8 @@ trait BuildSyntax:
end BuildSyntax end BuildSyntax
/** 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 BuildSyntax with Init[Scope] with InitializeImplicits: object Def extends BuildSyntax with Init with InitializeImplicits:
type ScopeType = Scope
type Classpath = Seq[Attributed[HashedVirtualFileRef]] type Classpath = Seq[Attributed[HashedVirtualFileRef]]
def settings(ss: SettingsDefinition*): Seq[Setting[?]] = ss.flatMap(_.settings) def settings(ss: SettingsDefinition*): Seq[Setting[?]] = ss.flatMap(_.settings)

View File

@ -334,7 +334,7 @@ object Project:
ScopedKey(Scope.fillTaskAxis(scoped.scope, scoped.key), scoped.key) ScopedKey(Scope.fillTaskAxis(scoped.scope, scoped.key), scoped.key)
def mapScope(f: Scope => Scope): [a] => ScopedKey[a] => ScopedKey[a] = def mapScope(f: Scope => Scope): [a] => ScopedKey[a] => ScopedKey[a] =
[a] => (k: ScopedKey[a]) => ScopedKey(f(k.scope), k.key) [a] => (k: ScopedKey[a]) => k.copy(scope = f(k.scope))
def transform(g: Scope => Scope, ss: Seq[Def.Setting[?]]): Seq[Def.Setting[?]] = def transform(g: Scope => Scope, ss: Seq[Def.Setting[?]]): Seq[Def.Setting[?]] =
// We use caching to avoid creating new Scope instances too many times // We use caching to avoid creating new Scope instances too many times
@ -361,7 +361,10 @@ object Project:
Project.transform(Scope.replaceThis(scope), ss) Project.transform(Scope.replaceThis(scope), ss)
private[sbt] def inScope[A](scope: Scope, i: Initialize[A]): Initialize[A] = private[sbt] def inScope[A](scope: Scope, i: Initialize[A]): Initialize[A] =
i.mapReferenced(Project.mapScope(Scope.replaceThis(scope))) i.mapReferenced(replaceThis(scope))
private[sbt] def replaceThis(scope: Scope): Def.MapScoped =
mapScope(Scope.replaceThis(scope))
/** /**
* Normalize a String so that it is suitable for use as a dependency management module identifier. * Normalize a String so that it is suitable for use as a dependency management module identifier.

View File

@ -11,7 +11,7 @@ package sbt
import scala.annotation.targetName import scala.annotation.targetName
import sbt.internal.util.Types.* import sbt.internal.util.Types.*
import sbt.internal.util.{ AttributeKey, KeyTag, Settings, SourcePosition } import sbt.internal.util.{ AttributeKey, KeyTag, SourcePosition }
import sbt.internal.util.TupleMapExtension.* import sbt.internal.util.TupleMapExtension.*
import sbt.util.OptJsonWriter import sbt.util.OptJsonWriter
import sbt.ConcurrentRestrictions.Tag import sbt.ConcurrentRestrictions.Tag
@ -303,8 +303,7 @@ object Scoped:
setting(scopedKey, app, source) setting(scopedKey, app, source)
/** From the given `Settings`, extract the value bound to this key. */ /** From the given `Settings`, extract the value bound to this key. */
final def get(settings: Settings[Scope]): Option[A1] = final def get(settings: Def.Settings): Option[A1] = settings.get(scopedKey)
settings.get(scopedKey.scope, scopedKey.key)
/** /**
* Creates an [[Def.Initialize]] with value `scala.None` if there was no previous definition of this key, * Creates an [[Def.Initialize]] with value `scala.None` if there was no previous definition of this key,
@ -460,7 +459,7 @@ object Scoped:
def toSettingKey: SettingKey[Task[A1]] = scopedSetting(scope, key) def toSettingKey: SettingKey[Task[A1]] = scopedSetting(scope, key)
def get(settings: Settings[Scope]): Option[Task[A1]] = settings.get(scope, key) def get(settings: Def.Settings): Option[Task[A1]] = settings.get(scopedKey)
/** /**
* Creates an [[Def.Initialize]] with value `scala.None` if there was no previous definition of this key, * Creates an [[Def.Initialize]] with value `scala.None` if there was no previous definition of this key,

View File

@ -47,7 +47,7 @@ end ParserInstance
/** Composes the Task and Initialize Instances to provide an Instance for [A1] Initialize[Task[A1]]. */ /** Composes the Task and Initialize Instances to provide an Instance for [A1] Initialize[Task[A1]]. */
object FullInstance: object FullInstance:
type SS = sbt.internal.util.Settings[Scope] type SS = Def.Settings
val settingsData = TaskKey[SS]( val settingsData = TaskKey[SS](
"settings-data", "settings-data",
"Provides access to the project data for the build.", "Provides access to the project data for the build.",

View File

@ -4177,14 +4177,15 @@ object Classpaths {
try { try {
val extracted = Project.extract(st) val extracted = Project.extract(st)
val sk = (projRef / Zero / Zero / libraryDependencies).scopedKey val sk = (projRef / Zero / Zero / libraryDependencies).scopedKey
val empty = extracted.structure.data.set(sk.scope, sk.key, Nil) val empty = extracted.structure.data.set(sk, Nil)
val settings = extracted.structure.settings filter { (s: Setting[?]) => val settings = extracted.structure.settings filter { (s: Setting[?]) =>
(s.key.key == libraryDependencies.key) && (s.key.key == libraryDependencies.key) &&
(s.key.scope.project == Select(projRef)) (s.key.scope.project == Select(projRef))
} }
Map(settings.asInstanceOf[Seq[Setting[Seq[ModuleID]]]].flatMap { s => settings
s.init.evaluate(empty) map { _ -> s.pos } .asInstanceOf[Seq[Setting[Seq[ModuleID]]]]
}*) .flatMap(s => s.init.evaluate(empty).map(_ -> s.pos))
.toMap
} catch { } catch {
case NonFatal(_) => Map() case NonFatal(_) => Map()
} }
@ -4339,7 +4340,7 @@ object Classpaths {
private[sbt] def depMap( private[sbt] def depMap(
projects: Seq[ProjectRef], projects: Seq[ProjectRef],
data: Settings[Scope], data: Def.Settings,
log: Logger log: Logger
): Task[Map[ModuleRevisionId, ModuleDescriptor]] = ): Task[Map[ModuleRevisionId, ModuleDescriptor]] =
val ivyModules = projects.flatMap { proj => val ivyModules = projects.flatMap { proj =>
@ -4416,14 +4417,14 @@ object Classpaths {
def interSort( def interSort(
projectRef: ProjectRef, projectRef: ProjectRef,
conf: Configuration, conf: Configuration,
data: Settings[Scope], data: Def.Settings,
deps: BuildDependencies deps: BuildDependencies
): Seq[(ProjectRef, String)] = ClasspathImpl.interSort(projectRef, conf, data, deps) ): Seq[(ProjectRef, String)] = ClasspathImpl.interSort(projectRef, conf, data, deps)
def interSortConfigurations( def interSortConfigurations(
projectRef: ProjectRef, projectRef: ProjectRef,
conf: Configuration, conf: Configuration,
data: Settings[Scope], data: Def.Settings,
deps: BuildDependencies deps: BuildDependencies
): Seq[(ProjectRef, ConfigRef)] = ): Seq[(ProjectRef, ConfigRef)] =
interSort(projectRef, conf, data, deps).map { case (projectRef, configName) => interSort(projectRef, conf, data, deps).map { case (projectRef, configName) =>
@ -4467,23 +4468,23 @@ object Classpaths {
sys.error("Configuration '" + conf + "' not defined in '" + in + "'") sys.error("Configuration '" + conf + "' not defined in '" + in + "'")
def allConfigs(conf: Configuration): Seq[Configuration] = ClasspathImpl.allConfigs(conf) def allConfigs(conf: Configuration): Seq[Configuration] = ClasspathImpl.allConfigs(conf)
def getConfigurations(p: ResolvedReference, data: Settings[Scope]): Seq[Configuration] = def getConfigurations(p: ResolvedReference, data: Def.Settings): Seq[Configuration] =
ClasspathImpl.getConfigurations(p, data) ClasspathImpl.getConfigurations(p, data)
def confOpt(configurations: Seq[Configuration], conf: String): Option[Configuration] = def confOpt(configurations: Seq[Configuration], conf: String): Option[Configuration] =
ClasspathImpl.confOpt(configurations, conf) ClasspathImpl.confOpt(configurations, conf)
def unmanagedLibs(dep: ResolvedReference, conf: String, data: Settings[Scope]): Task[Classpath] = def unmanagedLibs(dep: ResolvedReference, conf: String, data: Def.Settings): Task[Classpath] =
ClasspathImpl.unmanagedLibs(dep, conf, data) ClasspathImpl.unmanagedLibs(dep, conf, data)
def getClasspath( def getClasspath(
key: TaskKey[Classpath], key: TaskKey[Classpath],
dep: ResolvedReference, dep: ResolvedReference,
conf: String, conf: String,
data: Settings[Scope] data: Def.Settings
): Task[Classpath] = ): Task[Classpath] =
ClasspathImpl.getClasspath(key, dep, conf, data) ClasspathImpl.getClasspath(key, dep, conf, data)
def defaultConfigurationTask(p: ResolvedReference, data: Settings[Scope]): Configuration = def defaultConfigurationTask(p: ResolvedReference, data: Def.Settings): Configuration =
(p / defaultConfiguration).get(data).flatten.getOrElse(Configurations.Default) (p / defaultConfiguration).get(data).flatten.getOrElse(Configurations.Default)
val sbtIvySnapshots: URLRepository = Resolver.sbtIvyRepo("snapshots") val sbtIvySnapshots: URLRepository = Resolver.sbtIvyRepo("snapshots")
@ -4924,7 +4925,7 @@ trait BuildExtra extends BuildCommon with DefExtra {
def initScoped[T](sk: ScopedKey[?], i: Initialize[T]): Initialize[T] = def initScoped[T](sk: ScopedKey[?], i: Initialize[T]): Initialize[T] =
initScope(fillTaskAxis(sk.scope, sk.key), i) initScope(fillTaskAxis(sk.scope, sk.key), i)
def initScope[T](s: Scope, i: Initialize[T]): Initialize[T] = def initScope[T](s: Scope, i: Initialize[T]): Initialize[T] =
i.mapReferenced(Project.mapScope(Scope.replaceThis(s))) Project.inScope(s, i)
/** /**
* Disables post-compilation hook for determining tests for tab-completion (such as for 'test-only'). * Disables post-compilation hook for determining tests for tab-completion (such as for 'test-only').

View File

@ -449,8 +449,8 @@ object EvaluateTask {
ref: ProjectRef ref: ProjectRef
): Option[(Task[T], NodeView)] = { ): Option[(Task[T], NodeView)] = {
val thisScope = Load.projectScope(ref) val thisScope = Load.projectScope(ref)
val resolvedScope = Scope.replaceThis(thisScope)(taskKey.scope) val subScoped = Project.replaceThis(thisScope)(taskKey.scopedKey)
for (t <- structure.data.get(resolvedScope, taskKey.key)) for (t <- structure.data.get(subScoped))
yield (t, nodeView(state, streams, taskKey :: Nil)) yield (t, nodeView(state, streams, taskKey :: Nil))
} }
def nodeView( def nodeView(

View File

@ -12,7 +12,6 @@ import sbt.internal.{ Load, BuildStructure, Act, Aggregation, SessionSettings }
import Scope.GlobalScope import Scope.GlobalScope
import Def.{ ScopedKey, Setting } import Def.{ ScopedKey, Setting }
import sbt.internal.util.complete.Parser import sbt.internal.util.complete.Parser
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
@ -34,21 +33,21 @@ final case class Extracted(
* If the project axis is not explicitly specified, it is resolved to be the current project according to the extracted `session`. * If the project axis is not explicitly specified, it is resolved to be the current project according to the extracted `session`.
* Other axes are resolved to be `Zero` if they are not specified. * Other axes are resolved to be `Zero` if they are not specified.
*/ */
def get[T](key: SettingKey[T]): T = getOrError(inCurrent(key.scope), key.key) def get[T](key: SettingKey[T]): T = getOrError(inCurrent(key.scopedKey))
def get[T](key: TaskKey[T]): Task[T] = getOrError(inCurrent(key.scope), key.key) def get[T](key: TaskKey[T]): Task[T] = getOrError(inCurrent(key.scopedKey))
/** /**
* Gets the value assigned to `key` in the computed settings map wrapped in Some. If it does not exist, None is returned. * Gets the value assigned to `key` in the computed settings map wrapped in Some. If it does not exist, None is returned.
* If the project axis is not explicitly specified, it is resolved to be the current project according to the extracted `session`. * If the project axis is not explicitly specified, it is resolved to be the current project according to the extracted `session`.
* Other axes are resolved to be `Zero` if they are not specified. * Other axes are resolved to be `Zero` if they are not specified.
*/ */
def getOpt[T](key: SettingKey[T]): Option[T] = structure.data.get(inCurrent(key.scope), key.key) def getOpt[T](key: SettingKey[T]): Option[T] = structure.data.get(inCurrent(key.scopedKey))
def getOpt[T](key: TaskKey[T]): Option[Task[T]] = def getOpt[T](key: TaskKey[T]): Option[Task[T]] =
structure.data.get(inCurrent(key.scope), key.key) structure.data.get(inCurrent(key))
private def inCurrent(scope: Scope): Scope = private def inCurrent[T](key: ScopedKey[T]): ScopedKey[T] =
if scope.project == This then scope.rescope(currentRef) if key.scope.project == This then key.copy(scope = key.scope.rescope(currentRef))
else scope else key
/** /**
* Runs the task specified by `key` and returns the transformed State and the resulting value of the task. * Runs the task specified by `key` and returns the transformed State and the resulting value of the task.
@ -63,7 +62,7 @@ final case class Extracted(
val config = extractedTaskConfig(this, structure, state) val config = extractedTaskConfig(this, structure, state)
val value: Option[(State, Result[T])] = val value: Option[(State, Result[T])] =
EvaluateTask(structure, key.scopedKey, state, currentRef, config) EvaluateTask(structure, key.scopedKey, state, currentRef, config)
val (newS, result) = getOrError(rkey.scope, rkey.key, value) val (newS, result) = getOrError(rkey.scopedKey, value)
(newS, EvaluateTask.processResult2(result)) (newS, EvaluateTask.processResult2(result))
} }
@ -116,15 +115,15 @@ final case class Extracted(
private def resolve[K <: Scoped.ScopingSetting[K] & Scoped](key: K): K = private def resolve[K <: Scoped.ScopingSetting[K] & Scoped](key: K): K =
Scope.resolveScope(GlobalScope, currentRef.build, rootProject)(key.scope) / key Scope.resolveScope(GlobalScope, currentRef.build, rootProject)(key.scope) / key
private def getOrError[T](scope: Scope, key: AttributeKey[?], value: Option[T])(implicit private def getOrError[T](key: ScopedKey[?], value: Option[T])(implicit
display: Show[ScopedKey[?]] display: Show[ScopedKey[?]]
): T = ): T =
value getOrElse sys.error(display.show(ScopedKey(scope, key)) + " is undefined.") value.getOrElse(sys.error(display.show(key) + " is undefined."))
private def getOrError[T](scope: Scope, key: AttributeKey[T])(implicit private def getOrError[T](key: ScopedKey[T])(implicit
display: Show[ScopedKey[?]] display: Show[ScopedKey[?]]
): T = ): T =
getOrError(scope, key, structure.data.get(scope, key))(display) getOrError(key, structure.data.get(key))(display)
@deprecated( @deprecated(
"This discards session settings. Migrate to appendWithSession or appendWithoutSession.", "This discards session settings. Migrate to appendWithSession or appendWithoutSession.",

View File

@ -47,7 +47,7 @@ import sbt.internal.{
SettingGraph, SettingGraph,
SessionSettings SessionSettings
} }
import sbt.internal.util.{ AttributeKey, AttributeMap, Relation, Settings } import sbt.internal.util.{ AttributeKey, AttributeMap, Relation }
import sbt.internal.util.Types.const import sbt.internal.util.Types.const
import sbt.internal.server.ServerHandler import sbt.internal.server.ServerHandler
import sbt.librarymanagement.Configuration import sbt.librarymanagement.Configuration
@ -288,10 +288,10 @@ trait ProjectExtra extends Scoped.Syntax:
def orIdentity[A](opt: Option[A => A]): A => A = def orIdentity[A](opt: Option[A => A]): A => A =
opt.getOrElse(identity) opt.getOrElse(identity)
def getHook[A](key: SettingKey[A => A], data: Settings[Scope]): A => A = def getHook[A](key: SettingKey[A => A], data: Def.Settings): A => A =
orIdentity((Global / key).get(data)) orIdentity((Global / key).get(data))
def getHooks(data: Settings[Scope]): (State => State, State => State) = def getHooks(data: Def.Settings): (State => State, State => State) =
(getHook(Keys.onLoad, data), getHook(Keys.onUnload, data)) (getHook(Keys.onLoad, data), getHook(Keys.onUnload, data))
def current(state: State): ProjectRef = session(state).current def current(state: State): ProjectRef = session(state).current
@ -373,46 +373,34 @@ trait ProjectExtra extends Scoped.Syntax:
private[sbt] def scopedKeyData( private[sbt] def scopedKeyData(
structure: BuildStructure, structure: BuildStructure,
scope: Scope, key: ScopedKey[?]
key: AttributeKey[?]
): Option[ScopedKeyData[?]] = ): Option[ScopedKeyData[?]] =
structure.data.get(scope, key) map { v => structure.data.getKeyValue(key).map((defining, value) => ScopedKeyData(key, defining, value))
ScopedKeyData(ScopedKey(scope, key), v)
}
def details(structure: BuildStructure, actual: Boolean, scope: Scope, key: AttributeKey[?])( def details(structure: BuildStructure, actual: Boolean, key: ScopedKey[?])(using
using display: Show[ScopedKey[?]] display: Show[ScopedKey[?]]
): String = { ): String = {
val scoped = ScopedKey(scope, key) val data = scopedKeyData(structure, key).map(_.description).getOrElse("No entry for key.")
val description = key.key.description match
val data = scopedKeyData(structure, scope, key) map { _.description } getOrElse { case Some(desc) => s"Description:\n\t$desc\n"
"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 => "" case None => ""
}
val definingScoped = definingScope match { val (definingKey, providedBy) = structure.data.definingKey(key) match
case Some(sc) => ScopedKey(sc, key) case Some(k) => k -> s"Provided by:\n\t${Scope.display(k.scope, key.key.label)}\n"
case None => scoped case None => key -> ""
}
val comp = val comp =
Def.compiled(structure.settings, actual)(using Def.compiled(structure.settings, actual)(using
structure.delegates, structure.delegates,
structure.scopeLocal, structure.scopeLocal,
display display
) )
val definedAt = comp get definingScoped map { c => val definedAt = comp
Def.definedAtString(c.settings).capitalize .get(definingKey)
} getOrElse "" .map(c => Def.definedAtString(c.settings).capitalize)
.getOrElse("")
val cMap = Def.flattenLocals(comp) val cMap = Def.flattenLocals(comp)
val related = cMap.keys.filter(k => k.key == key && k.scope != scope) val related = cMap.keys.filter(k => k.key == key.key && k.scope != key.scope)
def derivedDependencies(c: ScopedKey[?]): List[ScopedKey[?]] = def derivedDependencies(c: ScopedKey[?]): List[ScopedKey[?]] =
comp comp
.get(c) .get(c)
@ -420,14 +408,14 @@ trait ProjectExtra extends Scoped.Syntax:
.toList .toList
.flatten .flatten
val depends = cMap.get(scoped) match { val depends = cMap.get(key) match
case Some(c) => c.dependencies.toSet; case None => Set.empty case Some(c) => c.dependencies.toSet
} case None => Set.empty
val derivedDepends: Set[ScopedKey[?]] = derivedDependencies(definingScoped).toSet val derivedDepends: Set[ScopedKey[?]] = derivedDependencies(definingKey).toSet
val reverse = Project.reverseDependencies(cMap, scoped) val reverse = Project.reverseDependencies(cMap, key)
val derivedReverse = val derivedReverse =
reverse.filter(r => derivedDependencies(r).contains(definingScoped)).toSet reverse.filter(r => derivedDependencies(r).contains(definingKey)).toSet
def printDepScopes( def printDepScopes(
baseLabel: String, baseLabel: String,
@ -460,7 +448,7 @@ trait ProjectExtra extends Scoped.Syntax:
definedAt + definedAt +
printDepScopes("Dependencies", "derived from", depends, derivedDepends) + printDepScopes("Dependencies", "derived from", depends, derivedDepends) +
printDepScopes("Reverse dependencies", "derives", reverse, derivedReverse) + printDepScopes("Reverse dependencies", "derives", reverse, derivedReverse) +
printScopes("Delegates", delegates(structure, scope, key)) + printScopes("Delegates", delegates(structure, key.scope, key.key)) +
printScopes("Related", related, 10) printScopes("Related", related, 10)
} }

View File

@ -11,16 +11,14 @@ package sbt
import Def.ScopedKey import Def.ScopedKey
import sbt.internal.util.KeyTag import sbt.internal.util.KeyTag
final case class ScopedKeyData[A](scoped: ScopedKey[A], value: Any) { final case class ScopedKeyData[A](key: ScopedKey[A], definingKey: ScopedKey[A], value: Any) {
val key = scoped.key def typeName: String = key.key.tag.toString
val scope = scoped.scope
def typeName: String = key.tag.toString
def settingValue: Option[Any] = def settingValue: Option[Any] =
key.tag match key.key.tag match
case KeyTag.Setting(_) => Some(value) case KeyTag.Setting(_) => Some(value)
case _ => None case _ => None
def description: String = def description: String =
key.tag match key.key.tag match
case KeyTag.Task(typeArg) => s"Task: $typeArg" case KeyTag.Task(typeArg) => s"Task: $typeArg"
case KeyTag.SeqTask(typeArg) => s"Task: Seq[$typeArg]" case KeyTag.SeqTask(typeArg) => s"Task: Seq[$typeArg]"
case KeyTag.InputTask(typeArg) => s"Input task: $typeArg" case KeyTag.InputTask(typeArg) => s"Input task: $typeArg"

View File

@ -58,11 +58,13 @@ object SessionVar {
key: ScopedKey[Task[T]], key: ScopedKey[Task[T]],
context: Scope, context: Scope,
state: State state: State
): ScopedKey[Task[T]] = { ): ScopedKey[Task[T]] =
val subScope = Scope.replaceThis(context)(key.scope) val subScoped = Project.replaceThis(context)(key)
val scope = Project.structure(state).data.definingScope(subScope, key.key) getOrElse subScope Project
ScopedKey(scope, key.key) .structure(state)
} .data
.definingKey(subScoped)
.getOrElse(subScoped)
def read[T](key: ScopedKey[Task[T]], state: State)(implicit f: JsonFormat[T]): Option[T] = def read[T](key: ScopedKey[Task[T]], state: State)(implicit f: JsonFormat[T]): Option[T] =
Project.structure(state).streams(state).use(key) { s => Project.structure(state).streams(state).use(key) { s =>

View File

@ -24,7 +24,6 @@ import sbt.internal.util.{
AttributeMap, AttributeMap,
IMap, IMap,
MessageOnlyException, MessageOnlyException,
Settings,
Util, Util,
} }
import sbt.util.Show import sbt.util.Show
@ -61,7 +60,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[?]],
data: Settings[Scope] data: Def.Settings
): Parser[ScopedKey[Any]] = ): Parser[ScopedKey[Any]] =
scopedKeySelected(index, current, defaultConfigs, keyMap, data, askProject = true) scopedKeySelected(index, current, defaultConfigs, keyMap, data, askProject = true)
.map(_.key.asInstanceOf[ScopedKey[Any]]) .map(_.key.asInstanceOf[ScopedKey[Any]])
@ -115,7 +114,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[?]],
data: Settings[Scope], data: Def.Settings,
askProject: Boolean, askProject: Boolean,
): Parser[ParsedKey] = ): Parser[ParsedKey] =
scopedKeyFull(index, current, defaultConfigs, keyMap, askProject = askProject).flatMap { scopedKeyFull(index, current, defaultConfigs, keyMap, askProject = askProject).flatMap {
@ -197,7 +196,7 @@ object Act {
key key
) )
def select(allKeys: Seq[Parser[ParsedKey]], data: Settings[Scope])(implicit def select(allKeys: Seq[Parser[ParsedKey]], data: Def.Settings)(implicit
show: Show[ScopedKey[?]] show: Show[ScopedKey[?]]
): Parser[ParsedKey] = ): Parser[ParsedKey] =
seq(allKeys) flatMap { ss => seq(allKeys) flatMap { ss =>
@ -235,10 +234,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: Def.Settings)(parsed: ParsedKey): Boolean = data.contains(parsed.key)
val key = parsed.key
data.definingScope(key.scope, key.key) == Some(key.scope)
}
def examples(p: Parser[String], exs: Set[String], label: String): Parser[String] = def examples(p: Parser[String], exs: Set[String], label: String): Parser[String] =
(p !!! ("Expected " + label)).examples(exs) (p !!! ("Expected " + label)).examples(exs)
@ -571,28 +567,14 @@ object Act {
def keyValues[T](extracted: Extracted)(keys: Seq[ScopedKey[T]]): Values[T] = def keyValues[T](extracted: Extracted)(keys: Seq[ScopedKey[T]]): Values[T] =
keyValues(extracted.structure)(keys) keyValues(extracted.structure)(keys)
def keyValues[T](structure: BuildStructure)(keys: Seq[ScopedKey[T]]): Values[T] = def keyValues[T](structure: BuildStructure)(keys: Seq[ScopedKey[T]]): Values[T] =
keys.flatMap { key => keys.flatMap(key => getValue(structure.data, key).map(KeyValue(key, _)))
getValue(structure.data, key.scope, key.key) map { value =>
KeyValue(key, value)
}
}
private def anyKeyValues(
structure: BuildStructure,
keys: Seq[ScopedKey[?]]
): Seq[KeyValue[?]] =
keys.flatMap { key =>
getValue(structure.data, key.scope, key.key) map { value =>
KeyValue(key, value)
}
}
private def getValue[T]( private def anyKeyValues(structure: BuildStructure, keys: Seq[ScopedKey[?]]): Seq[KeyValue[?]] =
data: Settings[Scope], keys.flatMap(key => getValue(structure.data, key).map(KeyValue(key, _)))
scope: Scope,
key: AttributeKey[T] private def getValue[T](data: Def.Settings, key: ScopedKey[T]): Option[T] =
): Option[T] = if (java.lang.Boolean.getBoolean("sbt.cli.nodelegation")) data.getDirect(key)
if (java.lang.Boolean.getBoolean("sbt.cli.nodelegation")) data.getDirect(scope, key) else data.get(key)
else data.get(scope, key)
def requireSession[T](s: State, p: => Parser[T]): Parser[T] = def requireSession[T](s: State, p: => Parser[T]): Parser[T] =
if s.get(sessionSettings).isEmpty then failure("No project loaded") else p if s.get(sessionSettings).isEmpty then failure("No project loaded") else p

View File

@ -11,7 +11,7 @@ package internal
import java.text.DateFormat import java.text.DateFormat
import sbt.Def.ScopedKey import sbt.Def.{ ScopedKey, Settings }
import sbt.Keys.{ showSuccess, showTiming, timingFormat } import sbt.Keys.{ showSuccess, showTiming, timingFormat }
import sbt.ProjectExtra.* import sbt.ProjectExtra.*
import sbt.SlashSyntax0.given import sbt.SlashSyntax0.given
@ -157,7 +157,7 @@ object Aggregation {
private def timingString( private def timingString(
startTime: Long, startTime: Long,
endTime: Long, endTime: Long,
data: Settings[Scope], data: Settings,
currentRef: ProjectRef, currentRef: ProjectRef,
): String = { ): String = {
val format = (currentRef / timingFormat).get(data) getOrElse defaultFormat val format = (currentRef / timingFormat).get(data) getOrElse defaultFormat
@ -301,7 +301,7 @@ object Aggregation {
ScopedKey(resolved, key.key) ScopedKey(resolved, key.key)
} }
def aggregationEnabled(key: ScopedKey[?], data: Settings[Scope]): Boolean = def aggregationEnabled(key: ScopedKey[?], data: Settings): Boolean =
(Scope.fillTaskAxis(key.scope, key.key) / Keys.aggregate).get(data).getOrElse(true) (Scope.fillTaskAxis(key.scope, key.key) / Keys.aggregate).get(data).getOrElse(true)
private[sbt] val suppressShow = private[sbt] val suppressShow =
AttributeKey[Boolean]("suppress-aggregation-show", Int.MaxValue) AttributeKey[Boolean]("suppress-aggregation-show", Int.MaxValue)

View File

@ -20,7 +20,7 @@ import sbt.SlashSyntax0.given
import BuildStreams.Streams import BuildStreams.Streams
import sbt.io.syntax._ import sbt.io.syntax._
import sbt.internal.inc.MappedFileConverter import sbt.internal.inc.MappedFileConverter
import sbt.internal.util.{ AttributeEntry, AttributeKey, AttributeMap, Attributed, Settings } import sbt.internal.util.{ AttributeEntry, AttributeKey, AttributeMap, Attributed }
import sbt.internal.util.Attributed.data import sbt.internal.util.Attributed.data
import sbt.util.Logger import sbt.util.Logger
import xsbti.FileConverter import xsbti.FileConverter
@ -29,7 +29,7 @@ final class BuildStructure(
val units: Map[URI, LoadedBuildUnit], val units: Map[URI, LoadedBuildUnit],
val root: URI, val root: URI,
val settings: Seq[Setting[?]], val settings: Seq[Setting[?]],
val data: Settings[Scope], val data: Def.Settings,
val index: StructureIndex, val index: StructureIndex,
val streams: State => Streams, val streams: State => Streams,
val delegates: Scope => Seq[Scope], val delegates: Scope => Seq[Scope],
@ -271,7 +271,7 @@ final class LoadedBuild(val root: URI, val units: Map[URI, LoadedBuildUnit]) {
unit.projects.map(p => ProjectRef(build, p.id) -> p) unit.projects.map(p => ProjectRef(build, p.id) -> p)
}.toIndexedSeq }.toIndexedSeq
def extra(data: Settings[Scope])(keyIndex: KeyIndex): BuildUtil[ResolvedProject] = def extra(data: Def.Settings)(keyIndex: KeyIndex): BuildUtil[ResolvedProject] =
BuildUtil(root, units, keyIndex, data) BuildUtil(root, units, keyIndex, data)
private[sbt] def autos = GroupedAutoPlugins(units) private[sbt] def autos = GroupedAutoPlugins(units)
@ -309,7 +309,7 @@ object BuildStreams {
def mkStreams( def mkStreams(
units: Map[URI, LoadedBuildUnit], units: Map[URI, LoadedBuildUnit],
root: URI, root: URI,
data: Settings[Scope] data: Def.Settings
): State => Streams = s => { ): State => Streams = s => {
s.get(Keys.stateStreams).getOrElse { s.get(Keys.stateStreams).getOrElse {
std.Streams( std.Streams(
@ -324,7 +324,7 @@ object BuildStreams {
} }
} }
def path(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope])( def path(units: Map[URI, LoadedBuildUnit], root: URI, data: Def.Settings)(
scoped: ScopedKey[?] scoped: ScopedKey[?]
): File = ): File =
resolvePath(projectPath(units, root, scoped, data), nonProjectPath(scoped)) resolvePath(projectPath(units, root, scoped, data), nonProjectPath(scoped))
@ -386,7 +386,7 @@ object BuildStreams {
units: Map[URI, LoadedBuildUnit], units: Map[URI, LoadedBuildUnit],
root: URI, root: URI,
scoped: ScopedKey[?], scoped: ScopedKey[?],
data: Settings[Scope] data: Def.Settings
): File = ): File =
scoped.scope.project match { scoped.scope.project match {
case Zero => refTarget(GlobalScope, units(root).localBase, data) / GlobalPath case Zero => refTarget(GlobalScope, units(root).localBase, data) / GlobalPath
@ -397,9 +397,9 @@ object BuildStreams {
case This => sys.error("Unresolved project reference (This) in " + displayFull(scoped)) case This => sys.error("Unresolved project reference (This) in " + displayFull(scoped))
} }
def refTarget(ref: ResolvedReference, fallbackBase: File, data: Settings[Scope]): File = def refTarget(ref: ResolvedReference, fallbackBase: File, data: Def.Settings): File =
refTarget(GlobalScope.copy(project = Select(ref)), fallbackBase, data) refTarget(GlobalScope.copy(project = Select(ref)), fallbackBase, data)
def refTarget(scope: Scope, fallbackBase: File, data: Settings[Scope]): File = def refTarget(scope: Scope, fallbackBase: File, data: Def.Settings): File =
((scope / Keys.target).get(data) getOrElse outputDirectory(fallbackBase)) / StreamsDirectory ((scope / Keys.target).get(data) getOrElse outputDirectory(fallbackBase)) / StreamsDirectory
} }

View File

@ -9,13 +9,13 @@
package sbt package sbt
package internal package internal
import sbt.internal.util.{ Relation, Settings, Dag } import sbt.internal.util.{ Relation, Dag }
import java.net.URI import java.net.URI
final class BuildUtil[Proj]( final class BuildUtil[Proj](
val keyIndex: KeyIndex, val keyIndex: KeyIndex,
val data: Settings[Scope], val data: Def.Settings,
val root: URI, val root: URI,
val rootProjectID: URI => String, val rootProjectID: URI => String,
val project: (URI, String) => Proj, val project: (URI, String) => Proj,
@ -57,7 +57,7 @@ object BuildUtil {
root: URI, root: URI,
units: Map[URI, LoadedBuildUnit], units: Map[URI, LoadedBuildUnit],
keyIndex: KeyIndex, keyIndex: KeyIndex,
data: Settings[Scope] data: Def.Settings
): BuildUtil[ResolvedProject] = { ): BuildUtil[ResolvedProject] = {
val getp = (build: URI, project: String) => Load.getProject(units, build, project) val getp = (build: URI, project: String) => Load.getProject(units, build, project)
val configs = (_: ResolvedProject).configurations.map(c => ConfigKey(c.name)) val configs = (_: ResolvedProject).configurations.map(c => ConfigKey(c.name))

View File

@ -15,7 +15,7 @@ import sbt.Keys._
import sbt.nio.Keys._ import sbt.nio.Keys._
import sbt.nio.file.{ Glob, RecursiveGlob } import sbt.nio.file.{ Glob, RecursiveGlob }
import sbt.Def.Initialize import sbt.Def.Initialize
import sbt.internal.util.{ Attributed, Dag, Settings } import sbt.internal.util.{ Attributed, Dag }
import sbt.librarymanagement.{ Configuration, TrackLevel } import sbt.librarymanagement.{ Configuration, TrackLevel }
import sbt.librarymanagement.Configurations.names import sbt.librarymanagement.Configurations.names
import sbt.std.TaskExtra._ import sbt.std.TaskExtra._
@ -180,7 +180,7 @@ private[sbt] object ClasspathImpl {
projectRef: ProjectRef, projectRef: ProjectRef,
conf: Configuration, conf: Configuration,
self: Configuration, self: Configuration,
data: Settings[Scope], data: Def.Settings,
deps: BuildDependencies, deps: BuildDependencies,
track: TrackLevel, track: TrackLevel,
log: Logger log: Logger
@ -198,7 +198,7 @@ private[sbt] object ClasspathImpl {
projectRef: ProjectRef, projectRef: ProjectRef,
conf: Configuration, conf: Configuration,
self: Configuration, self: Configuration,
data: Settings[Scope], data: Def.Settings,
deps: BuildDependencies, deps: BuildDependencies,
track: TrackLevel, track: TrackLevel,
log: Logger log: Logger
@ -244,7 +244,7 @@ private[sbt] object ClasspathImpl {
projectRef: ProjectRef, projectRef: ProjectRef,
conf: Configuration, conf: Configuration,
self: Configuration, self: Configuration,
data: Settings[Scope], data: Def.Settings,
deps: BuildDependencies, deps: BuildDependencies,
track: TrackLevel, track: TrackLevel,
log: Logger log: Logger
@ -282,7 +282,7 @@ private[sbt] object ClasspathImpl {
def unmanagedDependencies0( def unmanagedDependencies0(
projectRef: ProjectRef, projectRef: ProjectRef,
conf: Configuration, conf: Configuration,
data: Settings[Scope], data: Def.Settings,
deps: BuildDependencies, deps: BuildDependencies,
log: Logger log: Logger
): Initialize[Task[Classpath]] = ): Initialize[Task[Classpath]] =
@ -306,7 +306,7 @@ private[sbt] object ClasspathImpl {
def unmanagedLibs( def unmanagedLibs(
dep: ResolvedReference, dep: ResolvedReference,
conf: String, conf: String,
data: Settings[Scope] data: Def.Settings
): Task[Classpath] = ): Task[Classpath] =
getClasspath(unmanagedJars, dep, conf, data) getClasspath(unmanagedJars, dep, conf, data)
@ -315,7 +315,7 @@ private[sbt] object ClasspathImpl {
deps: BuildDependencies, deps: BuildDependencies,
conf: Configuration, conf: Configuration,
self: Configuration, self: Configuration,
data: Settings[Scope], data: Def.Settings,
track: TrackLevel, track: TrackLevel,
includeSelf: Boolean, includeSelf: Boolean,
log: Logger log: Logger
@ -346,7 +346,7 @@ private[sbt] object ClasspathImpl {
def interSort( def interSort(
projectRef: ProjectRef, projectRef: ProjectRef,
conf: Configuration, conf: Configuration,
data: Settings[Scope], data: Def.Settings,
deps: BuildDependencies deps: BuildDependencies
): Seq[(ProjectRef, String)] = ): Seq[(ProjectRef, String)] =
val visited = (new LinkedHashSet[(ProjectRef, String)]).asScala val visited = (new LinkedHashSet[(ProjectRef, String)]).asScala
@ -431,7 +431,7 @@ private[sbt] object ClasspathImpl {
def allConfigs(conf: Configuration): Seq[Configuration] = def allConfigs(conf: Configuration): Seq[Configuration] =
Dag.topologicalSort(conf)(_.extendsConfigs) Dag.topologicalSort(conf)(_.extendsConfigs)
def getConfigurations(p: ResolvedReference, data: Settings[Scope]): Seq[Configuration] = def getConfigurations(p: ResolvedReference, data: Def.Settings): Seq[Configuration] =
(p / ivyConfigurations).get(data).getOrElse(Nil) (p / ivyConfigurations).get(data).getOrElse(Nil)
def confOpt(configurations: Seq[Configuration], conf: String): Option[Configuration] = def confOpt(configurations: Seq[Configuration], conf: String): Option[Configuration] =
@ -441,14 +441,14 @@ private[sbt] object ClasspathImpl {
key: TaskKey[Seq[A]], key: TaskKey[Seq[A]],
dep: ResolvedReference, dep: ResolvedReference,
conf: Configuration, conf: Configuration,
data: Settings[Scope] data: Def.Settings
): Task[Seq[A]] = getClasspath(key, dep, conf.name, data) ): Task[Seq[A]] = getClasspath(key, dep, conf.name, data)
def getClasspath[A]( def getClasspath[A](
key: TaskKey[Seq[A]], key: TaskKey[Seq[A]],
dep: ResolvedReference, dep: ResolvedReference,
conf: String, conf: String,
data: Settings[Scope] data: Def.Settings
): Task[Seq[A]] = ): Task[Seq[A]] =
(dep / ConfigKey(conf) / key).get(data) match { (dep / ConfigKey(conf) / key).get(data) match {
case Some(x) => x case Some(x) => x

View File

@ -114,11 +114,9 @@ private[sbt] object Clean {
// This is the special portion of the task where we clear out the relevant streams // This is the special portion of the task where we clear out the relevant streams
// and file outputs of a task. // and file outputs of a task.
val streamsKey = scope.task.toOption.map(k => ScopedKey(scope.copy(task = Zero), k)) val streamsKey = scope.task.toOption.map(k => ScopedKey(scope.copy(task = Zero), k))
val stampKey = ScopedKey(scope, inputFileStamps.key)
val stampsKey = val stampsKey =
extracted.structure.data.getDirect(scope, inputFileStamps.key) match { if extracted.structure.data.contains(stampKey) then stampKey :: Nil else Nil
case Some(_) => ScopedKey(scope, inputFileStamps.key) :: Nil
case _ => Nil
}
val streamsGlobs = val streamsGlobs =
(streamsKey.toSeq ++ stampsKey) (streamsKey.toSeq ++ stampsKey)
.map(k => manager(k).cacheDirectory.toPath.toGlob / **) .map(k => manager(k).cacheDirectory.toPath.toGlob / **)

View File

@ -92,7 +92,7 @@ object GlobalPlugin {
(prods ++ intcp).distinct (prods ++ intcp).distinct
)(updateReport.value) )(updateReport.value)
} }
val resolvedTaskInit = taskInit.mapReferenced(Project.mapScope(Scope.replaceThis(p))) val resolvedTaskInit = taskInit.mapReferenced(Project.replaceThis(p))
val task = resolvedTaskInit.evaluate(data) val task = resolvedTaskInit.evaluate(data)
val roots = resolvedTaskInit.dependencies val roots = resolvedTaskInit.dependencies
evaluate(state, structure, task, roots) evaluate(state, structure, task, roots)

View File

@ -87,8 +87,7 @@ object Inspect {
val extracted = Project.extract(s) val extracted = Project.extract(s)
import extracted._ import extracted._
option match { option match {
case Details(actual) => case Details(actual) => Project.details(extracted.structure, actual, sk)
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 Project

View File

@ -94,7 +94,7 @@ object LintUnused {
} }
def lintResultLines( def lintResultLines(
result: Seq[(ScopedKey[?], String, Vector[SourcePosition])] result: Seq[(ScopedKey[?], String, Seq[SourcePosition])]
): Vector[String] = { ): Vector[String] = {
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
val buffer = ListBuffer.empty[String] val buffer = ListBuffer.empty[String]
@ -127,7 +127,7 @@ object LintUnused {
state: State, state: State,
includeKeys: String => Boolean, includeKeys: String => Boolean,
excludeKeys: String => Boolean excludeKeys: String => Boolean
): Seq[(ScopedKey[?], String, Vector[SourcePosition])] = { ): Seq[(ScopedKey[?], String, Seq[SourcePosition])] = {
val extracted = Project.extract(state) val extracted = Project.extract(state)
val structure = extracted.structure val structure = extracted.structure
val display = Def.showShortKey(None) // extracted.showKey val display = Def.showShortKey(None) // extracted.showKey
@ -135,17 +135,11 @@ object LintUnused {
val cMap = Def.flattenLocals(comp) val cMap = Def.flattenLocals(comp)
val used: Set[ScopedKey[?]] = cMap.values.flatMap(_.dependencies).toSet val used: Set[ScopedKey[?]] = cMap.values.flatMap(_.dependencies).toSet
val unused: Seq[ScopedKey[?]] = cMap.keys.filter(!used.contains(_)).toSeq val unused: Seq[ScopedKey[?]] = cMap.keys.filter(!used.contains(_)).toSeq
val withDefinedAts: Seq[UnusedKey] = unused map { u => val withDefinedAts: Seq[UnusedKey] = unused.map { u =>
val definingScope = structure.data.definingScope(u.scope, u.key) val data = Project.scopedKeyData(structure, u)
val definingScoped = definingScope match { val definedAt = comp.get(data.map(_.definingKey).getOrElse(u)) match
case Some(sc) => ScopedKey(sc, u.key) case Some(c) => definedAtString(c.settings)
case _ => u
}
val definedAt = comp.get(definingScoped) match {
case Some(c) => definedAtString(c.settings.toVector)
case _ => Vector.empty case _ => Vector.empty
}
val data = Project.scopedKeyData(structure, u.scope, u.key)
UnusedKey(u, definedAt, data) UnusedKey(u, definedAt, data)
} }
@ -167,18 +161,16 @@ object LintUnused {
&& isLocallyDefined(u) => && isLocallyDefined(u) =>
u u
} }
(unusedKeys map { u => unusedKeys.map(u => (u.scoped, display.show(u.scoped), u.positions)).sortBy(_._2)
(u.scoped, display.show(u.scoped), u.positions)
}).sortBy(_._2)
} }
private case class UnusedKey( private case class UnusedKey(
scoped: ScopedKey[?], scoped: ScopedKey[?],
positions: Vector[SourcePosition], positions: Seq[SourcePosition],
data: Option[ScopedKeyData[?]] data: Option[ScopedKeyData[?]]
) )
private def definedAtString(settings: Vector[Setting[?]]): Vector[SourcePosition] = { private def definedAtString(settings: Seq[Setting[?]]): Seq[SourcePosition] = {
settings flatMap { setting => settings flatMap { setting =>
setting.pos match { setting.pos match {
case NoPosition => Vector.empty case NoPosition => Vector.empty

View File

@ -21,7 +21,7 @@ import sbt.internal.inc.classpath.ClasspathUtil
import sbt.internal.inc.{ MappedFileConverter, ScalaInstance, ZincLmUtil, ZincUtil } import sbt.internal.inc.{ MappedFileConverter, ScalaInstance, ZincLmUtil, ZincUtil }
import sbt.internal.util.Attributed.data import sbt.internal.util.Attributed.data
import sbt.internal.util.Types.const import sbt.internal.util.Types.const
import sbt.internal.util.{ Attributed, Settings } import sbt.internal.util.Attributed
import sbt.internal.server.BuildServerEvalReporter import sbt.internal.server.BuildServerEvalReporter
import sbt.io.{ GlobFilter, IO } import sbt.io.{ GlobFilter, IO }
import sbt.librarymanagement.ivy.{ InlineIvyConfiguration, IvyDependencyResolution, IvyPaths } import sbt.librarymanagement.ivy.{ InlineIvyConfiguration, IvyDependencyResolution, IvyPaths }
@ -310,7 +310,7 @@ private[sbt] object Load {
(rootEval, bs) (rootEval, bs)
} }
private def checkTargets(data: Settings[Scope]): Option[String] = private def checkTargets(data: Def.Settings): Option[String] =
val dups = overlappingTargets(allTargets(data)) val dups = overlappingTargets(allTargets(data))
if (dups.isEmpty) None if (dups.isEmpty) None
else { else {
@ -323,7 +323,7 @@ private[sbt] object Load {
private def overlappingTargets(targets: Seq[(ProjectRef, File)]): Map[File, Seq[ProjectRef]] = private def overlappingTargets(targets: Seq[(ProjectRef, File)]): Map[File, Seq[ProjectRef]] =
targets.groupBy(_._2).view.filter(_._2.size > 1).mapValues(_.map(_._1)).toMap targets.groupBy(_._2).view.filter(_._2.size > 1).mapValues(_.map(_._1)).toMap
private def allTargets(data: Settings[Scope]): Seq[(ProjectRef, File)] = { private def allTargets(data: Def.Settings): Seq[(ProjectRef, File)] = {
import ScopeFilter._ import ScopeFilter._
val allProjects = ScopeFilter(Make.inAnyProject) val allProjects = ScopeFilter(Make.inAnyProject)
val targetAndRef = Def.setting { (Keys.thisProjectRef.value, Keys.target.value) } val targetAndRef = Def.setting { (Keys.thisProjectRef.value, Keys.target.value) }
@ -369,19 +369,19 @@ private[sbt] object Load {
if (isDummy(tk)) tk else Task(tk.info.set(Keys.taskDefinitionKey, key), tk.work) if (isDummy(tk)) tk else Task(tk.info.set(Keys.taskDefinitionKey, key), tk.work)
def structureIndex( def structureIndex(
data: Settings[Scope], data: Def.Settings,
settings: Seq[Setting[?]], settings: Seq[Setting[?]],
extra: KeyIndex => BuildUtil[?], extra: KeyIndex => BuildUtil[?],
projects: Map[URI, LoadedBuildUnit] projects: Map[URI, LoadedBuildUnit]
): StructureIndex = { ): StructureIndex = {
val keys = Index.allKeys(settings) val keys = Index.allKeys(settings)
val attributeKeys = Index.attributeKeys(data) ++ keys.map(_.key) val attributeKeys = data.attributeKeys ++ keys.map(_.key)
val scopedKeys = keys ++ data.allKeys((s, k) => ScopedKey(s, k)).toVector val scopedKeys = (keys ++ data.keys).toVector
val projectsMap = projects.view.mapValues(_.defined.keySet).toMap val projectsMap = projects.view.mapValues(_.defined.keySet).toMap
val configsMap: Map[String, Seq[Configuration]] = val configsMap: Map[String, Seq[Configuration]] =
projects.values.flatMap(bu => bu.defined map { case (k, v) => (k, v.configurations) }).toMap projects.values.flatMap(bu => bu.defined map { case (k, v) => (k, v.configurations) }).toMap
val keyIndex = KeyIndex(scopedKeys.toVector, projectsMap, configsMap) val keyIndex = KeyIndex(scopedKeys, projectsMap, configsMap)
val aggIndex = KeyIndex.aggregate(scopedKeys.toVector, extra(keyIndex), projectsMap, configsMap) val aggIndex = KeyIndex.aggregate(scopedKeys, extra(keyIndex), projectsMap, configsMap)
new StructureIndex( new StructureIndex(
Index.stringToKeyMap(attributeKeys), Index.stringToKeyMap(attributeKeys),
Index.taskToKeyMap(data), Index.taskToKeyMap(data),

View File

@ -22,7 +22,7 @@ import java.io.PrintWriter
sealed abstract class LogManager { sealed abstract class LogManager {
def apply( def apply(
data: Settings[Scope], data: Def.Settings,
state: State, state: State,
task: ScopedKey[?], task: ScopedKey[?],
writer: PrintWriter, writer: PrintWriter,
@ -30,20 +30,20 @@ sealed abstract class LogManager {
): ManagedLogger ): ManagedLogger
@deprecated("Use alternate apply that provides a LoggerContext", "1.4.0") @deprecated("Use alternate apply that provides a LoggerContext", "1.4.0")
def apply( def apply(
data: Settings[Scope], data: Def.Settings,
state: State, state: State,
task: ScopedKey[?], task: ScopedKey[?],
writer: PrintWriter writer: PrintWriter
): ManagedLogger = apply(data, state, task, writer, LoggerContext.globalContext) ): ManagedLogger = apply(data, state, task, writer, LoggerContext.globalContext)
def backgroundLog( def backgroundLog(
data: Settings[Scope], data: Def.Settings,
state: State, state: State,
task: ScopedKey[?], task: ScopedKey[?],
context: LoggerContext context: LoggerContext
): ManagedLogger ): ManagedLogger
@deprecated("Use alternate background log that provides a LoggerContext", "1.4.0") @deprecated("Use alternate background log that provides a LoggerContext", "1.4.0")
final def backgroundLog(data: Settings[Scope], state: State, task: ScopedKey[?]): ManagedLogger = final def backgroundLog(data: Def.Settings, state: State, task: ScopedKey[?]): ManagedLogger =
backgroundLog(data, state, task, LoggerContext.globalContext) backgroundLog(data, state, task, LoggerContext.globalContext)
} }
@ -62,7 +62,7 @@ object LogManager {
// This is called by mkStreams // This is called by mkStreams
// //
def construct( def construct(
data: Settings[Scope], data: Def.Settings,
state: State state: State
): (ScopedKey[?], PrintWriter) => ManagedLogger = ): (ScopedKey[?], PrintWriter) => ManagedLogger =
(task: ScopedKey[?], to: PrintWriter) => { (task: ScopedKey[?], to: PrintWriter) => {
@ -74,7 +74,7 @@ object LogManager {
@deprecated("Use alternate constructBackgroundLog that provides a LoggerContext", "1.8.0") @deprecated("Use alternate constructBackgroundLog that provides a LoggerContext", "1.8.0")
def constructBackgroundLog( def constructBackgroundLog(
data: Settings[Scope], data: Def.Settings,
state: State state: State
): ScopedKey[?] => ManagedLogger = { ): ScopedKey[?] => ManagedLogger = {
val context = state.get(Keys.loggerContext).getOrElse(LoggerContext.globalContext) val context = state.get(Keys.loggerContext).getOrElse(LoggerContext.globalContext)
@ -82,7 +82,7 @@ object LogManager {
} }
def constructBackgroundLog( def constructBackgroundLog(
data: Settings[Scope], data: Def.Settings,
state: State, state: State,
context: LoggerContext context: LoggerContext
): (ScopedKey[?]) => ManagedLogger = ): (ScopedKey[?]) => ManagedLogger =
@ -119,7 +119,7 @@ object LogManager {
extra: AppenderSupplier extra: AppenderSupplier
) extends LogManager { ) extends LogManager {
def apply( def apply(
data: Settings[Scope], data: Def.Settings,
state: State, state: State,
task: ScopedKey[?], task: ScopedKey[?],
to: PrintWriter, to: PrintWriter,
@ -137,7 +137,7 @@ object LogManager {
) )
def backgroundLog( def backgroundLog(
data: Settings[Scope], data: Def.Settings,
state: State, state: State,
task: ScopedKey[?], task: ScopedKey[?],
context: LoggerContext context: LoggerContext
@ -150,16 +150,16 @@ object LogManager {
// to change from global being the default to overriding, switch the order of state.get and data.get // to change from global being the default to overriding, switch the order of state.get and data.get
def getOr[T]( def getOr[T](
key: AttributeKey[T], key: AttributeKey[T],
data: Settings[Scope], data: Def.Settings,
scope: Scope, scope: Scope,
state: State, state: State,
default: T default: T
): T = ): T =
data.get(scope, key) orElse state.get(key) getOrElse default data.get(ScopedKey(scope, key)).orElse(state.get(key)).getOrElse(default)
@deprecated("Use defaultLogger that provides a LoggerContext", "1.4.0") @deprecated("Use defaultLogger that provides a LoggerContext", "1.4.0")
def defaultLogger( def defaultLogger(
data: Settings[Scope], data: Def.Settings,
state: State, state: State,
task: ScopedKey[?], task: ScopedKey[?],
console: Appender, console: Appender,
@ -170,7 +170,7 @@ object LogManager {
defaultLogger(data, state, task, console, backed, relay, extra, LoggerContext.globalContext) defaultLogger(data, state, task, console, backed, relay, extra, LoggerContext.globalContext)
// This is the main function that is used to generate the logger for tasks. // This is the main function that is used to generate the logger for tasks.
def defaultLogger( def defaultLogger(
data: Settings[Scope], data: Def.Settings,
state: State, state: State,
task: ScopedKey[?], task: ScopedKey[?],
console: Appender, console: Appender,
@ -242,7 +242,7 @@ object LogManager {
} }
def backgroundLog( def backgroundLog(
data: Settings[Scope], data: Def.Settings,
state: State, state: State,
task: ScopedKey[?], task: ScopedKey[?],
console: Appender, console: Appender,
@ -271,7 +271,7 @@ object LogManager {
// TODO: Fix this // TODO: Fix this
// if global logging levels are not explicitly set, set them from project settings // if global logging levels are not explicitly set, set them from project settings
// private[sbt] def setGlobalLogLevels(s: State, data: Settings[Scope]): State = // private[sbt] def setGlobalLogLevels(s: State, data: Def.Settings): State =
// if (hasExplicitGlobalLogLevels(s)) // if (hasExplicitGlobalLogLevels(s))
// s // s
// else { // else {

View File

@ -24,7 +24,8 @@ private[sbt] case class ProjectQuery(
val scalaMatches = val scalaMatches =
params.get(Keys.scalaBinaryVersion.key) match params.get(Keys.scalaBinaryVersion.key) match
case Some(expected) => case Some(expected) =>
val actualSbv = structure.data.get(Scope.ThisScope.rescope(p), scalaBinaryVersion.key) val actualSbv =
structure.data.get(Def.ScopedKey(Scope.ThisScope.rescope(p), scalaBinaryVersion.key))
actualSbv match actualSbv match
case Some(sbv) => sbv == expected case Some(sbv) => sbv == expected
case None => true case None => true

View File

@ -9,7 +9,7 @@
package sbt package sbt
package internal package internal
import sbt.internal.util.{ AttributeKey, complete, Relation, Settings, Util } import sbt.internal.util.{ AttributeKey, complete, Relation, Util }
import sbt.util.Show import sbt.util.Show
import sbt.librarymanagement.Configuration import sbt.librarymanagement.Configuration
@ -138,7 +138,7 @@ private[sbt] object SettingCompletions {
* The last part of the completion will generate a template for the value or function literal that will initialize the setting or task. * The last part of the completion will generate a template for the value or function literal that will initialize the setting or task.
*/ */
def settingParser( def settingParser(
settings: Settings[Scope], settings: Def.Settings,
rawKeyMap: Map[String, AttributeKey[?]], rawKeyMap: Map[String, AttributeKey[?]],
context: ResolvedProject, context: ResolvedProject,
): Parser[String] = { ): Parser[String] = {
@ -156,7 +156,7 @@ private[sbt] object SettingCompletions {
/** Parser for a Scope+AttributeKey (ScopedKey). */ /** Parser for a Scope+AttributeKey (ScopedKey). */
def scopedKeyParser( def scopedKeyParser(
keyMap: Map[String, AttributeKey[?]], keyMap: Map[String, AttributeKey[?]],
settings: Settings[Scope], settings: Def.Settings,
context: ResolvedProject context: ResolvedProject
): Parser[ScopedKey[?]] = { ): Parser[ScopedKey[?]] = {
val cutoff = KeyRanks.MainCutoff val cutoff = KeyRanks.MainCutoff
@ -195,15 +195,11 @@ private[sbt] object SettingCompletions {
*/ */
def scopeParser( def scopeParser(
key: AttributeKey[?], key: AttributeKey[?],
settings: Settings[Scope], settings: Def.Settings,
context: ResolvedProject context: ResolvedProject
): Parser[Scope] = { ): Parser[Scope] = {
val data = settings.data val definedScopes = settings.keys.collect { case sk if sk.key == key => sk.scope }
val allScopes = data.keys.toSeq scope(settings.scopes.toSeq, definedScopes.toSeq, context)
val definedScopes = data.toSeq flatMap { case (scope, attrs) =>
if attrs.contains(key) then scope :: Nil else Nil
}
scope(allScopes, definedScopes, context)
} }
private def scope( private def scope(

View File

@ -25,11 +25,8 @@ object SettingGraph {
compiled(structure.settings, false)(using 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 data = Project.scopedKeyData(structure, scoped)
val scope = scoped.scope val definedIn = data.map(d => display.show(d.definingKey))
val definedIn = structure.data.definingScope(scope, key) map { sc =>
display.show(ScopedKey(sc, key))
}
val depends = cMap.get(scoped) match { val depends = cMap.get(scoped) match {
case Some(c) => c.dependencies.toSet; case None => Set.empty case Some(c) => c.dependencies.toSet; case None => Set.empty
} }
@ -39,8 +36,8 @@ object SettingGraph {
SettingGraph( SettingGraph(
display.show(scoped), display.show(scoped),
definedIn, definedIn,
Project.scopedKeyData(structure, scope, key), data,
key.description, scoped.key.description,
basedir, basedir,
depends map { (x: ScopedKey[?]) => depends map { (x: ScopedKey[?]) =>
loop(x, generation + 1) loop(x, generation + 1)

View File

@ -16,7 +16,6 @@ import sbt.ProjectExtra.*
import sbt.SlashSyntax0.given import sbt.SlashSyntax0.given
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.complete.Parser import sbt.internal.util.complete.Parser
import sbt.nio.FileStamper import sbt.nio.FileStamper
import sbt.nio.Keys._ import sbt.nio.Keys._
@ -54,7 +53,7 @@ private[sbt] object WatchTransitiveDependencies {
val state: State val state: State
) { ) {
def structure: BuildStructure = extracted.structure def structure: BuildStructure = extracted.structure
def data: Map[Scope, AttributeMap] = extracted.structure.data.data def data: Settings = extracted.structure.data
} }
private def argumentsImpl( private def argumentsImpl(
@ -113,19 +112,19 @@ private[sbt] object WatchTransitiveDependencies {
val keys = collectKeys(args, allKeys, Set.empty, Set.empty) val keys = collectKeys(args, allKeys, Set.empty, Set.empty)
def getDynamicInputs(scopedKey: ScopedKey[Seq[Glob]], trigger: Boolean): Seq[DynamicInput] = { def getDynamicInputs(scopedKey: ScopedKey[Seq[Glob]], trigger: Boolean): Seq[DynamicInput] = {
data data
.get(scopedKey.scope) .getDirect(scopedKey)
.map { am => .map { globs =>
am.get(scopedKey.key) match {
case Some(globs: Seq[Glob]) =>
if (!trigger) { if (!trigger) {
val stamper = am.get(inputFileStamper.key).getOrElse(FileStamper.Hash) val stamper =
val forceTrigger = am.get(watchForceTriggerOnAnyChange.key).getOrElse(false) data.getDirect(scopedKey.copy(key = inputFileStamper.key)).getOrElse(FileStamper.Hash)
val forceTrigger =
data
.getDirect(scopedKey.copy(key = watchForceTriggerOnAnyChange.key))
.getOrElse(false)
globs.map(g => DynamicInput(g, stamper, forceTrigger)) globs.map(g => DynamicInput(g, stamper, forceTrigger))
} else { } else {
globs.map(g => DynamicInput(g, FileStamper.LastModified, forceTrigger = true)) globs.map(g => DynamicInput(g, FileStamper.LastModified, forceTrigger = true))
} }
case None => Nil: Seq[DynamicInput]
}
} }
.getOrElse(Nil) .getOrElse(Nil)
} }
@ -148,21 +147,15 @@ private[sbt] object WatchTransitiveDependencies {
.toIndexedSeq .toIndexedSeq
val projects = projectScopes.flatMap(_.project.toOption).distinct.toSet val projects = projectScopes.flatMap(_.project.toOption).distinct.toSet
val scopes: Seq[Either[Scope, Seq[Glob]]] = val scopes: Seq[Either[Scope, Seq[Glob]]] =
data.flatMap { case (s, am) => data.scopes.toSeq
if (s == Scope.Global || s.project.toOption.exists(projects.contains)) .filter(s => s == Scope.Global || s.project.toOption.exists(projects.contains))
am.get(Keys.watchSources.key) match { .flatMap { s =>
case Some(k) => data.getDirect(ScopedKey(s, Keys.watchSources.key)).map { task =>
k.work match { task.work match
// Avoid extracted.runTask if possible. case a: Action.Pure[Seq[Watched.WatchSource]] => Right(a.f().map(_.toGlob))
case Action.Pure(w, _) => Some(Right(w().map(_.toGlob))) case _ => Left(s)
case _ => Some(Left(s))
} }
case _ => None
} }
else {
None
}
}.toSeq
def toDynamicInput(glob: Glob): DynamicInput = def toDynamicInput(glob: Glob): DynamicInput =
DynamicInput(glob, FileStamper.LastModified, forceTrigger = true) DynamicInput(glob, FileStamper.LastModified, forceTrigger = true)
scopes.flatMap { scopes.flatMap {

View File

@ -19,7 +19,7 @@ import sjsonnew._
import sjsonnew.support.scalajson.unsafe._ import sjsonnew.support.scalajson.unsafe._
object SettingQuery { object SettingQuery {
import sbt.internal.util.{ AttributeKey, Settings } import sbt.internal.util.AttributeKey
import sbt.internal.util.complete.{ DefaultParsers, Parser }, DefaultParsers._ import sbt.internal.util.complete.{ DefaultParsers, Parser }, DefaultParsers._
import sbt.Def.{ showBuildRelativeKey2, ScopedKey } import sbt.Def.{ showBuildRelativeKey2, ScopedKey }
@ -70,7 +70,7 @@ object SettingQuery {
currentBuild: URI, currentBuild: URI,
defaultConfigs: Option[ResolvedReference] => Seq[String], defaultConfigs: Option[ResolvedReference] => Seq[String],
keyMap: Map[String, AttributeKey[?]], keyMap: Map[String, AttributeKey[?]],
data: Settings[Scope] data: Def.Settings
): Parser[ParsedKey] = ): Parser[ParsedKey] =
scopedKeyFull(index, currentBuild, defaultConfigs, keyMap) flatMap { choices => scopedKeyFull(index, currentBuild, defaultConfigs, keyMap) flatMap { choices =>
Act.select(choices, data)(showBuildRelativeKey2(currentBuild)) Act.select(choices, data)(showBuildRelativeKey2(currentBuild))
@ -81,7 +81,7 @@ object SettingQuery {
currentBuild: URI, currentBuild: URI,
defaultConfigs: Option[ResolvedReference] => Seq[String], defaultConfigs: Option[ResolvedReference] => Seq[String],
keyMap: Map[String, AttributeKey[?]], keyMap: Map[String, AttributeKey[?]],
data: Settings[Scope] data: Def.Settings
): Parser[ScopedKey[?]] = ): Parser[ScopedKey[?]] =
scopedKeySelected(index, currentBuild, defaultConfigs, keyMap, data).map(_.key) scopedKeySelected(index, currentBuild, defaultConfigs, keyMap, data).map(_.key)
@ -96,7 +96,7 @@ object SettingQuery {
def getSettingValue[A](structure: BuildStructure, key: Def.ScopedKey[A]): Either[String, A] = def getSettingValue[A](structure: BuildStructure, key: Def.ScopedKey[A]): Either[String, A] =
structure.data structure.data
.get(key.scope, key.key) .get(key)
.toRight(s"Key ${Def.displayFull(key)} not found") .toRight(s"Key ${Def.displayFull(key)} not found")
.flatMap { .flatMap {
case _: Task[_] => Left(s"Key ${Def.displayFull(key)} is a task, can only query settings") case _: Task[_] => Left(s"Key ${Def.displayFull(key)} is a task, can only query settings")

View File

@ -17,7 +17,6 @@ import sbt.internal.util.{
ConsoleOut, ConsoleOut,
GlobalLogging, GlobalLogging,
MainAppender, MainAppender,
Settings,
Terminal, Terminal,
} }
import sbt.internal.inc.PlainVirtualFileConverter import sbt.internal.inc.PlainVirtualFileConverter
@ -97,7 +96,7 @@ object FakeState {
val delegates: (Scope) => Seq[Scope] = _ => Nil val delegates: (Scope) => Seq[Scope] = _ => Nil
val scopeLocal: Def.ScopeLocal = _ => Nil val scopeLocal: Def.ScopeLocal = _ => Nil
val (cMap, data: Settings[Scope]) = val (cMap, data: Def.Settings) =
Def.makeWithCompiledMap(settings)(using 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)

View File

@ -10,7 +10,7 @@ package sbt
package internal package internal
import Def.{ ScopedKey, Setting } import Def.{ ScopedKey, Setting }
import sbt.internal.util.{ AttributeKey, AttributeMap, Relation, Settings } import sbt.internal.util.{ AttributeKey, Relation }
import sbt.internal.util.Types.{ const, some } import sbt.internal.util.Types.{ const, some }
import sbt.internal.util.complete.Parser import sbt.internal.util.complete.Parser
import sbt.librarymanagement.Configuration import sbt.librarymanagement.Configuration
@ -59,17 +59,18 @@ abstract class TestBuild {
sealed case class Structure( sealed case class Structure(
env: Env, env: Env,
current: ProjectRef, current: ProjectRef,
data: Settings[Scope], data: Def.Settings,
keyIndex: KeyIndex, keyIndex: KeyIndex,
keyMap: Map[String, AttributeKey[?]] keyMap: Map[String, AttributeKey[?]]
) { ) {
override def toString = override def toString =
env.toString + "\n" + "current: " + current + "\nSettings:\n\t" + showData + keyMap.keys env.toString + "\n" + "current: " + current + "\nSettings:\n\t" + showData + keyMap.keys
.mkString("All keys:\n\t", ", ", "") .mkString("All keys:\n\t", ", ", "")
def showKeys(map: AttributeMap): String = map.keys.mkString("\n\t ", ",", "\n") def showKeys(keys: Iterable[AttributeKey[?]]): String = keys.mkString("\n\t ", ",", "\n")
def showData: String = { def showData: String = {
val scopeStrings = val scopeStrings =
for ((scope, map) <- data.data) yield (Scope.display(scope, "<key>"), showKeys(map)) for (scope, keys) <- data.keys.groupMap(_.scope)(_.key)
yield (Scope.display(scope, "<key>"), showKeys(keys))
scopeStrings.toSeq.sorted.map(t => t._1 + t._2).mkString("\n\t") scopeStrings.toSeq.sorted.map(t => t._1 + t._2).mkString("\n\t")
} }
val extra: BuildUtil[Proj] = { val extra: BuildUtil[Proj] = {
@ -86,11 +87,10 @@ abstract class TestBuild {
} }
lazy val allAttributeKeys: Set[AttributeKey[?]] = { lazy val allAttributeKeys: Set[AttributeKey[?]] = {
val x = data.data.values.flatMap(_.keys).toSet if (data.attributeKeys.isEmpty) {
if (x.isEmpty) {
sys.error("allAttributeKeys is empty") sys.error("allAttributeKeys is empty")
} }
x data.attributeKeys
} }
lazy val (taskAxes, zeroTaskAxis, onlyTaskAxis, multiTaskAxis) = { lazy val (taskAxes, zeroTaskAxis, onlyTaskAxis, multiTaskAxis) = {
import collection.mutable import collection.mutable
@ -98,11 +98,10 @@ abstract class TestBuild {
// task axis of Scope is set to Zero and the value of the second map is the original task axis // task axis of Scope is set to Zero and the value of the second map is the original task axis
val taskAxesMappings = val taskAxesMappings =
for ((scope, keys) <- data.data; key <- keys.keys) for
yield (ScopedKey(scope.copy(task = Zero), key), scope.task): ( (scope, keys) <- data.keys.groupMap(_.scope)(_.key)
ScopedKey[?], key <- keys
ScopeAxis[AttributeKey[?]] yield (ScopedKey(scope.copy(task = Zero), key), scope.task)
)
val taskAxes = Relation.empty ++ taskAxesMappings val taskAxes = Relation.empty ++ taskAxesMappings
val zero = new HashSet[ScopedKey[?]] val zero = new HashSet[ScopedKey[?]]
@ -240,15 +239,14 @@ abstract class TestBuild {
} }
} }
val data = Def.makeWithCompiledMap(settings)(using env.delegates, const(Nil), display)._2 val data = Def.makeWithCompiledMap(settings)(using env.delegates, const(Nil), display)._2
val keys = data.allKeys((s, key) => ScopedKey(s, key)) val keyMap = data.keys.map(k => (k.key.label, k.key)).toMap[String, AttributeKey[?]]
val keyMap = keys.map(k => (k.key.label, k.key)).toMap[String, AttributeKey[?]]
val projectsMap = env.builds.map(b => (b.uri, b.projects.map(_.id).toSet)).toMap val projectsMap = env.builds.map(b => (b.uri, b.projects.map(_.id).toSet)).toMap
val confs = for { val confs = for {
b <- env.builds b <- env.builds
p <- b.projects p <- b.projects
} yield p.id -> p.configurations } yield p.id -> p.configurations
val confMap = confs.toMap val confMap = confs.toMap
Structure(env, current, data, KeyIndex(keys, projectsMap, confMap), keyMap) Structure(env, current, data, KeyIndex(data.keys, projectsMap, confMap), keyMap)
} }
lazy val mkEnv: Gen[Env] = { lazy val mkEnv: Gen[Env] = {

View File

@ -9,6 +9,7 @@
package sbt package sbt
trait Import { trait Import {
type Settings = Def.Settings
type Setting[T] = Def.Setting[T] type Setting[T] = Def.Setting[T]
type ScopedKey[T] = Def.ScopedKey[T] type ScopedKey[T] = Def.ScopedKey[T]
type SettingsDefinition = Def.SettingsDefinition type SettingsDefinition = Def.SettingsDefinition
@ -146,7 +147,7 @@ trait Import {
// type Dag[A <: Dag[A]] = sbt.internal.util.Dag[A] // type Dag[A <: Dag[A]] = sbt.internal.util.Dag[A]
type DelegatingPMap[K[_], V[_]] = sbt.internal.util.DelegatingPMap[K, V] type DelegatingPMap[K[_], V[_]] = sbt.internal.util.DelegatingPMap[K, V]
val ErrorHandling = sbt.internal.util.ErrorHandling val ErrorHandling = sbt.internal.util.ErrorHandling
type EvaluateSettings[S] = sbt.internal.util.EvaluateSettings[S] // type EvaluateSettings[I <: Init] = sbt.internal.util.EvaluateSettings[I]
val EvaluationState = sbt.internal.util.EvaluationState val EvaluationState = sbt.internal.util.EvaluationState
val ExitHook = sbt.internal.util.ExitHook val ExitHook = sbt.internal.util.ExitHook
type ExitHook = sbt.internal.util.ExitHook type ExitHook = sbt.internal.util.ExitHook
@ -168,7 +169,7 @@ trait Import {
type IDSet[T] = sbt.internal.util.IDSet[T] type IDSet[T] = sbt.internal.util.IDSet[T]
val IMap = sbt.internal.util.IMap val IMap = sbt.internal.util.IMap
type IMap[K[_], V[_]] = sbt.internal.util.IMap[K, V] type IMap[K[_], V[_]] = sbt.internal.util.IMap[K, V]
type Init[S] = sbt.internal.util.Init[S] type Init = sbt.internal.util.Init
type JLine = sbt.internal.util.JLine type JLine = sbt.internal.util.JLine
// val KCons = sbt.internal.util.KCons // val KCons = sbt.internal.util.KCons
// type KCons[H, +T <: KList[M], +M[_]] = sbt.internal.util.KCons[H, T, M] // type KCons[H, +T <: KList[M], +M[_]] = sbt.internal.util.KCons[H, T, M]
@ -193,7 +194,6 @@ trait Import {
val Relation = sbt.internal.util.Relation val Relation = sbt.internal.util.Relation
type Relation[A, B] = sbt.internal.util.Relation[A, B] type Relation[A, B] = sbt.internal.util.Relation[A, B]
val ScalaKeywords = sbt.internal.util.ScalaKeywords val ScalaKeywords = sbt.internal.util.ScalaKeywords
type Settings[S] = sbt.internal.util.Settings[S]
type SharedAttributeKey[T] = sbt.internal.util.SharedAttributeKey[T] type SharedAttributeKey[T] = sbt.internal.util.SharedAttributeKey[T]
val Signals = sbt.internal.util.Signals val Signals = sbt.internal.util.Signals
val SimpleReader = sbt.internal.util.SimpleReader val SimpleReader = sbt.internal.util.SimpleReader

View File

@ -20,13 +20,12 @@ enum EvaluationState:
case Calling case Calling
case Evaluated case Evaluated
abstract class EvaluateSettings[ScopeType]: class EvaluateSettings[I <: Init](
protected val init: Init[ScopeType] val init: I,
executor: Executor,
compiledSettings: Seq[init.Compiled[?]],
):
import init._ import init._
protected def executor: Executor
protected def compiledSettings: Seq[Compiled[?]]
import EvaluationState.* import EvaluationState.*
private val complete = new LinkedBlockingQueue[Option[Throwable]] private val complete = new LinkedBlockingQueue[Option[Throwable]]
@ -68,7 +67,7 @@ abstract class EvaluateSettings[ScopeType]:
private val running = new AtomicInteger private val running = new AtomicInteger
private val cancel = new AtomicBoolean(false) private val cancel = new AtomicBoolean(false)
def run(implicit delegates: ScopeType => Seq[ScopeType]): Settings[ScopeType] = { def run(implicit delegates: ScopeType => Seq[ScopeType]): Settings = {
assert(running.get() == 0, "Already running") assert(running.get() == 0, "Already running")
startWork() startWork()
roots.foreach(_.registerIfNew()) roots.foreach(_.registerIfNew())
@ -83,7 +82,7 @@ abstract class EvaluateSettings[ScopeType]:
private def getResults(implicit delegates: ScopeType => Seq[ScopeType]) = private def getResults(implicit delegates: ScopeType => Seq[ScopeType]) =
static.toTypedSeq.foldLeft(empty) { case (ss, static.TPair(key, node)) => static.toTypedSeq.foldLeft(empty) { case (ss, static.TPair(key, node)) =>
if key.key.isLocal then ss if key.key.isLocal then ss
else ss.set(key.scope, key.key, node.get) else ss.set(key, node.get)
} }
private lazy val getValue: [A] => INode[A] => A = [A] => (fa: INode[A]) => fa.get private lazy val getValue: [A] => INode[A] => A = [A] => (fa: INode[A]) => fa.get

View File

@ -12,53 +12,10 @@ import sbt.util.Show
import Util.{ nil, nilSeq } import Util.{ nil, nilSeq }
import scala.jdk.CollectionConverters.* import scala.jdk.CollectionConverters.*
sealed trait Settings[ScopeType]: // delegates should contain the input ScopeType as the first entry
def data: Map[ScopeType, AttributeMap]
def keys(scope: ScopeType): Set[AttributeKey[?]]
def scopes: Set[ScopeType]
def definingScope(scope: ScopeType, key: AttributeKey[?]): Option[ScopeType]
def allKeys[A](f: (ScopeType, AttributeKey[?]) => A): Seq[A]
def get[A](scope: ScopeType, key: AttributeKey[A]): Option[A]
def getDirect[A](scope: ScopeType, key: AttributeKey[A]): Option[A]
def set[A](scope: ScopeType, key: AttributeKey[A], value: A): Settings[ScopeType]
end Settings
private final class Settings0[ScopeType](
val data: Map[ScopeType, AttributeMap],
val delegates: ScopeType => Seq[ScopeType]
) extends Settings[ScopeType]:
def scopes: Set[ScopeType] = data.keySet
def keys(scope: ScopeType) = data(scope).keys.toSet
def allKeys[A](f: (ScopeType, AttributeKey[?]) => A): Seq[A] =
data.flatMap { case (scope, map) =>
map.keys.map(k => f(scope, k))
}.toSeq
def get[A](scope: ScopeType, key: AttributeKey[A]): Option[A] =
delegates(scope).flatMap { sc =>
getDirect(sc, key)
}.headOption
def definingScope(scope: ScopeType, key: AttributeKey[?]): Option[ScopeType] =
delegates(scope).find { sc =>
getDirect(sc, key).isDefined
}
def getDirect[A](scope: ScopeType, key: AttributeKey[A]): Option[A] =
data.get(scope).flatMap(_.get(key))
def set[A](scope: ScopeType, key: AttributeKey[A], value: A): Settings[ScopeType] =
val map = data.getOrElse(scope, AttributeMap.empty)
val newData = data.updated(scope, map.put(key, value))
Settings0(newData, delegates)
end Settings0
// delegates should contain the input Scope as the first entry
// this trait is intended to be mixed into an object // this trait is intended to be mixed into an object
trait Init[ScopeType]: trait Init:
type ScopeType
/** /**
* The Show instance used when a detailed String needs to be generated. * The Show instance used when a detailed String needs to be generated.
@ -80,6 +37,58 @@ trait Init[ScopeType]:
type ScopeLocal = ScopedKey[?] => Seq[Setting[?]] type ScopeLocal = ScopedKey[?] => Seq[Setting[?]]
type MapConstant = [a] => ScopedKey[a] => Option[a] type MapConstant = [a] => ScopedKey[a] => Option[a]
sealed trait Settings:
def attributeKeys: Set[AttributeKey[?]]
def keys: Iterable[ScopedKey[?]]
def contains(key: ScopedKey[?]): Boolean
def values: Iterable[Any]
def data: Map[ScopedKey[?], Any]
def scopes: Set[ScopeType]
def getKeyValue[A](key: ScopedKey[A]): Option[(ScopedKey[A], A)]
def get[A](key: ScopedKey[A]): Option[A]
def definingKey[A](key: ScopedKey[A]): Option[ScopedKey[A]]
def getDirect[A](key: ScopedKey[A]): Option[A]
def set[A](key: ScopedKey[A], value: A): Settings
end Settings
private final class Settings0(
val scopes: Set[ScopeType],
val attributeKeys: Set[AttributeKey[?]],
// In 1.x it was a Map[Scope, AttributeMap]
// For the heap, it is better to store the ScopedKey[?] directly to avoid recreating
// abd duplicating them later.
val data: Map[ScopedKey[?], Any],
d: ScopeType => Seq[ScopeType]
) extends Settings:
def keys: Iterable[ScopedKey[?]] = data.keys
def contains(key: ScopedKey[?]): Boolean = data.contains(key)
def values: Iterable[Any] = data.values
def get[A](key: ScopedKey[A]): Option[A] =
delegates(key).flatMap(data.get).nextOption.asInstanceOf[Option[A]]
def definingKey[A](key: ScopedKey[A]): Option[ScopedKey[A]] =
delegates(key).find(data.contains)
def getKeyValue[A](key: ScopedKey[A]): Option[(ScopedKey[A], A)] =
delegates(key).flatMap { k =>
data.get(k) match
case None => None
case Some(v) => Some(k -> v.asInstanceOf[A])
}.nextOption
def getDirect[A](key: ScopedKey[A]): Option[A] = data.get(key).asInstanceOf[Option[A]]
def set[A](key: ScopedKey[A], value: A): Settings =
val newScopes = scopes + key.scope
val newAttributeKeys = attributeKeys + key.key
val newData = data.updated(key, value)
Settings0(newScopes, newAttributeKeys, newData, d)
private def delegates[A](key: ScopedKey[A]): Iterator[ScopedKey[A]] =
d(key.scope).iterator.map(s => key.copy(scope = s))
end Settings0
private[sbt] abstract class ValidateKeyRef { private[sbt] abstract class ValidateKeyRef {
def apply[T](key: ScopedKey[T], selfRefOk: Boolean): ValidatedRef[T] def apply[T](key: ScopedKey[T], selfRefOk: Boolean): ValidatedRef[T]
} }
@ -163,16 +172,16 @@ trait Init[ScopeType]:
private final val nextID = new java.util.concurrent.atomic.AtomicLong private final val nextID = new java.util.concurrent.atomic.AtomicLong
private final def nextDefaultID(): Long = nextID.incrementAndGet() private final def nextDefaultID(): Long = nextID.incrementAndGet()
def empty(implicit delegates: ScopeType => Seq[ScopeType]): Settings[ScopeType] = def empty(implicit delegates: ScopeType => Seq[ScopeType]): Settings =
Settings0(Map.empty, delegates) Settings0(Set.empty, Set.empty, Map.empty, delegates)
def asTransform(s: Settings[ScopeType]): [A] => ScopedKey[A] => A = def asTransform(s: Settings): [A] => ScopedKey[A] => A =
[A] => (sk: ScopedKey[A]) => getValue(s, sk) [A] => (sk: ScopedKey[A]) => getValue(s, sk)
def getValue[T](s: Settings[ScopeType], k: ScopedKey[T]) = def getValue[T](s: Settings, k: ScopedKey[T]) =
s.get(k.scope, k.key) getOrElse (throw new InvalidReference(k)) s.get(k).getOrElse(throw new InvalidReference(k))
def asFunction[A](s: Settings[ScopeType]): ScopedKey[A] => A = k => getValue(s, k) def asFunction[A](s: Settings): ScopedKey[A] => A = k => getValue(s, k)
def mapScope(f: ScopeType => ScopeType): MapScoped = def mapScope(f: ScopeType => ScopeType): MapScoped =
[a] => (k: ScopedKey[a]) => k.copy(scope = f(k.scope)) [a] => (k: ScopedKey[a]) => k.copy(scope = f(k.scope))
@ -197,7 +206,7 @@ trait Init[ScopeType]:
// inject derived settings into scopes where their dependencies are directly defined // inject derived settings into scopes where their dependencies are directly defined
// and prepend per-scope settings // and prepend per-scope settings
val derived = deriveAndLocal(initDefaults, mkDelegates(delegates)) val derived = deriveAndLocal(initDefaults, mkDelegates(delegates))
// group by Scope/Key, dropping dead initializations // group by ScopeType/Key, dropping dead initializations
val sMap: ScopedMap = grouped(derived) val sMap: ScopedMap = grouped(derived)
// delegate references to undefined values according to 'delegates' // delegate references to undefined values according to 'delegates'
val dMap: ScopedMap = val dMap: ScopedMap =
@ -211,13 +220,13 @@ trait Init[ScopeType]:
delegates: ScopeType => Seq[ScopeType], delegates: ScopeType => Seq[ScopeType],
scopeLocal: ScopeLocal, scopeLocal: ScopeLocal,
display: Show[ScopedKey[?]] display: Show[ScopedKey[?]]
): Settings[ScopeType] = makeWithCompiledMap(init)._2 ): Settings = makeWithCompiledMap(init)._2
def makeWithCompiledMap(init: Seq[Setting[?]])(using def makeWithCompiledMap(init: Seq[Setting[?]])(using
delegates: ScopeType => Seq[ScopeType], delegates: ScopeType => Seq[ScopeType],
scopeLocal: ScopeLocal, scopeLocal: ScopeLocal,
display: Show[ScopedKey[?]] display: Show[ScopedKey[?]]
): (CompiledMap, Settings[ScopeType]) = ): (CompiledMap, Settings) =
val cMap = compiled(init)(using delegates, scopeLocal, display) val cMap = compiled(init)(using delegates, scopeLocal, display)
// order the initializations. cyclic references are detected here. // order the initializations. cyclic references are detected here.
val ordered: Seq[Compiled[?]] = sort(cMap) val ordered: Seq[Compiled[?]] = sort(cMap)
@ -235,16 +244,14 @@ trait Init[ScopeType]:
def compile(sMap: ScopedMap): CompiledMap = def compile(sMap: ScopedMap): CompiledMap =
sMap match sMap match
case m: IMap.IMap0[ScopedKey, SettingSeq] @unchecked => case m: IMap.IMap0[ScopedKey, SettingSeq] @unchecked =>
Par(m.backing.toVector) import scala.collection.parallel.CollectionConverters.*
m.backing.par
.map { case (k, ss) => .map { case (k, ss) =>
val deps = ss.flatMap(_.dependencies).toSet val deps = ss.iterator.flatMap(_.dependencies).toSet
( k -> Compiled(k.asInstanceOf[ScopedKey[Any]], deps, ss.asInstanceOf[SettingSeq[Any]])
k,
Compiled(k.asInstanceOf[ScopedKey[Any]], deps, ss.asInstanceOf[SettingSeq[Any]])
)
} }
.toVector .to(Map)
.toMap
case _ => case _ =>
sMap.toTypedSeq.map { case sMap.TPair(k, ss) => sMap.toTypedSeq.map { case sMap.TPair(k, ss) =>
val deps = ss.flatMap(_.dependencies) val deps = ss.flatMap(_.dependencies)
@ -324,16 +331,12 @@ trait Init[ScopeType]:
private def applyInits(ordered: Seq[Compiled[?]])(implicit private def applyInits(ordered: Seq[Compiled[?]])(implicit
delegates: ScopeType => Seq[ScopeType] delegates: ScopeType => Seq[ScopeType]
): Settings[ScopeType] = ): Settings =
val x = val x =
java.util.concurrent.Executors.newFixedThreadPool(Runtime.getRuntime.availableProcessors) java.util.concurrent.Executors.newFixedThreadPool(Runtime.getRuntime.availableProcessors)
try { try {
val eval: EvaluateSettings[ScopeType] = new EvaluateSettings[ScopeType] { val eval: EvaluateSettings[Init.this.type] = new EvaluateSettings(Init.this, x, ordered)
override val init: Init.this.type = Init.this eval.run(using delegates)
def compiledSettings = ordered
def executor = x
}
eval.run
} finally { } finally {
x.shutdown() x.shutdown()
} }
@ -416,15 +419,9 @@ trait Init[ScopeType]:
final class Flattened(val key: ScopedKey[?], val dependencies: Iterable[ScopedKey[?]]) final class Flattened(val key: ScopedKey[?], val dependencies: Iterable[ScopedKey[?]])
def flattenLocals(compiled: CompiledMap): Map[ScopedKey[?], Flattened] = { def flattenLocals(compiled: CompiledMap): Map[ScopedKey[?], Flattened] = {
val locals = compiled flatMap { case (key, comp) => val locals = compiled.collect { case (key, comp) if key.key.isLocal => comp }
if (key.key.isLocal) Seq(comp)
else nilSeq[Compiled[?]]
}
val ordered = Dag.topologicalSort(locals)( val ordered = Dag.topologicalSort(locals)(
_.dependencies.flatMap(dep => _.dependencies.collect { case dep if dep.key.isLocal => compiled(dep) }
if (dep.key.isLocal) Seq[Compiled[?]](compiled(dep))
else nilSeq[Compiled[?]]
)
) )
def flatten( def flatten(
cmap: Map[ScopedKey[?], Flattened], cmap: Map[ScopedKey[?], Flattened],
@ -433,7 +430,7 @@ trait Init[ScopeType]:
): Flattened = ): Flattened =
new Flattened( new Flattened(
key, key,
deps.flatMap(dep => if (dep.key.isLocal) cmap(dep).dependencies else Seq[ScopedKey[?]](dep)) deps.flatMap(dep => if (dep.key.isLocal) cmap(dep).dependencies else Seq(dep))
) )
val empty = Map.empty[ScopedKey[?], Flattened] val empty = Map.empty[ScopedKey[?], Flattened]
@ -442,10 +439,9 @@ trait Init[ScopeType]:
cmap.updated(c.key, flatten(cmap, c.key, c.dependencies)) cmap.updated(c.key, flatten(cmap, c.key, c.dependencies))
} }
compiled flatMap { case (key, comp) => compiled.collect {
if (key.key.isLocal) nilSeq[(ScopedKey[?], Flattened)] case (key, comp) if !key.key.isLocal =>
else (key, flatten(flattenedLocals, key, comp.dependencies))
Seq[(ScopedKey[?], Flattened)]((key, flatten(flattenedLocals, key, comp.dependencies)))
} }
} }
@ -653,7 +649,7 @@ trait Init[ScopeType]:
private[sbt] def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] private[sbt] def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1]
def evaluate(map: Settings[ScopeType]): A1 def evaluate(map: Settings): A1
def zip[A2](o: Initialize[A2]): Initialize[(A1, A2)] = zipTupled(o)(identity) def zip[A2](o: Initialize[A2]): Initialize[(A1, A2)] = zipTupled(o)(identity)
def zipWith[A2, U](o: Initialize[A2])(f: (A1, A2) => U): Initialize[U] = def zipWith[A2, U](o: Initialize[A2])(f: (A1, A2) => U): Initialize[U] =
@ -799,7 +795,7 @@ trait Init[ScopeType]:
(fa: Initialize[A]) => (fa.mapReferenced(g)) (fa: Initialize[A]) => (fa.mapReferenced(g))
private def mapConstantK(g: MapConstant): [A] => Initialize[A] => Initialize[A] = [A] => private def mapConstantK(g: MapConstant): [A] => Initialize[A] => Initialize[A] = [A] =>
(fa: Initialize[A]) => (fa.mapConstant(g)) (fa: Initialize[A]) => (fa.mapConstant(g))
private def evaluateK(g: Settings[ScopeType]): [A] => Initialize[A] => A = [A] => private def evaluateK(g: Settings): [A] => Initialize[A] => A = [A] =>
(fa: Initialize[A]) => (fa.evaluate(g)) (fa: Initialize[A]) => (fa.evaluate(g))
private def deps(ls: List[Initialize[?]]): Seq[ScopedKey[?]] = private def deps(ls: List[Initialize[?]]): Seq[ScopedKey[?]] =
ls.flatMap(_.dependencies) ls.flatMap(_.dependencies)
@ -820,7 +816,7 @@ trait Init[ScopeType]:
extends Keyed[S, A1]: extends Keyed[S, A1]:
override final def apply[A2](g: A1 => A2): Initialize[A2] = override final def apply[A2](g: A1 => A2): Initialize[A2] =
GetValue(scopedKey, g compose transform) GetValue(scopedKey, g compose transform)
override final def evaluate(ss: Settings[ScopeType]): A1 = transform(getValue(ss, scopedKey)) override final def evaluate(ss: Settings): A1 = transform(getValue(ss, scopedKey))
override final def mapReferenced(g: MapScoped): Initialize[A1] = override final def mapReferenced(g: MapScoped): Initialize[A1] =
GetValue(g(scopedKey), transform) GetValue(g(scopedKey), transform)
@ -842,7 +838,7 @@ trait Init[ScopeType]:
trait KeyedInitialize[A1] extends Keyed[A1, A1]: trait KeyedInitialize[A1] extends Keyed[A1, A1]:
override final def apply[A2](g: A1 => A2): Initialize[A2] = override final def apply[A2](g: A1 => A2): Initialize[A2] =
GetValue(scopedKey, g) GetValue(scopedKey, g)
override final def evaluate(ss: Settings[ScopeType]): A1 = getValue(ss, scopedKey) override final def evaluate(ss: Settings): A1 = getValue(ss, scopedKey)
override final def mapReferenced(g: MapScoped): Initialize[A1] = g(scopedKey) override final def mapReferenced(g: MapScoped): Initialize[A1] = g(scopedKey)
private[sbt] override final def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] = private[sbt] override final def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] =
@ -861,7 +857,7 @@ trait Init[ScopeType]:
override def dependencies: Seq[ScopedKey[?]] = Nil override def dependencies: Seq[ScopedKey[?]] = Nil
override def apply[A2](g2: ([x] => Initialize[x] => Initialize[x]) => A2): Initialize[A2] = override def apply[A2](g2: ([x] => Initialize[x] => Initialize[x]) => A2): Initialize[A2] =
map(this)(g2) map(this)(g2)
override def evaluate(ss: Settings[ScopeType]): [x] => Initialize[x] => Initialize[x] = f override def evaluate(ss: Settings): [x] => Initialize[x] => Initialize[x] = f
override def mapReferenced(g: MapScoped): Initialize[[x] => Initialize[x] => Initialize[x]] = override def mapReferenced(g: MapScoped): Initialize[[x] => Initialize[x] => Initialize[x]] =
TransformCapture(mapReferencedK(g) f) TransformCapture(mapReferencedK(g) f)
override def mapConstant(g: MapConstant): Initialize[[x] => Initialize[x] => Initialize[x]] = override def mapConstant(g: MapConstant): Initialize[[x] => Initialize[x] => Initialize[x]] =
@ -880,7 +876,7 @@ trait Init[ScopeType]:
extends Initialize[ScopedKey[A1]]: extends Initialize[ScopedKey[A1]]:
override def dependencies: Seq[ScopedKey[?]] = Nil override def dependencies: Seq[ScopedKey[?]] = Nil
override def apply[A2](g2: ScopedKey[A1] => A2): Initialize[A2] = map(this)(g2) override def apply[A2](g2: ScopedKey[A1] => A2): Initialize[A2] = map(this)(g2)
override def evaluate(ss: Settings[ScopeType]): ScopedKey[A1] = key override def evaluate(ss: Settings): ScopedKey[A1] = key
override def mapReferenced(g: MapScoped): Initialize[ScopedKey[A1]] = override def mapReferenced(g: MapScoped): Initialize[ScopedKey[A1]] =
ValidationCapture(g(key), selfRefOk) ValidationCapture(g(key), selfRefOk)
override def mapConstant(g: MapConstant): Initialize[ScopedKey[A1]] = this override def mapConstant(g: MapConstant): Initialize[ScopedKey[A1]] = this
@ -898,7 +894,7 @@ trait Init[ScopeType]:
extends Initialize[A1]: extends Initialize[A1]:
override def dependencies: Seq[ScopedKey[?]] = in.dependencies override def dependencies: Seq[ScopedKey[?]] = in.dependencies
override def apply[A2](g: A1 => A2): Initialize[A2] = Bind[S, A2](s => f(s)(g), in) override def apply[A2](g: A1 => A2): Initialize[A2] = Bind[S, A2](s => f(s)(g), in)
override def evaluate(ss: Settings[ScopeType]): A1 = f(in.evaluate(ss)).evaluate(ss) override def evaluate(ss: Settings): A1 = f(in.evaluate(ss)).evaluate(ss)
override def mapReferenced(g: MapScoped) = override def mapReferenced(g: MapScoped) =
Bind[S, A1](s => f(s).mapReferenced(g), in.mapReferenced(g)) Bind[S, A1](s => f(s).mapReferenced(g), in.mapReferenced(g))
@ -927,7 +923,7 @@ trait Init[ScopeType]:
case Some(i) => Right(Optional(i.validateKeyReferenced(g).toOption, f)) case Some(i) => Right(Optional(i.validateKeyReferenced(g).toOption, f))
override def mapConstant(g: MapConstant): Initialize[A1] = Optional(a map mapConstantK(g)[S], f) override def mapConstant(g: MapConstant): Initialize[A1] = Optional(a map mapConstantK(g)[S], f)
override def evaluate(ss: Settings[ScopeType]): A1 = override def evaluate(ss: Settings): A1 =
f(a.flatMap { i => trapBadRef(evaluateK(ss)(i)) }) f(a.flatMap { i => trapBadRef(evaluateK(ss)(i)) })
// proper solution is for evaluate to be deprecated or for external use only and a new internal method returning Either be used // proper solution is for evaluate to be deprecated or for external use only and a new internal method returning Either be used
@ -946,7 +942,7 @@ trait Init[ScopeType]:
override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] = Right(this) override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] = Right(this)
override def apply[A2](g: A1 => A2): Initialize[A2] = Value[A2](() => g(value())) override def apply[A2](g: A1 => A2): Initialize[A2] = Value[A2](() => g(value()))
override def mapConstant(g: MapConstant): Initialize[A1] = this override def mapConstant(g: MapConstant): Initialize[A1] = this
override def evaluate(map: Settings[ScopeType]): A1 = value() override def evaluate(map: Settings): A1 = value()
private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 = private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 =
init init
end Value end Value
@ -958,7 +954,7 @@ trait Init[ScopeType]:
Right(this) Right(this)
override def apply[A2](g: Set[ScopeType] => A2) = map(this)(g) override def apply[A2](g: Set[ScopeType] => A2) = map(this)(g)
override def mapConstant(g: MapConstant): Initialize[Set[ScopeType]] = this override def mapConstant(g: MapConstant): Initialize[Set[ScopeType]] = this
override def evaluate(map: Settings[ScopeType]): Set[ScopeType] = map.scopes override def evaluate(map: Settings): Set[ScopeType] = map.scopes
private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 = private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 =
init init
end StaticScopes end StaticScopes
@ -971,7 +967,7 @@ trait Init[ScopeType]:
override def mapConstant(g: MapConstant): Initialize[A2] = override def mapConstant(g: MapConstant): Initialize[A2] =
Uniform(f, inputs.map(_.mapConstant(g))) Uniform(f, inputs.map(_.mapConstant(g)))
override def apply[A3](g: A2 => A3): Initialize[A3] = Uniform(g.compose(f), inputs) override def apply[A3](g: A2 => A3): Initialize[A3] = Uniform(g.compose(f), inputs)
override def evaluate(ss: Settings[ScopeType]): A2 = f(inputs.map(_.evaluate(ss))) override def evaluate(ss: Settings): A2 = f(inputs.map(_.evaluate(ss)))
override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A2] = override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A2] =
val tx = inputs.map(_.validateKeyReferenced(g)) val tx = inputs.map(_.validateKeyReferenced(g))
@ -997,7 +993,7 @@ trait Init[ScopeType]:
override def apply[A2](g: A1 => A2): Initialize[A2] = Apply(g compose f, inputs) override def apply[A2](g: A1 => A2): Initialize[A2] = Apply(g compose f, inputs)
override def evaluate(ss: Settings[ScopeType]): A1 = f(inputs.unmap(evaluateK(ss))) override def evaluate(ss: Settings): A1 = f(inputs.unmap(evaluateK(ss)))
override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] = override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] =
val tx: Tuple.Map[Tup, ValidatedInit] = inputs.transform(validateKeyReferencedK(g)) val tx: Tuple.Map[Tup, ValidatedInit] = inputs.transform(validateKeyReferencedK(g))

View File

@ -191,7 +191,7 @@ object SettingsTest extends Properties("settings") {
checkKey(chk, Some(expected), eval) checkKey(chk, Some(expected), eval)
} }
def checkKey[T](key: ScopedKey[T], expected: Option[T], settings: Settings[Scope]) = { def checkKey[T](key: ScopedKey[T], expected: Option[T], settings: Def.Settings) = {
val value = settings.get(key.scope, key.key) val value = settings.get(key.scope, key.key)
("Key: " + key) |: ("Key: " + key) |:
("Value: " + value) |: ("Value: " + value) |:
@ -199,7 +199,7 @@ object SettingsTest extends Properties("settings") {
(value == expected) (value == expected)
} }
def evaluate(settings: Seq[Setting[_]]): Settings[Scope] = def evaluate(settings: Seq[Setting[_]]): Def.Settings =
try { try {
makeWithCompiledMap(settings)(delegates, scopeLocal, showFullKey)._2 makeWithCompiledMap(settings)(delegates, scopeLocal, showFullKey)._2
} catch { } catch {

View File

@ -19,7 +19,8 @@ final case class Scope(nestIndex: Int, idAtIndex: Int = 0)
// Lots of type constructors would become binary, which as you may know requires lots of type lambdas // Lots of type constructors would become binary, which as you may know requires lots of type lambdas
// when you want a type function with only one parameter. // when you want a type function with only one parameter.
// That would be a general pain.) // That would be a general pain.)
case class SettingsExample() extends Init[Scope] { case class SettingsExample() extends Init {
type ScopeType = Scope
// Provides a way of showing a Scope+AttributeKey[_] // Provides a way of showing a Scope+AttributeKey[_]
val showFullKey: Show[ScopedKey[?]] = Show[ScopedKey[?]]((key: ScopedKey[?]) => { val showFullKey: Show[ScopedKey[?]] = Show[ScopedKey[?]]((key: ScopedKey[?]) => {
s"${key.scope.nestIndex}(${key.scope.idAtIndex})/${key.key.label}" s"${key.scope.nestIndex}(${key.scope.idAtIndex})/${key.key.label}"
@ -64,7 +65,7 @@ case class SettingsUsage(val settingsExample: SettingsExample) {
// "compiles" and applies the settings. // "compiles" and applies the settings.
// This can be split into multiple steps to access intermediate results if desired. // This can be split into multiple steps to access intermediate results if desired.
// The 'inspect' command operates on the output of 'compile', for example. // The 'inspect' command operates on the output of 'compile', for example.
val applied: Settings[Scope] = val applied: Settings =
makeWithCompiledMap(mySettings)(using delegates, scopeLocal, showFullKey)._2 makeWithCompiledMap(mySettings)(using delegates, scopeLocal, showFullKey)._2
// Show results. // Show results.