mirror of https://github.com/sbt/sbt.git
Using sbt-datatype + sjson-new for JSON serialization
This commit is contained in:
parent
e7456b5653
commit
18233ace05
|
|
@ -176,11 +176,13 @@ lazy val actionsProj = (project in file("main-actions")).
|
||||||
|
|
||||||
// General command support and core commands not specific to a build system
|
// General command support and core commands not specific to a build system
|
||||||
lazy val commandProj = (project in file("main-command")).
|
lazy val commandProj = (project in file("main-command")).
|
||||||
|
enablePlugins(DatatypePlugin, JsonCodecPlugin).
|
||||||
settings(
|
settings(
|
||||||
testedBaseSettings,
|
testedBaseSettings,
|
||||||
name := "Command",
|
name := "Command",
|
||||||
libraryDependencies ++= Seq(launcherInterface, compilerInterface,
|
libraryDependencies ++= Seq(launcherInterface, compilerInterface,
|
||||||
sbtIO, utilLogging, utilCompletion, compilerClasspath, json4s, json4sNative) // to transitively get json4s)
|
sbtIO, utilLogging, utilCompletion, compilerClasspath, sjsonNewScalaJson),
|
||||||
|
sourceManaged in (Compile, generateDatatypes) := baseDirectory.value / "src" / "main" / "datatype-scala"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fixes scope=Scope for Setting (core defined in collectionProj) to define the settings system used in build definitions
|
// Fixes scope=Scope for Setting (core defined in collectionProj) to define the settings system used in build definitions
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* This code is generated using sbt-datatype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DO NOT EDIT MANUALLY
|
||||||
|
package sbt.internal.server
|
||||||
|
final class CommandMessage(
|
||||||
|
val `type`: String,
|
||||||
|
val commandLine: Option[String]) extends Serializable {
|
||||||
|
|
||||||
|
def this(`type`: String) = this(`type`, None)
|
||||||
|
|
||||||
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
case x: CommandMessage => (this.`type` == x.`type`) && (this.commandLine == x.commandLine)
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
override def hashCode: Int = {
|
||||||
|
37 * (37 * (17 + `type`.##) + commandLine.##)
|
||||||
|
}
|
||||||
|
override def toString: String = {
|
||||||
|
"CommandMessage(" + `type` + ", " + commandLine + ")"
|
||||||
|
}
|
||||||
|
def copy(`type`: String): CommandMessage = {
|
||||||
|
new CommandMessage(`type`, commandLine)
|
||||||
|
}
|
||||||
|
def copy(`type`: String = `type`, commandLine: Option[String] = commandLine): CommandMessage = {
|
||||||
|
new CommandMessage(`type`, commandLine)
|
||||||
|
}
|
||||||
|
def withType(`type`: String): CommandMessage = {
|
||||||
|
copy(`type` = `type`)
|
||||||
|
}
|
||||||
|
def withCommandLine(commandLine: Option[String]): CommandMessage = {
|
||||||
|
copy(commandLine = commandLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object CommandMessage {
|
||||||
|
def apply(`type`: String): CommandMessage = new CommandMessage(`type`, None)
|
||||||
|
def apply(`type`: String, commandLine: Option[String]): CommandMessage = new CommandMessage(`type`, commandLine)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
* This code is generated using sbt-datatype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DO NOT EDIT MANUALLY
|
||||||
|
package sbt.internal.server
|
||||||
|
final class EventMessage(
|
||||||
|
val `type`: String,
|
||||||
|
val status: Option[String],
|
||||||
|
val commandQueue: Vector[String],
|
||||||
|
val level: Option[String],
|
||||||
|
val message: Option[String],
|
||||||
|
val success: Option[Boolean],
|
||||||
|
val commandLine: Option[String]) extends Serializable {
|
||||||
|
|
||||||
|
def this(`type`: String) = this(`type`, None, Vector(), None, None, None, None)
|
||||||
|
|
||||||
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
case x: EventMessage => (this.`type` == x.`type`) && (this.status == x.status) && (this.commandQueue == x.commandQueue) && (this.level == x.level) && (this.message == x.message) && (this.success == x.success) && (this.commandLine == x.commandLine)
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
override def hashCode: Int = {
|
||||||
|
37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + `type`.##) + status.##) + commandQueue.##) + level.##) + message.##) + success.##) + commandLine.##)
|
||||||
|
}
|
||||||
|
override def toString: String = {
|
||||||
|
"EventMessage(" + `type` + ", " + status + ", " + commandQueue + ", " + level + ", " + message + ", " + success + ", " + commandLine + ")"
|
||||||
|
}
|
||||||
|
def copy(`type`: String): EventMessage = {
|
||||||
|
new EventMessage(`type`, status, commandQueue, level, message, success, commandLine)
|
||||||
|
}
|
||||||
|
def copy(`type`: String = `type`, status: Option[String] = status, commandQueue: Vector[String] = commandQueue, level: Option[String] = level, message: Option[String] = message, success: Option[Boolean] = success, commandLine: Option[String] = commandLine): EventMessage = {
|
||||||
|
new EventMessage(`type`, status, commandQueue, level, message, success, commandLine)
|
||||||
|
}
|
||||||
|
def withType(`type`: String): EventMessage = {
|
||||||
|
copy(`type` = `type`)
|
||||||
|
}
|
||||||
|
def withStatus(status: Option[String]): EventMessage = {
|
||||||
|
copy(status = status)
|
||||||
|
}
|
||||||
|
def withCommandQueue(commandQueue: Vector[String]): EventMessage = {
|
||||||
|
copy(commandQueue = commandQueue)
|
||||||
|
}
|
||||||
|
def withLevel(level: Option[String]): EventMessage = {
|
||||||
|
copy(level = level)
|
||||||
|
}
|
||||||
|
def withMessage(message: Option[String]): EventMessage = {
|
||||||
|
copy(message = message)
|
||||||
|
}
|
||||||
|
def withSuccess(success: Option[Boolean]): EventMessage = {
|
||||||
|
copy(success = success)
|
||||||
|
}
|
||||||
|
def withCommandLine(commandLine: Option[String]): EventMessage = {
|
||||||
|
copy(commandLine = commandLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object EventMessage {
|
||||||
|
def apply(`type`: String): EventMessage = new EventMessage(`type`, None, Vector(), None, None, None, None)
|
||||||
|
def apply(`type`: String, status: Option[String], commandQueue: Vector[String], level: Option[String], message: Option[String], success: Option[Boolean], commandLine: Option[String]): EventMessage = new EventMessage(`type`, status, commandQueue, level, message, success, commandLine)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/**
|
||||||
|
* This code is generated using sbt-datatype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DO NOT EDIT MANUALLY
|
||||||
|
package sbt.internal.server.codec
|
||||||
|
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
||||||
|
trait CommandMessageFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||||
|
implicit lazy val CommandMessageFormat: JsonFormat[sbt.internal.server.CommandMessage] = new JsonFormat[sbt.internal.server.CommandMessage] {
|
||||||
|
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.server.CommandMessage = {
|
||||||
|
jsOpt match {
|
||||||
|
case Some(js) =>
|
||||||
|
unbuilder.beginObject(js)
|
||||||
|
val `type` = unbuilder.readField[String]("type")
|
||||||
|
val commandLine = unbuilder.readField[Option[String]]("commandLine")
|
||||||
|
unbuilder.endObject()
|
||||||
|
new sbt.internal.server.CommandMessage(`type`, commandLine)
|
||||||
|
case None =>
|
||||||
|
deserializationError("Expected JsObject but found None")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override def write[J](obj: sbt.internal.server.CommandMessage, builder: Builder[J]): Unit = {
|
||||||
|
builder.beginObject()
|
||||||
|
builder.addField("type", obj.`type`)
|
||||||
|
builder.addField("commandLine", obj.commandLine)
|
||||||
|
builder.endObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* This code is generated using sbt-datatype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DO NOT EDIT MANUALLY
|
||||||
|
package sbt.internal.server.codec
|
||||||
|
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
||||||
|
trait EventMessageFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||||
|
implicit lazy val EventMessageFormat: JsonFormat[sbt.internal.server.EventMessage] = new JsonFormat[sbt.internal.server.EventMessage] {
|
||||||
|
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.server.EventMessage = {
|
||||||
|
jsOpt match {
|
||||||
|
case Some(js) =>
|
||||||
|
unbuilder.beginObject(js)
|
||||||
|
val `type` = unbuilder.readField[String]("type")
|
||||||
|
val status = unbuilder.readField[Option[String]]("status")
|
||||||
|
val commandQueue = unbuilder.readField[Vector[String]]("commandQueue")
|
||||||
|
val level = unbuilder.readField[Option[String]]("level")
|
||||||
|
val message = unbuilder.readField[Option[String]]("message")
|
||||||
|
val success = unbuilder.readField[Option[Boolean]]("success")
|
||||||
|
val commandLine = unbuilder.readField[Option[String]]("commandLine")
|
||||||
|
unbuilder.endObject()
|
||||||
|
new sbt.internal.server.EventMessage(`type`, status, commandQueue, level, message, success, commandLine)
|
||||||
|
case None =>
|
||||||
|
deserializationError("Expected JsObject but found None")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override def write[J](obj: sbt.internal.server.EventMessage, builder: Builder[J]): Unit = {
|
||||||
|
builder.beginObject()
|
||||||
|
builder.addField("type", obj.`type`)
|
||||||
|
builder.addField("status", obj.status)
|
||||||
|
builder.addField("commandQueue", obj.commandQueue)
|
||||||
|
builder.addField("level", obj.level)
|
||||||
|
builder.addField("message", obj.message)
|
||||||
|
builder.addField("success", obj.success)
|
||||||
|
builder.addField("commandLine", obj.commandLine)
|
||||||
|
builder.endObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
{
|
||||||
|
"codecNamespace": "sbt.internal.server.codec",
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"name": "CommandMessage",
|
||||||
|
"namespace": "sbt.internal.server",
|
||||||
|
"type": "record",
|
||||||
|
"target": "Scala",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "type",
|
||||||
|
"type": "String",
|
||||||
|
"since": "0.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "commandLine",
|
||||||
|
"type": "String?",
|
||||||
|
"default": "None",
|
||||||
|
"since": "0.1.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "EventMessage",
|
||||||
|
"namespace": "sbt.internal.server",
|
||||||
|
"type": "record",
|
||||||
|
"target": "Scala",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "type",
|
||||||
|
"type": "String",
|
||||||
|
"since": "0.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "status",
|
||||||
|
"type": "String?",
|
||||||
|
"default": "None",
|
||||||
|
"since": "0.1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "commandQueue",
|
||||||
|
"type": "String*",
|
||||||
|
"default": "Vector()",
|
||||||
|
"since": "0.1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "level",
|
||||||
|
"type": "String?",
|
||||||
|
"default": "None",
|
||||||
|
"since": "0.1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "message",
|
||||||
|
"type": "String?",
|
||||||
|
"default": "None",
|
||||||
|
"since": "0.1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "success",
|
||||||
|
"type": "boolean?",
|
||||||
|
"default": "None",
|
||||||
|
"since": "0.1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "commandLine",
|
||||||
|
"type": "String?",
|
||||||
|
"default": "None",
|
||||||
|
"since": "0.1.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -5,66 +5,68 @@ package sbt
|
||||||
package internal
|
package internal
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import org.json4s.JsonAST.{ JArray, JString }
|
import sjsonnew.{ JsonFormat, BasicJsonProtocol }
|
||||||
import org.json4s._
|
import sjsonnew.support.scalajson.unsafe.{ Converter, CompactPrinter }
|
||||||
import org.json4s.JsonDSL._
|
import scala.json.ast.unsafe.JValue
|
||||||
import org.json4s.native.JsonMethods._
|
import sjsonnew.support.scalajson.unsafe.Parser
|
||||||
import org.json4s.ParserUtil.ParseException
|
import java.nio.ByteBuffer
|
||||||
|
import scala.util.{ Success, Failure }
|
||||||
|
|
||||||
object Serialization {
|
object Serialization {
|
||||||
|
|
||||||
def serialize(event: Event): Array[Byte] = {
|
def serialize(event: Event): Array[Byte] =
|
||||||
compact(render(toJson(event))).getBytes("UTF-8")
|
{
|
||||||
}
|
import ServerCodec._
|
||||||
|
val msg = toMessage(event)
|
||||||
def toJson(event: Event): JObject = event match {
|
val json: JValue = Converter.toJson[EventMessage](msg).get
|
||||||
case LogEvent(level, message) =>
|
CompactPrinter(json).getBytes("UTF-8")
|
||||||
JObject(
|
}
|
||||||
"type" -> JString("log_event"),
|
def toMessage(event: Event): EventMessage =
|
||||||
"level" -> JString(level),
|
event match {
|
||||||
"message" -> JString(message)
|
case LogEvent(level, message) =>
|
||||||
)
|
EventMessage(`type` = "logEvent",
|
||||||
|
status = None, commandQueue = Vector(),
|
||||||
case StatusEvent(Ready) =>
|
level = Some(level), message = Some(message), success = None, commandLine = None)
|
||||||
JObject(
|
case StatusEvent(Ready) =>
|
||||||
"type" -> JString("status_event"),
|
EventMessage(`type` = "statusEvent",
|
||||||
"status" -> JString("ready"),
|
status = Some("ready"), commandQueue = Vector(),
|
||||||
"command_queue" -> JArray(List.empty)
|
level = None, message = None, success = None, commandLine = None)
|
||||||
)
|
case StatusEvent(Processing(command, commandQueue)) =>
|
||||||
|
EventMessage(`type` = "statusEvent",
|
||||||
case StatusEvent(Processing(command, commandQueue)) =>
|
status = Some("processing"), commandQueue = commandQueue.toVector,
|
||||||
JObject(
|
level = None, message = None, success = None, commandLine = None)
|
||||||
"type" -> JString("status_event"),
|
case ExecutionEvent(command, status) =>
|
||||||
"status" -> JString("processing"),
|
EventMessage(`type` = "executionEvent",
|
||||||
"command_queue" -> JArray(commandQueue.map(JString).toList)
|
status = None, commandQueue = Vector(),
|
||||||
)
|
level = None, message = None, success = Some(status), commandLine = Some(command))
|
||||||
|
}
|
||||||
case ExecutionEvent(command, status) =>
|
|
||||||
JObject(
|
|
||||||
"type" -> JString("execution_event"),
|
|
||||||
"command" -> JString(command),
|
|
||||||
"success" -> JBool(status)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A command or an invalid input description
|
* @return A command or an invalid input description
|
||||||
*/
|
*/
|
||||||
def deserialize(bytes: Seq[Byte]): Either[String, Command] =
|
def deserialize(bytes: Seq[Byte]): Either[String, Command] =
|
||||||
try {
|
{
|
||||||
val json = parse(new String(bytes.toArray, "UTF-8"))
|
val buffer = ByteBuffer.wrap(bytes.toArray)
|
||||||
implicit val formats = DefaultFormats
|
Parser.parseFromByteBuffer(buffer) match {
|
||||||
|
case Success(json) =>
|
||||||
(json \ "type").toOption match {
|
import ServerCodec._
|
||||||
case Some(JString("exec")) =>
|
Converter.fromJson[CommandMessage](json) match {
|
||||||
(json \ "command_line").toOption match {
|
case Success(command) =>
|
||||||
case Some(JString(cmd)) => Right(Execution(cmd))
|
command.`type` match {
|
||||||
case _ => Left("Missing or invalid command_line field")
|
case "exec" =>
|
||||||
|
command.commandLine match {
|
||||||
|
case Some(cmd) => Right(Execution(cmd))
|
||||||
|
case None => Left("Missing or invalid command_line field")
|
||||||
|
}
|
||||||
|
case cmd => Left(s"Unknown command type $cmd")
|
||||||
|
}
|
||||||
|
case Failure(e) => Left(e.getMessage)
|
||||||
}
|
}
|
||||||
case Some(cmd) => Left(s"Unknown command type $cmd")
|
case Failure(e) =>
|
||||||
case None => Left("Invalid command, missing type field")
|
Left(s"Parse error: ${e.getMessage}")
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
case e: ParseException => Left(s"Parse error: ${e.getMessage}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ServerCodec extends ServerCodec
|
||||||
|
trait ServerCodec extends codec.EventMessageFormats with codec.CommandMessageFormats with BasicJsonProtocol
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,7 @@ object Dependencies {
|
||||||
lazy val compilerClasspath = "org.scala-sbt" %% "zinc-classpath" % zincVersion
|
lazy val compilerClasspath = "org.scala-sbt" %% "zinc-classpath" % zincVersion
|
||||||
lazy val compilerApiInfo = "org.scala-sbt" %% "zinc-apiinfo" % zincVersion
|
lazy val compilerApiInfo = "org.scala-sbt" %% "zinc-apiinfo" % zincVersion
|
||||||
lazy val compilerIvyIntegration = "org.scala-sbt" %% "zinc-ivy-integration" % zincVersion
|
lazy val compilerIvyIntegration = "org.scala-sbt" %% "zinc-ivy-integration" % zincVersion
|
||||||
|
lazy val sjsonNewScalaJson = "com.eed3si9n" %% "sjson-new-scalajson" % "0.4.2"
|
||||||
lazy val json4s = "org.json4s" %% "json4s" % "3.2.10"
|
|
||||||
lazy val json4sNative = "org.json4s" %% "json4s-native" % "3.2.10"
|
|
||||||
|
|
||||||
lazy val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.11.4"
|
lazy val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.11.4"
|
||||||
lazy val specs2 = "org.specs2" %% "specs2" % "2.3.11"
|
lazy val specs2 = "org.specs2" %% "specs2" % "2.3.11"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
addSbtPlugin("org.scala-sbt" % "sbt-datatype" % "0.2.6")
|
||||||
Loading…
Reference in New Issue