mirror of https://github.com/sbt/sbt.git
Merge pull request #3032 from dwijnand/setting-query-json
Start handling default types when serialising query setting values
This commit is contained in:
commit
ece85b44bd
|
|
@ -181,7 +181,8 @@ lazy val protocolProj = (project in file("protocol")).
|
|||
testedBaseSettings,
|
||||
name := "Protocol",
|
||||
libraryDependencies ++= Seq(sjsonNewScalaJson),
|
||||
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala"
|
||||
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
|
||||
contrabandFormatsForType in generateContrabands in Compile := ContrabandConfig.getFormats
|
||||
).
|
||||
configure(addSbtUtilLogging)
|
||||
|
||||
|
|
@ -211,6 +212,7 @@ lazy val mainSettingsProj = (project in file("main-settings")).
|
|||
// The main integration project for sbt. It brings all of the projects together, configures them, and provides for overriding conventions.
|
||||
lazy val mainProj = (project in file("main")).
|
||||
dependsOn(actionsProj, mainSettingsProj, runProj, commandProj).
|
||||
disablePlugins(SbtScalariform).
|
||||
settings(
|
||||
testedBaseSettings,
|
||||
name := "Main",
|
||||
|
|
|
|||
|
|
@ -3,19 +3,20 @@
|
|||
*/
|
||||
package sbt
|
||||
|
||||
/** An abstraction on top of Settings for build configuration and task definition. */
|
||||
import scala.language.experimental.macros
|
||||
|
||||
import java.io.File
|
||||
|
||||
import ConcurrentRestrictions.Tag
|
||||
import Def.{ Initialize, KeyedInitialize, ScopedKey, Setting, setting }
|
||||
import sbt.io.{ FileFilter, PathFinder }
|
||||
import sbt.io.syntax._
|
||||
import std.TaskExtra.{ task => mktask, _ }
|
||||
import sbt.internal.util.Types._
|
||||
import sbt.internal.util.{ ~>, AList, AttributeKey, Settings, SourcePosition }
|
||||
import sbt.util.OptJsonWriter
|
||||
import sbt.ConcurrentRestrictions.Tag
|
||||
import sbt.Def.{ Initialize, KeyedInitialize, ScopedKey, Setting, setting }
|
||||
import std.TaskExtra.{ task => mktask, _ }
|
||||
|
||||
import language.experimental.macros
|
||||
/** An abstraction on top of Settings for build configuration and task definition. */
|
||||
|
||||
sealed trait Scoped { def scope: Scope; val key: AttributeKey[_] }
|
||||
|
||||
|
|
@ -471,17 +472,17 @@ object TaskKey {
|
|||
|
||||
/** Constructs SettingKeys, which are associated with a value to define a basic setting.*/
|
||||
object SettingKey {
|
||||
def apply[T: Manifest](label: String, description: String = "", rank: Int = KeyRanks.DefaultSettingRank): SettingKey[T] =
|
||||
def apply[T: Manifest: OptJsonWriter](label: String, description: String = "", rank: Int = KeyRanks.DefaultSettingRank): SettingKey[T] =
|
||||
apply(AttributeKey[T](label, description, rank))
|
||||
|
||||
def apply[T: Manifest](label: String, description: String, extend1: Scoped, extendN: Scoped*): SettingKey[T] =
|
||||
def apply[T: Manifest: OptJsonWriter](label: String, description: String, extend1: Scoped, extendN: Scoped*): SettingKey[T] =
|
||||
apply(AttributeKey[T](label, description, extendScoped(extend1, extendN)))
|
||||
|
||||
def apply[T: Manifest](label: String, description: String, rank: Int, extend1: Scoped, extendN: Scoped*): SettingKey[T] =
|
||||
def apply[T: Manifest: OptJsonWriter](label: String, description: String, rank: Int, extend1: Scoped, extendN: Scoped*): SettingKey[T] =
|
||||
apply(AttributeKey[T](label, description, extendScoped(extend1, extendN), rank))
|
||||
|
||||
def apply[T](akey: AttributeKey[T]): SettingKey[T] =
|
||||
new SettingKey[T] { val key = akey; def scope = Scope.ThisScope }
|
||||
|
||||
def local[T: Manifest]: SettingKey[T] = apply[T](AttributeKey.local[T])
|
||||
def local[T: Manifest: OptJsonWriter]: SettingKey[T] = apply[T](AttributeKey.local[T])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
package sbt
|
||||
package std
|
||||
|
||||
import reflect.macros._
|
||||
import scala.annotation.tailrec
|
||||
import scala.reflect.macros._
|
||||
|
||||
import sbt.util.OptJsonWriter
|
||||
|
||||
private[sbt] object KeyMacro {
|
||||
def settingKeyImpl[T: c.WeakTypeTag](c: blackbox.Context)(description: c.Expr[String]): c.Expr[SettingKey[T]] =
|
||||
keyImpl[T, SettingKey[T]](c) { (name, mf) =>
|
||||
c.universe.reify { SettingKey[T](name.splice, description.splice)(mf.splice) }
|
||||
keyImpl2[T, SettingKey[T]](c) { (name, mf, ojw) =>
|
||||
c.universe.reify { SettingKey[T](name.splice, description.splice)(mf.splice, ojw.splice) }
|
||||
}
|
||||
def taskKeyImpl[T: c.WeakTypeTag](c: blackbox.Context)(description: c.Expr[String]): c.Expr[TaskKey[T]] =
|
||||
keyImpl[T, TaskKey[T]](c) { (name, mf) =>
|
||||
|
|
@ -17,20 +20,33 @@ private[sbt] object KeyMacro {
|
|||
c.universe.reify { InputKey[T](name.splice, description.splice)(mf.splice) }
|
||||
}
|
||||
|
||||
def keyImpl[T: c.WeakTypeTag, S: c.WeakTypeTag](c: blackbox.Context)(f: (c.Expr[String], c.Expr[Manifest[T]]) => c.Expr[S]): c.Expr[S] =
|
||||
{
|
||||
import c.universe._
|
||||
val enclosingValName = definingValName(c, methodName => s"""$methodName must be directly assigned to a val, such as `val x = $methodName[Int]("description")`.""")
|
||||
val name = c.Expr[String](Literal(Constant(enclosingValName)))
|
||||
val mf = c.Expr[Manifest[T]](c.inferImplicitValue(weakTypeOf[Manifest[T]]))
|
||||
f(name, mf)
|
||||
}
|
||||
def keyImpl[T: c.WeakTypeTag, S: c.WeakTypeTag](c: blackbox.Context)(
|
||||
f: (c.Expr[String], c.Expr[Manifest[T]]) => c.Expr[S]
|
||||
): c.Expr[S] =
|
||||
f(getName(c), getImplicit[Manifest[T]](c))
|
||||
|
||||
private def keyImpl2[T: c.WeakTypeTag, S: c.WeakTypeTag](c: blackbox.Context)(
|
||||
f: (c.Expr[String], c.Expr[Manifest[T]], c.Expr[OptJsonWriter[T]]) => c.Expr[S]
|
||||
): c.Expr[S] =
|
||||
f(getName(c), getImplicit[Manifest[T]](c), getImplicit[OptJsonWriter[T]](c))
|
||||
|
||||
private def getName[S: c.WeakTypeTag, T: c.WeakTypeTag](c: blackbox.Context): c.Expr[String] = {
|
||||
import c.universe._
|
||||
val enclosingValName = definingValName(c, methodName => s"""$methodName must be directly assigned to a val, such as `val x = $methodName[Int]("description")`.""")
|
||||
c.Expr[String](Literal(Constant(enclosingValName)))
|
||||
}
|
||||
|
||||
private def getImplicit[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[T] = {
|
||||
import c.universe._
|
||||
c.Expr[T](c.inferImplicitValue(weakTypeOf[T]))
|
||||
}
|
||||
|
||||
def definingValName(c: blackbox.Context, invalidEnclosingTree: String => String): String =
|
||||
{
|
||||
import c.universe.{ Apply => ApplyTree, _ }
|
||||
val methodName = c.macroApplication.symbol.name
|
||||
def processName(n: Name): String = n.decodedName.toString.trim // trim is not strictly correct, but macros don't expose the API necessary
|
||||
def enclosingVal(trees: List[c.Tree]): String =
|
||||
@tailrec def enclosingVal(trees: List[c.Tree]): String =
|
||||
{
|
||||
trees match {
|
||||
case vd @ ValDef(_, name, _, _) :: ts => processName(name)
|
||||
|
|
@ -44,6 +60,7 @@ private[sbt] object KeyMacro {
|
|||
}
|
||||
enclosingVal(enclosingTrees(c).toList)
|
||||
}
|
||||
|
||||
def enclosingTrees(c: blackbox.Context): Seq[c.Tree] =
|
||||
c.asInstanceOf[reflect.macros.runtime.Context].callsiteTyper.context.enclosingContextChain.map(_.tree.asInstanceOf[c.Tree])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import sbt.internal.io.WatchState
|
|||
import sbt.internal.util.{ AttributeKey, CacheStore, SourcePosition }
|
||||
|
||||
import sbt.librarymanagement.Configurations.CompilerPlugin
|
||||
import sbt.librarymanagement.LibraryManagementCodec._
|
||||
import sbt.librarymanagement.{
|
||||
Artifact,
|
||||
Configuration,
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ private[sbt] final class CommandExchange {
|
|||
def onIncomingSocket(socket: Socket): Unit =
|
||||
{
|
||||
s.log.info(s"new client connected from: ${socket.getPort}")
|
||||
val channel = new NetworkChannel(newChannelName, socket, Project structure s, Project.session(s).currentBuild)
|
||||
val channel = new NetworkChannel(newChannelName, socket, Project structure s)
|
||||
subscribe(channel)
|
||||
channel.publishEventMessage(ChannelAcceptedEvent(channel.name))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -699,7 +699,7 @@ private[sbt] object Load {
|
|||
* sbt file to resolve a project.
|
||||
* @param log A logger to report auto-plugin issues to.
|
||||
*/
|
||||
private[this] def resolveProject(
|
||||
private[sbt] def resolveProject(
|
||||
p: Project,
|
||||
projectPlugins: Seq[AutoPlugin],
|
||||
loadedPlugins: LoadedPlugins,
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@ package sbt
|
|||
package internal
|
||||
package server
|
||||
|
||||
import java.net.{ Socket, SocketTimeoutException, URI }
|
||||
import java.net.{ Socket, SocketTimeoutException }
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import scala.util.{ Left, Right }
|
||||
import sbt.protocol._
|
||||
import sjsonnew._
|
||||
|
||||
final class NetworkChannel(val name: String, connection: Socket, structure: BuildStructure, currentBuild: URI) extends CommandChannel {
|
||||
final class NetworkChannel(val name: String, connection: Socket, structure: BuildStructure) extends CommandChannel {
|
||||
private val running = new AtomicBoolean(true)
|
||||
private val delimiter: Byte = '\n'.toByte
|
||||
private val out = connection.getOutputStream
|
||||
|
|
@ -79,32 +78,8 @@ final class NetworkChannel(val name: String, connection: Socket, structure: Buil
|
|||
private def onExecCommand(cmd: ExecCommand) =
|
||||
append(Exec(cmd.commandLine, cmd.execId orElse Some(Exec.newExecId), Some(CommandSource(name))))
|
||||
|
||||
private def onSettingQuery(req: SettingQuery) = {
|
||||
import sbt.internal.util.complete.Parser
|
||||
|
||||
val key = Parser.parse(req.setting, SettingQuery.scopedKeyParser(structure, currentBuild))
|
||||
|
||||
def getSettingValue[A](key: Def.ScopedKey[A]) =
|
||||
structure.data.get(key.scope, key.key)
|
||||
.toRight(s"Key ${Def displayFull key} not found")
|
||||
.flatMap {
|
||||
case _: Task[_] => Left(s"Key ${Def displayFull key} is a task, can only query settings")
|
||||
case _: InputTask[_] => Left(s"Key ${Def displayFull key} is an input task, can only query settings")
|
||||
case x => Right(x)
|
||||
}
|
||||
|
||||
val values = key match {
|
||||
case Left(msg) => Left(s"Invalid programmatic input: $msg")
|
||||
case Right(key) => Right(getSettingValue(key))
|
||||
}
|
||||
|
||||
val jsonValues = values match {
|
||||
case Left(errors) => errors
|
||||
case Right(value) => value.toString
|
||||
}
|
||||
|
||||
StandardMain.exchange publishEventMessage SettingQueryResponse(jsonValues)
|
||||
}
|
||||
private def onSettingQuery(req: SettingQuery) =
|
||||
StandardMain.exchange publishEventMessage SettingQuery.handleSettingQuery(req, structure)
|
||||
|
||||
def shutdown(): Unit = {
|
||||
println("Shutting down client connection")
|
||||
|
|
@ -112,70 +87,3 @@ final class NetworkChannel(val name: String, connection: Socket, structure: Buil
|
|||
out.close()
|
||||
}
|
||||
}
|
||||
|
||||
object SettingQuery {
|
||||
import sbt.internal.util.{ AttributeKey, Settings }
|
||||
import sbt.internal.util.complete.{ DefaultParsers, Parser }, DefaultParsers._
|
||||
import sbt.Def.{ showBuildRelativeKey, ScopedKey }
|
||||
|
||||
// Similar to Act.ParsedAxis / Act.projectRef / Act.resolveProject except you can't omit the project reference
|
||||
|
||||
sealed trait ParsedExplicitAxis[+T]
|
||||
final object ParsedExplicitGlobal extends ParsedExplicitAxis[Nothing]
|
||||
final class ParsedExplicitValue[T](val value: T) extends ParsedExplicitAxis[T]
|
||||
def explicitValue[T](t: Parser[T]): Parser[ParsedExplicitAxis[T]] = t map { v => new ParsedExplicitValue(v) }
|
||||
|
||||
def projectRef(index: KeyIndex, currentBuild: URI): Parser[ParsedExplicitAxis[ResolvedReference]] = {
|
||||
val global = token(Act.GlobalString ~ '/') ^^^ ParsedExplicitGlobal
|
||||
val trailing = '/' !!! "Expected '/' (if selecting a project)"
|
||||
global | explicitValue(Act.resolvedReference(index, currentBuild, trailing))
|
||||
}
|
||||
|
||||
def resolveProject(parsed: ParsedExplicitAxis[ResolvedReference]): Option[ResolvedReference] = parsed match {
|
||||
case ParsedExplicitGlobal => None
|
||||
case pv: ParsedExplicitValue[_] => Some(pv.value)
|
||||
}
|
||||
|
||||
def scopedKeyFull(
|
||||
index: KeyIndex,
|
||||
currentBuild: URI,
|
||||
defaultConfigs: Option[ResolvedReference] => Seq[String],
|
||||
keyMap: Map[String, AttributeKey[_]]
|
||||
): Parser[Seq[Parser[ParsedKey]]] = {
|
||||
for {
|
||||
rawProject <- projectRef(index, currentBuild)
|
||||
proj = resolveProject(rawProject)
|
||||
confAmb <- Act.config(index configs proj)
|
||||
partialMask = ScopeMask(true, confAmb.isExplicit, false, false)
|
||||
} yield Act.taskKeyExtra(index, defaultConfigs, keyMap, 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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package sbt
|
||||
package internal
|
||||
package server
|
||||
|
||||
import java.net.URI
|
||||
import scala.json.ast.unsafe.JValue
|
||||
import scala.util.{ Left, Right }
|
||||
import sbt.util.{ SomeJsonWriter, NoJsonWriter }
|
||||
import sbt.librarymanagement.LibraryManagementCodec._
|
||||
import sbt.protocol._
|
||||
import sjsonnew._
|
||||
import sjsonnew.support.scalajson.unsafe._
|
||||
|
||||
object SettingQuery {
|
||||
import sbt.internal.util.{ AttributeKey, Settings }
|
||||
import sbt.internal.util.complete.{ DefaultParsers, Parser }, DefaultParsers._
|
||||
import sbt.Def.{ showBuildRelativeKey, ScopedKey }
|
||||
|
||||
// Similar to Act.ParsedAxis / Act.projectRef / Act.resolveProject except you can't omit the project reference
|
||||
|
||||
sealed trait ParsedExplicitAxis[+T]
|
||||
final object ParsedExplicitGlobal extends ParsedExplicitAxis[Nothing]
|
||||
final class ParsedExplicitValue[T](val value: T) extends ParsedExplicitAxis[T]
|
||||
def explicitValue[T](t: Parser[T]): Parser[ParsedExplicitAxis[T]] = t map { v => new ParsedExplicitValue(v) }
|
||||
|
||||
def projectRef(index: KeyIndex, currentBuild: URI): Parser[ParsedExplicitAxis[ResolvedReference]] = {
|
||||
val global = token(Act.GlobalString ~ '/') ^^^ ParsedExplicitGlobal
|
||||
val trailing = '/' !!! "Expected '/' (if selecting a project)"
|
||||
global | explicitValue(Act.resolvedReference(index, currentBuild, trailing))
|
||||
}
|
||||
|
||||
def resolveProject(parsed: ParsedExplicitAxis[ResolvedReference]): Option[ResolvedReference] = parsed match {
|
||||
case ParsedExplicitGlobal => None
|
||||
case pv: ParsedExplicitValue[_] => Some(pv.value)
|
||||
}
|
||||
|
||||
def scopedKeyFull(
|
||||
index: KeyIndex,
|
||||
currentBuild: URI,
|
||||
defaultConfigs: Option[ResolvedReference] => Seq[String],
|
||||
keyMap: Map[String, AttributeKey[_]]
|
||||
): Parser[Seq[Parser[ParsedKey]]] = {
|
||||
for {
|
||||
rawProject <- projectRef(index, currentBuild)
|
||||
proj = resolveProject(rawProject)
|
||||
confAmb <- Act.config(index configs proj)
|
||||
partialMask = ScopeMask(true, confAmb.isExplicit, false, false)
|
||||
} yield Act.taskKeyExtra(index, defaultConfigs, keyMap, proj, confAmb, partialMask)
|
||||
}
|
||||
|
||||
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(structure: BuildStructure): Parser[ScopedKey[_]] =
|
||||
scopedKey(
|
||||
structure.index.keyIndex,
|
||||
structure.root,
|
||||
structure.extra.configurationsForAxis,
|
||||
structure.index.keyMap,
|
||||
structure.data
|
||||
)
|
||||
|
||||
def getSettingValue[A](structure: BuildStructure, key: Def.ScopedKey[A]): Either[String, A] =
|
||||
structure.data.get(key.scope, key.key)
|
||||
.toRight(s"Key ${Def displayFull key} not found")
|
||||
.flatMap {
|
||||
case _: Task[_] => Left(s"Key ${Def displayFull key} is a task, can only query settings")
|
||||
case _: InputTask[_] => Left(s"Key ${Def displayFull key} is an input task, can only query settings")
|
||||
case x => Right(x)
|
||||
}
|
||||
|
||||
def getJsonWriter[A](key: AttributeKey[A]): Either[String, JsonWriter[A]] = key.optJsonWriter match {
|
||||
case SomeJsonWriter(jw) => Right(jw)
|
||||
case NoJsonWriter() => Left(s"JsonWriter for ${key.manifest} not found")
|
||||
}
|
||||
|
||||
def toJson[A: JsonWriter](x: A): JValue = Converter toJsonUnsafe x
|
||||
|
||||
def getSettingJsonValue[A](structure: BuildStructure, key: Def.ScopedKey[A]): Either[String, JValue] =
|
||||
getSettingValue(structure, key) flatMap (value =>
|
||||
getJsonWriter(key.key) map { implicit jw: JsonWriter[A] => toJson(value) }
|
||||
)
|
||||
|
||||
def handleSettingQuery(req: SettingQuery, structure: BuildStructure): SettingQueryResponse = {
|
||||
val key = Parser.parse(req.setting, scopedKeyParser(structure))
|
||||
|
||||
val result =
|
||||
for {
|
||||
key <- key
|
||||
json <- getSettingJsonValue(structure, key)
|
||||
} yield SettingQuerySuccess(json, key.key.manifest.toString)
|
||||
|
||||
result match {
|
||||
case Right(x) => x
|
||||
case Left(s) => SettingQueryFailure(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
package sbt
|
||||
package internal
|
||||
package server
|
||||
|
||||
import java.io._
|
||||
import java.net._
|
||||
import java.nio.file._
|
||||
import java.util.concurrent._
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
import xsbti._
|
||||
import sbt.io.IO
|
||||
import sbt.internal.util._
|
||||
import sbt.internal.BuildStreams.{ Streams => _, _ }
|
||||
import sbt.internal.Load._
|
||||
import sbt.util._
|
||||
import sbt.BuildPaths._
|
||||
import sbt.Def.{ ScopeLocal, ScopedKey, Setting }
|
||||
import sbt.Keys._
|
||||
|
||||
object SettingQueryTest extends org.specs2.mutable.Specification {
|
||||
implicit class PathOps(val path: Path) extends AnyVal {
|
||||
def /(other: String): Path = if (other == ".") path else path resolve other
|
||||
}
|
||||
|
||||
val baseDir: Path = Files createTempDirectory "sbt-setting-query-test"
|
||||
val globalDir: Path = Files createTempDirectory "sbt-setting-query-test-global-dir"
|
||||
val bootDir: Path = Files createTempDirectory "sbt-setting-query-test-boot-dir"
|
||||
val ivyHome: Path = Files createTempDirectory "sbt-setting-query-test-ivy-home"
|
||||
val logFile: File = File.createTempFile("sbt", ".log")
|
||||
|
||||
val baseFile: File = baseDir.toFile
|
||||
val baseUri: URI = IO directoryURI baseFile
|
||||
IO assertAbsolute baseUri
|
||||
|
||||
val globalDirFile: File = globalDir.toFile
|
||||
|
||||
def ??? : Nothing = { Thread.dumpStack(); throw new NotImplementedError }
|
||||
|
||||
val noopLoader: ClassLoader = new URLClassLoader(Array(), null)
|
||||
|
||||
object NoGlobalLock extends GlobalLock { def apply[T](lockFile: File, run: Callable[T]) = run.call() }
|
||||
|
||||
lazy val structure: BuildStructure = {
|
||||
val projectSettings: Seq[Setting[_]] = Seq(scalaVersion := "2.12.1")
|
||||
|
||||
val appConfig: AppConfiguration = new AppConfiguration {
|
||||
def baseDirectory(): File = baseFile
|
||||
def arguments(): Array[String] = Array()
|
||||
def provider(): AppProvider = new AppProvider {
|
||||
def scalaProvider(): ScalaProvider = new ScalaProvider { scalaProvider =>
|
||||
def launcher(): Launcher = new Launcher {
|
||||
def getScala(version: String): ScalaProvider = getScala(version, "")
|
||||
def getScala(version: String, reason: String): ScalaProvider = getScala(version, reason, "org.scala-lang")
|
||||
def getScala(version: String, reason: String, scalaOrg: String): ScalaProvider = scalaProvider
|
||||
|
||||
def app(id: ApplicationID, version: String): AppProvider = ???
|
||||
|
||||
def topLoader(): ClassLoader = noopLoader
|
||||
def globalLock(): GlobalLock = NoGlobalLock
|
||||
def bootDirectory(): File = bootDir.toFile
|
||||
def ivyRepositories(): Array[Repository] = Array()
|
||||
def appRepositories(): Array[Repository] = Array()
|
||||
def isOverrideRepositories: Boolean = false
|
||||
def ivyHome(): File = SettingQueryTest.this.ivyHome.toFile
|
||||
def checksums(): Array[String] = Array()
|
||||
}
|
||||
def version(): String = "2.12.1"
|
||||
|
||||
def loader(): ClassLoader = noopLoader
|
||||
def jars(): Array[File] = Array(libraryJar, compilerJar)
|
||||
|
||||
def libraryJar(): File = new File("scala-library.jar")
|
||||
def compilerJar(): File = new File("scala-compiler.jar")
|
||||
|
||||
def app(id: ApplicationID): AppProvider = ???
|
||||
}
|
||||
|
||||
def id(): ApplicationID = sbt.ApplicationID(
|
||||
"org.scala-sbt", "sbt", "0.13.13", "sbt.xMain",
|
||||
components = Seq(), crossVersionedValue = CrossValue.Disabled, extra = Seq()
|
||||
)
|
||||
|
||||
def loader(): ClassLoader = noopLoader
|
||||
|
||||
def entryPoint(): Class[_] = ???
|
||||
def mainClass(): Class[_ <: AppMain] = ???
|
||||
def newMain(): AppMain = ???
|
||||
|
||||
def mainClasspath(): Array[File] = Array()
|
||||
|
||||
def components(): ComponentProvider = new ComponentProvider {
|
||||
def componentLocation(id: String): File = ???
|
||||
def component(componentID: String): Array[File] = ???
|
||||
def defineComponent(componentID: String, components: Array[File]): Unit = ???
|
||||
def addToComponent(componentID: String, components: Array[File]): Boolean = ???
|
||||
def lockFile(): File = ???
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val state: State =
|
||||
StandardMain.initialState(appConfig, initialDefinitions = Seq(), preCommands = Seq())
|
||||
.put(globalBaseDirectory, globalDirFile)
|
||||
|
||||
val config0 = defaultPreGlobal(state, baseFile, globalDirFile, state.log)
|
||||
val config = defaultWithGlobal(state, baseFile, config0, globalDirFile, state.log)
|
||||
|
||||
val buildUnit: BuildUnit = {
|
||||
val loadedPlugins: LoadedPlugins =
|
||||
noPlugins(projectStandard(baseFile), config.copy(pluginManagement = config.pluginManagement.forPlugin))
|
||||
|
||||
val project: Project = {
|
||||
val project0 = Project("t", baseFile) settings projectSettings
|
||||
val fileToLoadedSbtFileMap = new mutable.HashMap[File, LoadedSbtFile]
|
||||
val autoPlugins = loadedPlugins.detected.deducePluginsFromProject(project0, state.log)
|
||||
val injectSettings = config.injectSettings
|
||||
resolveProject(project0, autoPlugins, loadedPlugins, injectSettings, fileToLoadedSbtFileMap, state.log)
|
||||
}
|
||||
|
||||
val projects: Seq[Project] = Seq(project)
|
||||
val builds: Seq[BuildDef] = BuildDef.defaultAggregated(project.id, Nil) :: Nil
|
||||
val defs: LoadedDefinitions = new LoadedDefinitions(baseFile, Nil, noopLoader, builds, projects, Nil)
|
||||
new BuildUnit(baseUri, baseFile, defs, loadedPlugins)
|
||||
}
|
||||
|
||||
val (partBuildUnit: PartBuildUnit, projectRefs: List[ProjectReference]) = loaded(buildUnit)
|
||||
val partBuildUnits: Map[URI, PartBuildUnit] = Map(buildUnit.uri -> partBuildUnit)
|
||||
val allProjectRefs: Map[URI, List[ProjectReference]] = Map(buildUnit.uri -> projectRefs)
|
||||
checkAll(allProjectRefs, partBuildUnits)
|
||||
|
||||
val partBuild: PartBuild = new PartBuild(baseUri, partBuildUnits)
|
||||
val loadedBuild: LoadedBuild = resolveProjects(partBuild)
|
||||
|
||||
val units: Map[URI, LoadedBuildUnit] = loadedBuild.units
|
||||
|
||||
val settings: Seq[Setting[_]] = finalTransforms(buildConfigurations(loadedBuild, getRootProject(units), config.injectSettings))
|
||||
val delegates: Scope => Seq[Scope] = defaultDelegates(loadedBuild)
|
||||
val scopeLocal: ScopeLocal = EvaluateTask.injectStreams
|
||||
val display: Show[ScopedKey[_]] = Project showLoadingKey loadedBuild
|
||||
|
||||
val data: Settings[Scope] = Def.make(settings)(delegates, scopeLocal, display)
|
||||
val extra: KeyIndex => BuildUtil[_] = index => BuildUtil(baseUri, units, index, data)
|
||||
|
||||
val index: StructureIndex = structureIndex(data, settings, extra, units)
|
||||
val streams: State => Streams = mkStreams(units, baseUri, data)
|
||||
|
||||
val structure: BuildStructure =
|
||||
new BuildStructure(units, baseUri, settings, data, index, streams, delegates, scopeLocal)
|
||||
|
||||
structure
|
||||
}
|
||||
|
||||
def query(setting: String): String = {
|
||||
import sbt.protocol._
|
||||
val req: SettingQuery = protocol.SettingQuery(setting)
|
||||
val rsp: SettingQueryResponse = server.SettingQuery.handleSettingQuery(req, structure)
|
||||
val bytes: Array[Byte] = Serialization serializeEventMessage rsp
|
||||
val payload: String = new String(bytes, java.nio.charset.StandardCharsets.UTF_8)
|
||||
payload
|
||||
}
|
||||
|
||||
// -.- avoid specs2's ko/ok
|
||||
import org.specs2.matcher.MatchResult
|
||||
def qok(x: String, t: String): String => MatchResult[Any] = query(_) must_== """{"type":"SettingQuerySuccess","value":""" + x + ""","contentType":"""" + t + """"}"""
|
||||
def qko(msg: String): String => MatchResult[Any] = query(_) must_== """{"type":"SettingQueryFailure","message":"""" + msg + """"}"""
|
||||
|
||||
"setting query" should {
|
||||
"t/scalaVersion" in qok("\"2.12.1\"", "java.lang.String")
|
||||
"t/pollInterval" in qok("500", "Int")
|
||||
"t/sourcesInBase" in qok("true", "Boolean")
|
||||
"t/startYear" in qok("null", "scala.Option[Int]")
|
||||
"t/scalaArtifacts" in qok("""["scala-library","scala-compiler","scala-reflect","scala-actors","scalap"]""", "scala.collection.Seq[java.lang.String]")
|
||||
|
||||
"t/libraryDependencies" in qok(
|
||||
"""[{"organization":"org.scala-lang","name":"scala-library","revision":"2.12.1","isChanging":false,"isTransitive":true,"isForce":false,"crossVersion":{"type":"Disabled"}}]""",
|
||||
"scala.collection.Seq[sbt.librarymanagement.ModuleID]")
|
||||
|
||||
"scalaVersion" in qko("Not a valid project ID: scalaVersion\\nscalaVersion\\n ^")
|
||||
"t/scalacOptions" in qko(s"Key {$baseUri}t/compile:scalacOptions is a task, can only query settings")
|
||||
"t/fooo" in qko("Expected ':' (if selecting a configuration)\\nNot a valid key: fooo (similar: fork)\\nt/fooo\\n ^")
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ object ContrabandConfig {
|
|||
case "Option" | "Set" | "scala.Vector" => { tpe => getFormats(oneArg(tpe)) }
|
||||
case "Map" | "Tuple2" | "scala.Tuple2" => { tpe => twoArgs(tpe).flatMap(getFormats) }
|
||||
case "Int" | "Long" => { _ => Nil }
|
||||
case "scala.json.ast.unsafe.JValue" => { _ => "sbt.internal.JValueFormat" :: Nil }
|
||||
}
|
||||
|
||||
/** Returns the list of formats required to encode the given `TpeRef`. */
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
import sbt._
|
||||
import sbt.Keys._
|
||||
import com.typesafe.sbt.SbtScalariform._
|
||||
import ScalariformKeys.{ format => scalariformFormat, preferences => scalariformPreferences }
|
||||
import sbt._, Keys._
|
||||
import com.typesafe.sbt.SbtScalariform._, autoImport._
|
||||
|
||||
object Formatting {
|
||||
lazy val BuildConfig = config("build") extend Compile
|
||||
lazy val BuildSbtConfig = config("buildsbt") extend Compile
|
||||
val BuildConfig = config("build") extend Compile
|
||||
val BuildSbtConfig = config("buildsbt") extend Compile
|
||||
|
||||
val scalariformCheck = taskKey[Unit]("Checks that the existing code is formatted, via git diff")
|
||||
|
||||
lazy val prefs: Seq[Setting[_]] = {
|
||||
private val prefs: Seq[Setting[_]] = {
|
||||
import scalariform.formatter.preferences._
|
||||
Seq(
|
||||
scalariformPreferences ~= (_
|
||||
|
|
@ -20,8 +18,8 @@ object Formatting {
|
|||
)
|
||||
}
|
||||
|
||||
lazy val settings: Seq[Setting[_]] = Seq() ++ scalariformSettings ++ prefs
|
||||
lazy val sbtFilesSettings: Seq[Setting[_]] = Seq() ++ scalariformSettings ++ prefs ++
|
||||
val settings: Seq[Setting[_]] = Seq() ++ prefs
|
||||
val sbtFilesSettings: Seq[Setting[_]] = Seq() ++ prefs ++
|
||||
inConfig(BuildConfig)(configScalariformSettings) ++
|
||||
inConfig(BuildSbtConfig)(configScalariformSettings) ++
|
||||
Seq(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol
|
||||
final class SettingQueryFailure private (
|
||||
val message: String) extends sbt.protocol.SettingQueryResponse() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case x: SettingQueryFailure => (this.message == x.message)
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (17 + message.##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"SettingQueryFailure(" + message + ")"
|
||||
}
|
||||
protected[this] def copy(message: String = message): SettingQueryFailure = {
|
||||
new SettingQueryFailure(message)
|
||||
}
|
||||
def withMessage(message: String): SettingQueryFailure = {
|
||||
copy(message = message)
|
||||
}
|
||||
}
|
||||
object SettingQueryFailure {
|
||||
|
||||
def apply(message: String): SettingQueryFailure = new SettingQueryFailure(message)
|
||||
}
|
||||
|
|
@ -4,29 +4,22 @@
|
|||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol
|
||||
final class SettingQueryResponse private (
|
||||
val value: String) extends sbt.protocol.EventMessage() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case x: SettingQueryResponse => (this.value == x.value)
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (17 + value.##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"SettingQueryResponse(" + value + ")"
|
||||
}
|
||||
protected[this] def copy(value: String = value): SettingQueryResponse = {
|
||||
new SettingQueryResponse(value)
|
||||
}
|
||||
def withValue(value: String): SettingQueryResponse = {
|
||||
copy(value = value)
|
||||
}
|
||||
abstract class SettingQueryResponse() extends sbt.protocol.EventMessage() with Serializable {
|
||||
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case x: SettingQueryResponse => true
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
17
|
||||
}
|
||||
override def toString: String = {
|
||||
"SettingQueryResponse()"
|
||||
}
|
||||
}
|
||||
object SettingQueryResponse {
|
||||
|
||||
def apply(value: String): SettingQueryResponse = new SettingQueryResponse(value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol
|
||||
final class SettingQuerySuccess private (
|
||||
val value: scala.json.ast.unsafe.JValue,
|
||||
val contentType: String) extends sbt.protocol.SettingQueryResponse() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case x: SettingQuerySuccess => (this.value == x.value) && (this.contentType == x.contentType)
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (37 * (17 + value.##) + contentType.##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"SettingQuerySuccess(" + value + ", " + contentType + ")"
|
||||
}
|
||||
protected[this] def copy(value: scala.json.ast.unsafe.JValue = value, contentType: String = contentType): SettingQuerySuccess = {
|
||||
new SettingQuerySuccess(value, contentType)
|
||||
}
|
||||
def withValue(value: scala.json.ast.unsafe.JValue): SettingQuerySuccess = {
|
||||
copy(value = value)
|
||||
}
|
||||
def withContentType(contentType: String): SettingQuerySuccess = {
|
||||
copy(contentType = contentType)
|
||||
}
|
||||
}
|
||||
object SettingQuerySuccess {
|
||||
|
||||
def apply(value: scala.json.ast.unsafe.JValue, contentType: String): SettingQuerySuccess = new SettingQuerySuccess(value, contentType)
|
||||
}
|
||||
|
|
@ -5,6 +5,6 @@
|
|||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
||||
trait EventMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ChannelAcceptedEventFormats with sbt.protocol.codec.LogEventFormats with sbt.protocol.codec.ExecStatusEventFormats with sbt.protocol.codec.SettingQueryResponseFormats =>
|
||||
implicit lazy val EventMessageFormat: JsonFormat[sbt.protocol.EventMessage] = flatUnionFormat4[sbt.protocol.EventMessage, sbt.protocol.ChannelAcceptedEvent, sbt.protocol.LogEvent, sbt.protocol.ExecStatusEvent, sbt.protocol.SettingQueryResponse]("type")
|
||||
trait EventMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ChannelAcceptedEventFormats with sbt.protocol.codec.LogEventFormats with sbt.protocol.codec.ExecStatusEventFormats with sbt.internal.JValueFormat with sbt.protocol.codec.SettingQuerySuccessFormats with sbt.protocol.codec.SettingQueryFailureFormats =>
|
||||
implicit lazy val EventMessageFormat: JsonFormat[sbt.protocol.EventMessage] = flatUnionFormat5[sbt.protocol.EventMessage, sbt.protocol.ChannelAcceptedEvent, sbt.protocol.LogEvent, sbt.protocol.ExecStatusEvent, sbt.protocol.SettingQuerySuccess, sbt.protocol.SettingQueryFailure]("type")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
|
|||
with sbt.protocol.codec.ChannelAcceptedEventFormats
|
||||
with sbt.protocol.codec.LogEventFormats
|
||||
with sbt.protocol.codec.ExecStatusEventFormats
|
||||
with sbt.protocol.codec.SettingQueryResponseFormats
|
||||
with sbt.internal.JValueFormat
|
||||
with sbt.protocol.codec.SettingQuerySuccessFormats
|
||||
with sbt.protocol.codec.SettingQueryFailureFormats
|
||||
with sbt.protocol.codec.EventMessageFormats
|
||||
with sbt.protocol.codec.SettingQueryResponseFormats
|
||||
with sbt.protocol.codec.ExecutionEventFormats
|
||||
object JsonProtocol extends JsonProtocol
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
||||
trait SettingQueryFailureFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val SettingQueryFailureFormat: JsonFormat[sbt.protocol.SettingQueryFailure] = new JsonFormat[sbt.protocol.SettingQueryFailure] {
|
||||
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.SettingQueryFailure = {
|
||||
jsOpt match {
|
||||
case Some(js) =>
|
||||
unbuilder.beginObject(js)
|
||||
val message = unbuilder.readField[String]("message")
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.SettingQueryFailure(message)
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.protocol.SettingQueryFailure, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
builder.addField("message", obj.message)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,23 +5,6 @@
|
|||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
||||
trait SettingQueryResponseFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val SettingQueryResponseFormat: JsonFormat[sbt.protocol.SettingQueryResponse] = new JsonFormat[sbt.protocol.SettingQueryResponse] {
|
||||
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.SettingQueryResponse = {
|
||||
jsOpt match {
|
||||
case Some(js) =>
|
||||
unbuilder.beginObject(js)
|
||||
val value = unbuilder.readField[String]("value")
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.SettingQueryResponse(value)
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.protocol.SettingQueryResponse, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
builder.addField("value", obj.value)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
trait SettingQueryResponseFormats { self: sbt.internal.JValueFormat with sjsonnew.BasicJsonProtocol with sbt.protocol.codec.SettingQuerySuccessFormats with sbt.protocol.codec.SettingQueryFailureFormats =>
|
||||
implicit lazy val SettingQueryResponseFormat: JsonFormat[sbt.protocol.SettingQueryResponse] = flatUnionFormat2[sbt.protocol.SettingQueryResponse, sbt.protocol.SettingQuerySuccess, sbt.protocol.SettingQueryFailure]("type")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
||||
trait SettingQuerySuccessFormats { self: sbt.internal.JValueFormat with sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val SettingQuerySuccessFormat: JsonFormat[sbt.protocol.SettingQuerySuccess] = new JsonFormat[sbt.protocol.SettingQuerySuccess] {
|
||||
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.SettingQuerySuccess = {
|
||||
jsOpt match {
|
||||
case Some(js) =>
|
||||
unbuilder.beginObject(js)
|
||||
val value = unbuilder.readField[scala.json.ast.unsafe.JValue]("value")
|
||||
val contentType = unbuilder.readField[String]("contentType")
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.SettingQuerySuccess(value, contentType)
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.protocol.SettingQuerySuccess, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
builder.addField("value", obj.value)
|
||||
builder.addField("contentType", obj.contentType)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,8 +40,15 @@ type ExecStatusEvent implements EventMessage {
|
|||
commandQueue: [String]
|
||||
}
|
||||
|
||||
type SettingQueryResponse implements EventMessage {
|
||||
value: String!
|
||||
interface SettingQueryResponse implements EventMessage {}
|
||||
|
||||
type SettingQuerySuccess implements SettingQueryResponse {
|
||||
value: scala.json.ast.unsafe.JValue!
|
||||
contentType: String!
|
||||
}
|
||||
|
||||
type SettingQueryFailure implements SettingQueryResponse {
|
||||
message: String!
|
||||
}
|
||||
|
||||
# enum Status {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package sbt
|
||||
package internal
|
||||
|
||||
import sjsonnew.{ JsonWriter => JW, JsonReader => JR, JsonFormat => JF, _ }
|
||||
import scala.json.ast.unsafe._
|
||||
|
||||
trait JValueFormat { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit val JNullJF: JF[JNull.type] = new JF[JNull.type] {
|
||||
def write[J](x: JNull.type, b: Builder[J]) = b.writeNull()
|
||||
def read[J](j: Option[J], u: Unbuilder[J]) = JNull
|
||||
}
|
||||
|
||||
implicit val JBooleanJF: JF[JBoolean] = project(_.get, JBoolean(_))
|
||||
implicit val JStringJF: JF[JString] = project(_.value, JString(_))
|
||||
implicit val JNumberJF: JF[JNumber] = project(x => BigDecimal(x.value), (x: BigDecimal) => JNumber(x.toString))
|
||||
implicit val JArrayJF: JF[JArray] = project[JArray, Array[JValue]](_.value, JArray(_))
|
||||
|
||||
implicit lazy val JObjectJW: JW[JObject] = new JW[JObject] {
|
||||
def write[J](x: JObject, b: Builder[J]) = {
|
||||
b.beginObject()
|
||||
x.value foreach (jsonField => JValueJW.addField(jsonField.field, jsonField.value, b))
|
||||
b.endObject()
|
||||
}
|
||||
}
|
||||
|
||||
implicit lazy val JValueJW: JW[JValue] = new JW[JValue] {
|
||||
def write[J](x: JValue, b: Builder[J]) = x match {
|
||||
case x: JNull.type => JNullJF.write(x, b)
|
||||
case x: JBoolean => JBooleanJF.write(x, b)
|
||||
case x: JString => JStringJF.write(x, b)
|
||||
case x: JNumber => JNumberJF.write(x, b)
|
||||
case x: JArray => JArrayJF.write(x, b)
|
||||
case x: JObject => JObjectJW.write(x, b)
|
||||
}
|
||||
}
|
||||
|
||||
implicit lazy val JValueJR: JR[JValue] = new JR[JValue] {
|
||||
def read[J](j: Option[J], u: Unbuilder[J]) = ??? // Is this even possible? with no Manifest[J]?
|
||||
}
|
||||
|
||||
implicit lazy val JValueJF: JF[JValue] = jsonFormat[JValue](JValueJR, JValueJW)
|
||||
}
|
||||
Loading…
Reference in New Issue