From bf5bc46d3c3e5c7104fb20eeadfba65d0c671bb2 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 27 Feb 2017 14:11:20 +0000 Subject: [PATCH] Disallow SettingQuery relying on currentProject Introduce a specialised scopedKeyParser on SettingQuery to redefine the "projectRef" parser to never match "*" or omitted project refereneces. --- .../sbt/internal/server/NetworkChannel.scala | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala index 790091aa6..33a75f6f3 100644 --- a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala +++ b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala @@ -83,7 +83,7 @@ final class NetworkChannel(val name: String, connection: Socket, state: State) e import sbt.internal.util.complete.Parser val extracted = Project extract state - val key = Parser.parse(req.setting, Act scopedKeyParser extracted) + val key = Parser.parse(req.setting, SettingQuery scopedKeyParser extracted) def getSettingValue[A](key: Def.ScopedKey[A]) = extracted.structure.data.get(key.scope, key.key) @@ -113,3 +113,61 @@ final class NetworkChannel(val name: String, connection: Socket, state: State) e out.close() } } + +object SettingQuery { + import java.net.URI + import sbt.internal.util.{ AttributeKey, Settings } + import sbt.internal.util.complete.{ DefaultParsers, Parser }, DefaultParsers._ + import sbt.Def.{ showBuildRelativeKey, ScopedKey } + + // Similar to Act.projectRef, except doesn't match "*" or omitted project references + def projectRef(index: KeyIndex, currentBuild: URI): Parser[ResolvedReference] = { + val trailing = '/' !!! "Expected '/' (if selecting a project)" + Act.resolvedReference(index, currentBuild, trailing) + } + + def scopedKeyFull( + index: KeyIndex, + currentBuild: URI, + defaultConfigs: Option[ResolvedReference] => Seq[String], + keyMap: Map[String, AttributeKey[_]] + ): Parser[Seq[Parser[ParsedKey]]] = { + for { + proj <- projectRef(index, currentBuild) + confAmb <- Act.config(index configs Some(proj)) + partialMask = ScopeMask(true, confAmb.isExplicit, false, false) + } yield Act.taskKeyExtra(index, defaultConfigs, keyMap, Some(proj), confAmb, partialMask) + } + + def scopedKeyParser(structure: BuildStructure, currentBuild: URI): Parser[ScopedKey[_]] = + scopedKey( + structure.index.keyIndex, + currentBuild, + structure.extra.configurationsForAxis, + structure.index.keyMap, + structure.data + ) + + def scopedKeySelected( + index: KeyIndex, + currentBuild: URI, + defaultConfigs: Option[ResolvedReference] => Seq[String], + keyMap: Map[String, AttributeKey[_]], + data: Settings[Scope] + ): Parser[ParsedKey] = + scopedKeyFull(index, currentBuild, defaultConfigs, keyMap) flatMap { choices => + Act.select(choices, data)(showBuildRelativeKey(currentBuild, index.buildURIs.size > 1)) + } + + def scopedKey( + index: KeyIndex, + currentBuild: URI, + defaultConfigs: Option[ResolvedReference] => Seq[String], + keyMap: Map[String, AttributeKey[_]], + data: Settings[Scope] + ): Parser[ScopedKey[_]] = + scopedKeySelected(index, currentBuild, defaultConfigs, keyMap, data).map(_.key) + + def scopedKeyParser(extracted: Extracted): Parser[ScopedKey[_]] = + scopedKeyParser(extracted.structure, extracted.currentRef.build) +}