mirror of https://github.com/sbt/sbt.git
[2.x] fix: Use correct configuration identifier for display (#8698)
**Problem** The configuration name translation in logging was incorrect. When a configuration like MultiJvm (id="MultiJvm", name="multi-jvm") was displayed, it showed "Multi-jvm" instead of "MultiJvm" because the display logic was guessing the identifier by capitalizing the ivy config name. **Solution** This fix: - Adds configNameToIdent reverse mapping in ConfigIndex to look up the correct Configuration.id from the ivy config name - Adds toConfigIdent method in KeyIndex trait for display lookup - Updates Scope.display to accept a config name lookup function - Updates showLoadingKey and showContextKey to use the index lookup Fixes #5211 Generated-by: Claude
This commit is contained in:
parent
47e7133260
commit
4e0180d759
|
|
@ -733,6 +733,7 @@ lazy val mainProj = (project in file("main"))
|
|||
exclude[DirectMissingMethodProblem]("sbt.coursierint.LMCoursier.coursierConfiguration"),
|
||||
exclude[IncompatibleMethTypeProblem]("sbt.internal.Compiler.scalaInstanceTask"),
|
||||
exclude[ReversedMissingMethodProblem]("sbt.ScriptedRun.invoke"),
|
||||
exclude[ReversedMissingMethodProblem]("sbt.internal.KeyIndex.toConfigIdent"),
|
||||
),
|
||||
)
|
||||
.dependsOn(lmCore, lmIvy, lmCoursierShadedPublishing)
|
||||
|
|
|
|||
|
|
@ -102,6 +102,12 @@ object Def extends BuildSyntax with Init with InitializeImplicits:
|
|||
|
||||
private[sbt] def showShortKey(
|
||||
keyNameColor: Option[String],
|
||||
): Show[ScopedKey[?]] =
|
||||
showShortKey(keyNameColor, Scope.guessConfigIdent)
|
||||
|
||||
private[sbt] def showShortKey(
|
||||
keyNameColor: Option[String],
|
||||
configNameToIdent: String => String,
|
||||
): Show[ScopedKey[?]] = {
|
||||
def displayShort(
|
||||
project: Reference
|
||||
|
|
@ -117,7 +123,8 @@ object Def extends BuildSyntax with Init with InitializeImplicits:
|
|||
Scope.display(
|
||||
key.scope,
|
||||
withColor(key.key.label, keyNameColor),
|
||||
ref => displayShort(ref)
|
||||
ref => displayShort(ref),
|
||||
configNameToIdent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,6 +169,9 @@ object Scope:
|
|||
|
||||
def display(config: ConfigKey): String = guessConfigIdent(config.name) + " /"
|
||||
|
||||
def display(config: ConfigKey, configNameToIdent: String => String): String =
|
||||
configNameToIdent(config.name) + " /"
|
||||
|
||||
private[sbt] val configIdents: Map[String, String] =
|
||||
Map(
|
||||
"scala-tool" -> "ScalaTool",
|
||||
|
|
@ -191,6 +194,14 @@ object Scope:
|
|||
def display(scope: Scope, sep: String, showProject: Reference => String): String =
|
||||
displayMasked(scope, sep, showProject, ScopeMask())
|
||||
|
||||
def display(
|
||||
scope: Scope,
|
||||
sep: String,
|
||||
showProject: Reference => String,
|
||||
configNameToIdent: String => String
|
||||
): String =
|
||||
displayMasked(scope, sep, showProject, ScopeMask(), showZeroConfig = false, configNameToIdent)
|
||||
|
||||
private[sbt] def displayPedantic(scope: Scope, sep: String): String =
|
||||
displayMasked(scope, sep, showProject, ScopeMask(), true)
|
||||
|
||||
|
|
@ -237,25 +248,35 @@ object Scope:
|
|||
showProject: Reference => String,
|
||||
mask: ScopeMask,
|
||||
showZeroConfig: Boolean
|
||||
): String = {
|
||||
): String =
|
||||
displayMasked(scope, sep, showProject, mask, showZeroConfig, guessConfigIdent)
|
||||
|
||||
def displayMasked(
|
||||
scope: Scope,
|
||||
sep: String,
|
||||
showProject: Reference => String,
|
||||
mask: ScopeMask,
|
||||
showZeroConfig: Boolean,
|
||||
configNameToIdent: String => String
|
||||
): String =
|
||||
import scope.{ project, config, task, extra }
|
||||
extra.toOption.flatMap(_.get(customShowString)).getOrElse {
|
||||
val zeroConfig = if (showZeroConfig) "Zero /" else ""
|
||||
val configPrefix = config.foldStrict(display, zeroConfig, "./")
|
||||
val taskPrefix = task.foldStrict(_.label + " /", "", "./")
|
||||
val extras = extra.foldStrict(_.entries.map(_.toString).toList, nil, nil)
|
||||
val postfix = if (extras.isEmpty) "" else extras.mkString("(", ", ", ")")
|
||||
if (scope == GlobalScope) "Global / " + sep + postfix
|
||||
else
|
||||
mask.concatShow(
|
||||
appendSpace(projectPrefix(project, showProject)),
|
||||
appendSpace(configPrefix),
|
||||
appendSpace(taskPrefix),
|
||||
sep,
|
||||
postfix
|
||||
)
|
||||
}
|
||||
}
|
||||
extra.toOption
|
||||
.flatMap(_.get(customShowString))
|
||||
.getOrElse:
|
||||
val zeroConfig = if showZeroConfig then "Zero /" else ""
|
||||
val configPrefix = config.foldStrict(c => display(c, configNameToIdent), zeroConfig, "./")
|
||||
val taskPrefix = task.foldStrict(_.label + " /", "", "./")
|
||||
val extras = extra.foldStrict(_.entries.map(_.toString).toList, nil, nil)
|
||||
val postfix = if extras.isEmpty then "" else extras.mkString("(", ", ", ")")
|
||||
if scope == GlobalScope then "Global / " + sep + postfix
|
||||
else
|
||||
mask.concatShow(
|
||||
appendSpace(projectPrefix(project, showProject)),
|
||||
appendSpace(configPrefix),
|
||||
appendSpace(taskPrefix),
|
||||
sep,
|
||||
postfix
|
||||
)
|
||||
|
||||
private[sbt] def appendSpace(s: String): String =
|
||||
if (s == "") ""
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
package sbt
|
||||
|
||||
import sbt.BasicCommandStrings.{ StashOnFailure, networkExecPrefix }
|
||||
import sbt.ProjectExtra.extract
|
||||
import sbt.ProjectExtra.*
|
||||
import sbt.internal.{ ConsoleChannel, FastTrackCommands, ShutdownHooks, SysProp, TaskProgress }
|
||||
import sbt.internal.langserver.ErrorCodes
|
||||
import sbt.internal.nio.CheckBuildSources.CheckBuildSourcesKey
|
||||
|
|
@ -156,7 +156,13 @@ private[sbt] object MainLoop:
|
|||
state.get(Keys.superShellSleep.key).getOrElse(SysProp.supershellSleep.millis)
|
||||
val superShellThreshold =
|
||||
state.get(Keys.superShellThreshold.key).getOrElse(SysProp.supershellThreshold)
|
||||
val taskProgress = new TaskProgress(superShellSleep, superShellThreshold, state.log)
|
||||
val taskProgress =
|
||||
new TaskProgress(
|
||||
superShellSleep,
|
||||
superShellThreshold,
|
||||
state.log,
|
||||
Project.configNameToIdent(state)
|
||||
)
|
||||
val gcMonitor = if (SysProp.gcMonitor) Some(new sbt.internal.GCMonitor(state.log)) else None
|
||||
try {
|
||||
ErrorHandling.wideConvert {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import Def.{ Flattened, Initialize, ScopedKey, Setting }
|
|||
import sbt.internal.{
|
||||
Load,
|
||||
BuildStructure,
|
||||
KeyIndex,
|
||||
LoadedBuild,
|
||||
LoadedBuildUnit,
|
||||
SettingGraph,
|
||||
|
|
@ -199,31 +200,69 @@ trait ProjectExtra extends Scoped.Syntax:
|
|||
showContextKey(state, None)
|
||||
|
||||
def showContextKey(state: State, keyNameColor: Option[String]): Show[ScopedKey[?]] =
|
||||
if (isProjectLoaded(state)) showContextKey2(session(state), keyNameColor)
|
||||
if isProjectLoaded(state) then
|
||||
val se = session(state)
|
||||
val st = structure(state)
|
||||
showContextKey2(se, st.index.keyIndex, keyNameColor)
|
||||
else Def.showFullKey
|
||||
|
||||
// @deprecated("Use showContextKey2 which doesn't take the unused structure param", "1.1.1")
|
||||
// def showContextKey(
|
||||
// session: SessionSettings,
|
||||
// structure: BuildStructure,
|
||||
// keyNameColor: Option[String] = None
|
||||
// ): Show[ScopedKey[_]] =
|
||||
// showContextKey2(session, keyNameColor)
|
||||
|
||||
def showContextKey2(
|
||||
session: SessionSettings,
|
||||
keyNameColor: Option[String] = None
|
||||
): Show[ScopedKey[?]] =
|
||||
Def.showRelativeKey2(session.current, keyNameColor)
|
||||
|
||||
def showContextKey2(
|
||||
session: SessionSettings,
|
||||
keyIndex: KeyIndex,
|
||||
keyNameColor: Option[String]
|
||||
): Show[ScopedKey[?]] =
|
||||
val current = session.current
|
||||
val configNameToIdent: String => String = name => keyIndex.toConfigIdent(Some(current))(name)
|
||||
Show[ScopedKey[?]]: key =>
|
||||
val color: String => String = Def.withColor(_, keyNameColor)
|
||||
key.scope.extra.toOption
|
||||
.flatMap(_.get(Scope.customShowString).map(color))
|
||||
.getOrElse:
|
||||
Scope.display(
|
||||
key.scope,
|
||||
color(key.key.label),
|
||||
ref => Def.displayRelative2(current, ref),
|
||||
configNameToIdent
|
||||
)
|
||||
|
||||
def showLoadingKey(
|
||||
loaded: LoadedBuild,
|
||||
keyNameColor: Option[String] = None
|
||||
): Show[ScopedKey[?]] =
|
||||
Def.showRelativeKey2(
|
||||
ProjectRef(loaded.root, loaded.units(loaded.root).rootProjects.head),
|
||||
keyNameColor
|
||||
)
|
||||
val configNameToIdent = buildConfigNameToIdent(loaded)
|
||||
val current = ProjectRef(loaded.root, loaded.units(loaded.root).rootProjects.head)
|
||||
Show[ScopedKey[?]]: key =>
|
||||
val color: String => String = Def.withColor(_, keyNameColor)
|
||||
key.scope.extra.toOption
|
||||
.flatMap(_.get(Scope.customShowString).map(color))
|
||||
.getOrElse:
|
||||
Scope.display(
|
||||
key.scope,
|
||||
color(key.key.label),
|
||||
ref => Def.displayRelative2(current, ref),
|
||||
configNameToIdent
|
||||
)
|
||||
|
||||
private[sbt] def configNameToIdent(state: State): String => String =
|
||||
if isProjectLoaded(state) then buildConfigNameToIdent(structure(state).units)
|
||||
else Scope.guessConfigIdent
|
||||
|
||||
private def buildConfigNameToIdent(loaded: LoadedBuild): String => String =
|
||||
buildConfigNameToIdent(loaded.units)
|
||||
|
||||
private def buildConfigNameToIdent(units: Map[URI, LoadedBuildUnit]): String => String =
|
||||
val configMap = (for
|
||||
(_, unit) <- units.iterator
|
||||
(_, project) <- unit.defined.iterator
|
||||
config <- project.configurations.iterator
|
||||
yield config.name -> config.id).toMap
|
||||
name => configMap.getOrElse(name, Scope.guessConfigIdent(name))
|
||||
|
||||
def getOrError[T](state: State, key: AttributeKey[T], msg: String): T =
|
||||
state.get(key).getOrElse(sys.error(msg))
|
||||
|
|
@ -253,11 +292,11 @@ trait ProjectExtra extends Scoped.Syntax:
|
|||
val se = Project.session(state)
|
||||
val st = Project.structure(state)
|
||||
val currentRef = internal.ProjectNavigation.effectiveCurrentRef(state)
|
||||
Extracted(st, se, currentRef)(using Project.showContextKey2(se))
|
||||
Extracted(st, se, currentRef)(using Project.showContextKey2(se, st.index.keyIndex, None))
|
||||
}
|
||||
|
||||
private[sbt] def extract(se: SessionSettings, st: BuildStructure): Extracted =
|
||||
Extracted(st, se, se.current)(using Project.showContextKey2(se))
|
||||
Extracted(st, se, se.current)(using Project.showContextKey2(se, st.index.keyIndex, None))
|
||||
|
||||
def getProjectForReference(ref: Reference, structure: BuildStructure): Option[ResolvedProject] =
|
||||
ref match
|
||||
|
|
@ -401,7 +440,7 @@ trait ProjectExtra extends Scoped.Syntax:
|
|||
case None => ""
|
||||
|
||||
val (definingKey, providedBy) = structure.data.definingKey(key) match
|
||||
case Some(k) => k -> s"Provided by:\n\t${Scope.display(k.scope, key.key.label)}\n"
|
||||
case Some(k) => k -> s"Provided by:\n\t${display.show(ScopedKey(k.scope, key.key))}\n"
|
||||
case None => key -> ""
|
||||
val comp =
|
||||
Def.compiled(structure.settings, actual)(using
|
||||
|
|
|
|||
|
|
@ -17,10 +17,12 @@ import scala.collection.mutable
|
|||
import scala.collection.immutable.VectorBuilder
|
||||
import scala.concurrent.duration.*
|
||||
|
||||
private[sbt] abstract class AbstractTaskExecuteProgress extends ExecuteProgress {
|
||||
private[sbt] abstract class AbstractTaskExecuteProgress(
|
||||
configNameToIdent: String => String = Scope.guessConfigIdent
|
||||
) extends ExecuteProgress {
|
||||
import AbstractTaskExecuteProgress.Timer
|
||||
|
||||
private val showScopedKey = Def.showShortKey(None)
|
||||
private val showScopedKey = Def.showShortKey(None, configNameToIdent)
|
||||
private val anonOwners = new ConcurrentHashMap[TaskId[?], TaskId[?]]
|
||||
private val calledBy = new ConcurrentHashMap[TaskId[?], TaskId[?]]
|
||||
private val timings = new ConcurrentHashMap[TaskId[?], Timer]
|
||||
|
|
|
|||
|
|
@ -48,7 +48,13 @@ object KeyIndex {
|
|||
val data = ids map { id =>
|
||||
val configs = configurations.getOrElse(id, Seq())
|
||||
val configIdentToName = configs.map(config => config.id -> config.name).toMap
|
||||
Option(id) -> new ConfigIndex(Map.empty, configIdentToName, emptyAKeyIndex)
|
||||
val configNameToIdent = configs.map(config => config.name -> config.id).toMap
|
||||
Option(id) -> new ConfigIndex(
|
||||
Map.empty,
|
||||
configIdentToName,
|
||||
configNameToIdent,
|
||||
emptyAKeyIndex
|
||||
)
|
||||
}
|
||||
Option(uri) -> new ProjectIndex(data.toMap)
|
||||
}
|
||||
|
|
@ -66,6 +72,11 @@ object KeyIndex {
|
|||
case Some(idx) => idx.fromConfigIdent(proj)(configIdent)
|
||||
case _ => Scope.unguessConfigIdent(configIdent)
|
||||
}
|
||||
private[sbt] def toConfigIdent(proj: Option[ResolvedReference])(configName: String): String =
|
||||
indices.find(idx => idx.exists(proj)) match {
|
||||
case Some(idx) => idx.toConfigIdent(proj)(configName)
|
||||
case _ => Scope.guessConfigIdent(configName)
|
||||
}
|
||||
def tasks(proj: Option[ResolvedReference], conf: Option[String]) = concat(_.tasks(proj, conf))
|
||||
def tasks(proj: Option[ResolvedReference], conf: Option[String], key: String) =
|
||||
concat(_.tasks(proj, conf, key))
|
||||
|
|
@ -79,7 +90,8 @@ object KeyIndex {
|
|||
private[sbt] def getOr[A, B](m: Map[A, B], key: A, or: B): B = m.getOrElse(key, or)
|
||||
private[sbt] def keySet[A, B](m: Map[Option[A], B]): Set[A] = m.keys.flatten.toSet
|
||||
private[sbt] val emptyAKeyIndex = new AKeyIndex(Relation.empty)
|
||||
private[sbt] val emptyConfigIndex = new ConfigIndex(Map.empty, Map.empty, emptyAKeyIndex)
|
||||
private[sbt] val emptyConfigIndex =
|
||||
new ConfigIndex(Map.empty, Map.empty, Map.empty, emptyAKeyIndex)
|
||||
private[sbt] val emptyProjectIndex = new ProjectIndex(Map.empty)
|
||||
private[sbt] val emptyBuildIndex = new BuildIndex(Map.empty)
|
||||
|
||||
|
|
@ -115,6 +127,7 @@ trait KeyIndex {
|
|||
): Set[String]
|
||||
private[sbt] def configIdents(project: Option[ResolvedReference]): Set[String]
|
||||
private[sbt] def fromConfigIdent(proj: Option[ResolvedReference])(configIdent: String): String
|
||||
private[sbt] def toConfigIdent(proj: Option[ResolvedReference])(configName: String): String
|
||||
}
|
||||
trait ExtendableKeyIndex extends KeyIndex {
|
||||
def add(scoped: ScopedKey[?]): ExtendableKeyIndex
|
||||
|
|
@ -135,11 +148,13 @@ private[sbt] case class IdentifiableConfig(name: String, ident: Option[String])
|
|||
/*
|
||||
* data contains the mapping between a configuration name and its keys.
|
||||
* configIdentToName contains the mapping between a configuration ident and its name
|
||||
* configNameToIdent contains the reverse mapping from name to ident for display purposes
|
||||
* noConfigKeys contains the keys without a configuration.
|
||||
*/
|
||||
private[sbt] final class ConfigIndex(
|
||||
val data: Map[String, AKeyIndex],
|
||||
val configIdentToName: Map[String, String],
|
||||
val configNameToIdent: Map[String, String],
|
||||
val noConfigKeys: AKeyIndex
|
||||
) {
|
||||
def add(
|
||||
|
|
@ -157,18 +172,22 @@ private[sbt] final class ConfigIndex(
|
|||
config: IdentifiableConfig,
|
||||
task: Option[AttributeKey[?]],
|
||||
key: AttributeKey[?]
|
||||
): ConfigIndex = {
|
||||
): ConfigIndex =
|
||||
val keyIndex = data.getOrElse(config.name, emptyAKeyIndex)
|
||||
val configIdent = config.ident.getOrElse(Scope.guessConfigIdent(config.name))
|
||||
// Only add to configNameToIdent if not already present to preserve correct mappings from base()
|
||||
val updatedNameToIdent =
|
||||
if configNameToIdent.contains(config.name) then configNameToIdent
|
||||
else configNameToIdent.updated(config.name, configIdent)
|
||||
new ConfigIndex(
|
||||
data.updated(config.name, keyIndex.add(task, key)),
|
||||
configIdentToName.updated(configIdent, config.name),
|
||||
updatedNameToIdent,
|
||||
noConfigKeys
|
||||
)
|
||||
}
|
||||
|
||||
def addKeyWithoutConfig(task: Option[AttributeKey[?]], key: AttributeKey[?]): ConfigIndex = {
|
||||
new ConfigIndex(data, configIdentToName, noConfigKeys.add(task, key))
|
||||
new ConfigIndex(data, configIdentToName, configNameToIdent, noConfigKeys.add(task, key))
|
||||
}
|
||||
|
||||
def keyIndex(conf: Option[String]): AKeyIndex = conf match {
|
||||
|
|
@ -179,8 +198,13 @@ private[sbt] final class ConfigIndex(
|
|||
def configs: Set[String] = data.keySet
|
||||
private[sbt] lazy val idents: Set[String] = configIdentToName.keySet
|
||||
|
||||
// guess Configuration name from an identifier.
|
||||
// There's a guessing involved because we could have scoped key that Project is not aware of.
|
||||
// Looks up the display identifier for a configuration name.
|
||||
// Falls back to guessing if the name is not in the index.
|
||||
private[sbt] def toConfigIdent(name: String): String =
|
||||
configNameToIdent.getOrElse(name, Scope.guessConfigIdent(name))
|
||||
|
||||
// Looks up the configuration name from an identifier.
|
||||
// Falls back to guessing if the identifier is not in the index.
|
||||
private[sbt] def fromConfigIdent(ident: String): String =
|
||||
configIdentToName.getOrElse(ident, Scope.unguessConfigIdent(ident))
|
||||
}
|
||||
|
|
@ -224,6 +248,9 @@ private[sbt] final class KeyIndex0(val data: BuildIndex) extends ExtendableKeyIn
|
|||
private[sbt] def fromConfigIdent(proj: Option[ResolvedReference])(configIdent: String): String =
|
||||
confIndex(proj).fromConfigIdent(configIdent)
|
||||
|
||||
private[sbt] def toConfigIdent(proj: Option[ResolvedReference])(configName: String): String =
|
||||
confIndex(proj).toConfigIdent(configName)
|
||||
|
||||
def tasks(proj: Option[ResolvedReference], conf: Option[String]): Set[AttributeKey[?]] =
|
||||
keyIndex(proj, conf).tasks
|
||||
def tasks(
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@ import sbt.util.Logger
|
|||
private[sbt] class TaskProgress(
|
||||
sleepDuration: FiniteDuration,
|
||||
threshold: FiniteDuration,
|
||||
logger: Logger
|
||||
) extends AbstractTaskExecuteProgress
|
||||
logger: Logger,
|
||||
configNameToIdent: String => String = Scope.guessConfigIdent
|
||||
) extends AbstractTaskExecuteProgress(configNameToIdent)
|
||||
with ExecuteProgress
|
||||
with AutoCloseable {
|
||||
private val lastTaskCount = new AtomicInteger(0)
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
// intentionally empty - CheckPlugin provides settings
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package sbt
|
||||
|
||||
import sbt.*
|
||||
import Keys.*
|
||||
|
||||
object CheckPlugin extends AutoPlugin:
|
||||
override def requires = plugins.JvmPlugin
|
||||
override def trigger = allRequirements
|
||||
|
||||
lazy val MultiJvm = config("multi-jvm")
|
||||
lazy val test1 = taskKey[Unit]("")
|
||||
|
||||
override def projectConfigurations = Seq(MultiJvm)
|
||||
override def projectSettings = Seq(
|
||||
MultiJvm / test1 := {},
|
||||
commands += Command.command("checkShortKeyDisplay") { state =>
|
||||
val configNameToIdent = Project.configNameToIdent(state)
|
||||
val show = Def.showShortKey(None, configNameToIdent)
|
||||
val displayed = show.show((MultiJvm / test1).scopedKey)
|
||||
if !displayed.contains("MultiJvm") then
|
||||
sys.error(s"Expected 'MultiJvm' in short key display but got: '$displayed'")
|
||||
state.log.info(s"Config display check passed: $displayed")
|
||||
state
|
||||
},
|
||||
)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Verify that custom configuration MultiJvm displays correctly
|
||||
# instead of the guessed Multi-jvm (#5211)
|
||||
> checkShortKeyDisplay
|
||||
Loading…
Reference in New Issue