From 43eec230e66a835d866910b065909a3c9f2ae222 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 20 Mar 2017 16:44:57 +0000 Subject: [PATCH] Switch SettingQueryResponse to JValue, implement JValueFormat --- build.sbt | 4 +- .../sbt/internal/server/SettingQuery.scala | 26 +++++--- project/ContrabandConfig.scala | 1 + .../sbt/protocol/SettingQueryResponse.scala | 8 +-- .../protocol/codec/EventMessageFormats.scala | 2 +- .../sbt/protocol/codec/JsonProtocol.scala | 1 + .../codec/SettingQueryResponseFormats.scala | 4 +- protocol/src/main/contraband/server.contra | 2 +- .../scala/sbt/internal/JValueFormat.scala | 61 +++++++++++++++++++ 9 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 protocol/src/main/scala/sbt/internal/JValueFormat.scala diff --git a/build.sbt b/build.sbt index b8ff283b6..d4fc0cbab 100644 --- a/build.sbt +++ b/build.sbt @@ -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", diff --git a/main/src/main/scala/sbt/internal/server/SettingQuery.scala b/main/src/main/scala/sbt/internal/server/SettingQuery.scala index 84c98232c..0a290b934 100644 --- a/main/src/main/scala/sbt/internal/server/SettingQuery.scala +++ b/main/src/main/scala/sbt/internal/server/SettingQuery.scala @@ -6,9 +6,10 @@ package internal package server import java.net.URI +import scala.json.ast.unsafe.JValue import scala.util.{ Left, Right } +import sbt.librarymanagement.LibraryManagementCodec._ import sbt.protocol._ -import sjsonnew._ import sjsonnew.support.scalajson.unsafe._ object SettingQuery { @@ -86,25 +87,30 @@ object SettingQuery { case x => Right(x) } - def toJsonStringStrict[A: Manifest](x: A): Either[String, String] = + def toJsonStringStrict[A: Manifest](x: A): Either[String, JValue] = JsonFormatRegistry.lookup[A] .toRight(s"JsonWriter for ${manifest[A]} not found") - .map(implicit jsonWriter => CompactPrinter(Converter.toJsonUnsafe(x))) + .map(implicit jsonWriter => Converter toJsonUnsafe x) - def toJsonString[A: Manifest](x: A): String = + def toJson[A: Manifest](x: A): JValue = toJsonStringStrict(x) match { - case Right(s) => s - case Left(_) => x.toString + case Right(j) => j + case Left(_) => Converter toJsonUnsafe x.toString } - def getSettingJsonStringValue[A](structure: BuildStructure, key: Def.ScopedKey[A]): Either[String, String] = - getSettingValue(structure, key) map (toJsonString(_)(key.key.manifest)) + def getSettingJsonStringValue[A](structure: BuildStructure, key: Def.ScopedKey[A]): Either[String, JValue] = + getSettingValue(structure, key) map (toJson(_)(key.key.manifest)) def handleSettingQuery(req: SettingQuery, structure: BuildStructure): SettingQueryResponse = { val key = Parser.parse(req.setting, scopedKeyParser(structure)) - val result: Either[String, String] = key flatMap (getSettingJsonStringValue(structure, _)) + val result: Either[String, JValue] = key flatMap (getSettingJsonStringValue(structure, _)) - SettingQueryResponse(result.merge) + val finalResult: JValue = result match { + case Right(j) => j + case Left(s) => Converter toJsonUnsafe s + } + + SettingQueryResponse(finalResult) } } diff --git a/project/ContrabandConfig.scala b/project/ContrabandConfig.scala index d57d87afa..7fb8a2b8e 100644 --- a/project/ContrabandConfig.scala +++ b/project/ContrabandConfig.scala @@ -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`. */ diff --git a/protocol/src/main/contraband-scala/sbt/protocol/SettingQueryResponse.scala b/protocol/src/main/contraband-scala/sbt/protocol/SettingQueryResponse.scala index 0c7878968..633801200 100644 --- a/protocol/src/main/contraband-scala/sbt/protocol/SettingQueryResponse.scala +++ b/protocol/src/main/contraband-scala/sbt/protocol/SettingQueryResponse.scala @@ -5,7 +5,7 @@ // DO NOT EDIT MANUALLY package sbt.protocol final class SettingQueryResponse private ( - val value: String) extends sbt.protocol.EventMessage() with Serializable { + val value: scala.json.ast.unsafe.JValue) extends sbt.protocol.EventMessage() with Serializable { @@ -19,14 +19,14 @@ final class SettingQueryResponse private ( override def toString: String = { "SettingQueryResponse(" + value + ")" } - protected[this] def copy(value: String = value): SettingQueryResponse = { + protected[this] def copy(value: scala.json.ast.unsafe.JValue = value): SettingQueryResponse = { new SettingQueryResponse(value) } - def withValue(value: String): SettingQueryResponse = { + def withValue(value: scala.json.ast.unsafe.JValue): SettingQueryResponse = { copy(value = value) } } object SettingQueryResponse { - def apply(value: String): SettingQueryResponse = new SettingQueryResponse(value) + def apply(value: scala.json.ast.unsafe.JValue): SettingQueryResponse = new SettingQueryResponse(value) } diff --git a/protocol/src/main/contraband-scala/sbt/protocol/codec/EventMessageFormats.scala b/protocol/src/main/contraband-scala/sbt/protocol/codec/EventMessageFormats.scala index 41ffd6dc9..d74e27dce 100644 --- a/protocol/src/main/contraband-scala/sbt/protocol/codec/EventMessageFormats.scala +++ b/protocol/src/main/contraband-scala/sbt/protocol/codec/EventMessageFormats.scala @@ -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 => +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.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") } diff --git a/protocol/src/main/contraband-scala/sbt/protocol/codec/JsonProtocol.scala b/protocol/src/main/contraband-scala/sbt/protocol/codec/JsonProtocol.scala index e2a840a52..e91f6606c 100644 --- a/protocol/src/main/contraband-scala/sbt/protocol/codec/JsonProtocol.scala +++ b/protocol/src/main/contraband-scala/sbt/protocol/codec/JsonProtocol.scala @@ -11,6 +11,7 @@ trait JsonProtocol extends 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.SettingQueryResponseFormats with sbt.protocol.codec.EventMessageFormats with sbt.protocol.codec.ExecutionEventFormats diff --git a/protocol/src/main/contraband-scala/sbt/protocol/codec/SettingQueryResponseFormats.scala b/protocol/src/main/contraband-scala/sbt/protocol/codec/SettingQueryResponseFormats.scala index ce7f7a217..45d0756c8 100644 --- a/protocol/src/main/contraband-scala/sbt/protocol/codec/SettingQueryResponseFormats.scala +++ b/protocol/src/main/contraband-scala/sbt/protocol/codec/SettingQueryResponseFormats.scala @@ -5,13 +5,13 @@ // DO NOT EDIT MANUALLY package sbt.protocol.codec import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder } -trait SettingQueryResponseFormats { self: sjsonnew.BasicJsonProtocol => +trait SettingQueryResponseFormats { self: sbt.internal.JValueFormat with 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") + val value = unbuilder.readField[scala.json.ast.unsafe.JValue]("value") unbuilder.endObject() sbt.protocol.SettingQueryResponse(value) case None => diff --git a/protocol/src/main/contraband/server.contra b/protocol/src/main/contraband/server.contra index 44103c0c1..7d9798aa8 100644 --- a/protocol/src/main/contraband/server.contra +++ b/protocol/src/main/contraband/server.contra @@ -41,7 +41,7 @@ type ExecStatusEvent implements EventMessage { } type SettingQueryResponse implements EventMessage { - value: String! + value: scala.json.ast.unsafe.JValue! } # enum Status { diff --git a/protocol/src/main/scala/sbt/internal/JValueFormat.scala b/protocol/src/main/scala/sbt/internal/JValueFormat.scala new file mode 100644 index 000000000..e74d3bc73 --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/JValueFormat.scala @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 Lightbend Inc. + */ +package sbt +package internal + +import sjsonnew.{ JsonWriter => JW, JsonReader => JR, JsonFormat => JF, _ } +import scala.json.ast.unsafe._ + +trait JValueFormat { self: sjsonnew.BasicJsonProtocol => + /** Define a JsonWriter for the type T wrapper of underlying type U given JsonWriter[U] and T => U. */ + def unlift[T, U](unlift: T => U)(implicit z: JW[U]): JW[T] = new JW[T] { + def write[J](w: T, b: Builder[J]) = z.write(unlift(w), b) + } + + /** Define a JsonReader for the type T wrapper of underlying type U given JsonReader[U] and U => T. */ + def lift[T, U](lift: U => T)(implicit z: JR[U]): JR[T] = new JR[T] { + def read[J](j: Option[J], u: Unbuilder[J]): T = lift(z.read(j, u)) + } + + @inline def ?[A](implicit z: A): A = z + + implicit val JNullJW: JW[JNull.type] = new JW[JNull.type] { def write[J](x: JNull.type, b: Builder[J]) = b.writeNull() } + implicit val JNullJR: JR[JNull.type] = new JR[JNull.type] { def read[J](j: Option[J], u: Unbuilder[J]) = JNull } + + implicit val JBooleanJW: JW[JBoolean] = unlift(_.get) + implicit val JBooleanJR: JR[JBoolean] = lift(JBoolean(_)) + + implicit val JStringJW: JW[JString] = unlift(_.value) + implicit val JStringJR: JR[JString] = lift(JString(_)) + + implicit val JNumberJW: JW[JNumber] = unlift(x => BigDecimal(x.value)) + implicit val JNumberJR: JR[JNumber] = lift((x: BigDecimal) => JNumber(x.toString)) + + implicit lazy val JArrayJW: JW[JArray] = unlift[JArray, Array[JValue]](_.value) + + 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 => ?[JW[JNull.type]].write(x, b) + case x: JBoolean => ?[JW[JBoolean]].write(x, b) + case x: JString => ?[JW[JString]].write(x, b) + case x: JNumber => ?[JW[JNumber]].write(x, b) + case x: JObject => ?[JW[JObject]].write(x, b) + case x: JArray => ?[JW[JArray]].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) +}