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
|
||||
lazy val commandProj = (project in file("main-command")).
|
||||
enablePlugins(DatatypePlugin, JsonCodecPlugin).
|
||||
settings(
|
||||
testedBaseSettings,
|
||||
name := "Command",
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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 server
|
||||
|
||||
import org.json4s.JsonAST.{ JArray, JString }
|
||||
import org.json4s._
|
||||
import org.json4s.JsonDSL._
|
||||
import org.json4s.native.JsonMethods._
|
||||
import org.json4s.ParserUtil.ParseException
|
||||
import sjsonnew.{ JsonFormat, BasicJsonProtocol }
|
||||
import sjsonnew.support.scalajson.unsafe.{ Converter, CompactPrinter }
|
||||
import scala.json.ast.unsafe.JValue
|
||||
import sjsonnew.support.scalajson.unsafe.Parser
|
||||
import java.nio.ByteBuffer
|
||||
import scala.util.{ Success, Failure }
|
||||
|
||||
object Serialization {
|
||||
|
||||
def serialize(event: Event): Array[Byte] = {
|
||||
compact(render(toJson(event))).getBytes("UTF-8")
|
||||
}
|
||||
|
||||
def toJson(event: Event): JObject = event match {
|
||||
case LogEvent(level, message) =>
|
||||
JObject(
|
||||
"type" -> JString("log_event"),
|
||||
"level" -> JString(level),
|
||||
"message" -> JString(message)
|
||||
)
|
||||
|
||||
case StatusEvent(Ready) =>
|
||||
JObject(
|
||||
"type" -> JString("status_event"),
|
||||
"status" -> JString("ready"),
|
||||
"command_queue" -> JArray(List.empty)
|
||||
)
|
||||
|
||||
case StatusEvent(Processing(command, commandQueue)) =>
|
||||
JObject(
|
||||
"type" -> JString("status_event"),
|
||||
"status" -> JString("processing"),
|
||||
"command_queue" -> JArray(commandQueue.map(JString).toList)
|
||||
)
|
||||
|
||||
case ExecutionEvent(command, status) =>
|
||||
JObject(
|
||||
"type" -> JString("execution_event"),
|
||||
"command" -> JString(command),
|
||||
"success" -> JBool(status)
|
||||
)
|
||||
}
|
||||
def serialize(event: Event): Array[Byte] =
|
||||
{
|
||||
import ServerCodec._
|
||||
val msg = toMessage(event)
|
||||
val json: JValue = Converter.toJson[EventMessage](msg).get
|
||||
CompactPrinter(json).getBytes("UTF-8")
|
||||
}
|
||||
def toMessage(event: Event): EventMessage =
|
||||
event match {
|
||||
case LogEvent(level, message) =>
|
||||
EventMessage(`type` = "logEvent",
|
||||
status = None, commandQueue = Vector(),
|
||||
level = Some(level), message = Some(message), success = None, commandLine = None)
|
||||
case StatusEvent(Ready) =>
|
||||
EventMessage(`type` = "statusEvent",
|
||||
status = Some("ready"), commandQueue = Vector(),
|
||||
level = None, message = None, success = None, commandLine = None)
|
||||
case StatusEvent(Processing(command, commandQueue)) =>
|
||||
EventMessage(`type` = "statusEvent",
|
||||
status = Some("processing"), commandQueue = commandQueue.toVector,
|
||||
level = None, message = None, success = None, commandLine = None)
|
||||
case ExecutionEvent(command, status) =>
|
||||
EventMessage(`type` = "executionEvent",
|
||||
status = None, commandQueue = Vector(),
|
||||
level = None, message = None, success = Some(status), commandLine = Some(command))
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A command or an invalid input description
|
||||
*/
|
||||
def deserialize(bytes: Seq[Byte]): Either[String, Command] =
|
||||
try {
|
||||
val json = parse(new String(bytes.toArray, "UTF-8"))
|
||||
implicit val formats = DefaultFormats
|
||||
|
||||
(json \ "type").toOption match {
|
||||
case Some(JString("exec")) =>
|
||||
(json \ "command_line").toOption match {
|
||||
case Some(JString(cmd)) => Right(Execution(cmd))
|
||||
case _ => Left("Missing or invalid command_line field")
|
||||
{
|
||||
val buffer = ByteBuffer.wrap(bytes.toArray)
|
||||
Parser.parseFromByteBuffer(buffer) match {
|
||||
case Success(json) =>
|
||||
import ServerCodec._
|
||||
Converter.fromJson[CommandMessage](json) match {
|
||||
case Success(command) =>
|
||||
command.`type` match {
|
||||
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 None => Left("Invalid command, missing type field")
|
||||
case Failure(e) =>
|
||||
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 compilerApiInfo = "org.scala-sbt" %% "zinc-apiinfo" % zincVersion
|
||||
lazy val compilerIvyIntegration = "org.scala-sbt" %% "zinc-ivy-integration" % zincVersion
|
||||
|
||||
lazy val json4s = "org.json4s" %% "json4s" % "3.2.10"
|
||||
lazy val json4sNative = "org.json4s" %% "json4s-native" % "3.2.10"
|
||||
lazy val sjsonNewScalaJson = "com.eed3si9n" %% "sjson-new-scalajson" % "0.4.2"
|
||||
|
||||
lazy val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.11.4"
|
||||
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