Add and handle GetSetting

This commit is contained in:
Dale Wijnand 2017-01-20 16:35:06 +00:00
parent 164b0fe830
commit d9d741851a
No known key found for this signature in database
GPG Key ID: 4F256E3D151DF5EF
9 changed files with 258 additions and 7 deletions

View File

@ -7,8 +7,9 @@ package server
import java.net.{ Socket, SocketTimeoutException }
import java.util.concurrent.atomic.AtomicBoolean
import sbt.protocol.{ Serialization, CommandMessage, ExecCommand, EventMessage }
import sjsonnew.JsonFormat
import scala.util.{ Left, Right }
import sbt.protocol._
import sjsonnew._, LList.:*:
final class NetworkChannel(val name: String, connection: Socket, state: State) extends CommandChannel {
private val running = new AtomicBoolean(true)
@ -71,15 +72,136 @@ final class NetworkChannel(val name: String, connection: Socket, state: State) e
}
def onCommand(command: CommandMessage): Unit = command match {
case x: ExecCommand => onExecCommand(x)
case x: ExecCommand => onExecCommand(x)
case x: SettingQuery => onSettingQuery(x)
}
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 extracted = Project extract state
val keys = Parser.parse(req.setting, Act aggregatedKeyParser extracted)
def getSettingValue[A](key: Def.ScopedKey[A]) =
extracted.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 zeroValues: Either[Vector[String], Vector[Any]] = Right(Vector.empty)
def anyLeftsOrAllRights[A, B](acc: Either[Vector[A], Vector[B]], elem: Either[A, B]): Either[Vector[A], Vector[B]] =
(acc, elem) match {
case (Right(a), Right(x)) => Right(a :+ x)
case (Right(_), Left(x)) => Left(Vector(x))
case (Left(a), Right(_)) => Left(a)
case (Left(a), Left(x)) => Left(a :+ x)
}
val values = keys match {
case Left(msg) => Left(s"Invalid programmatic input:" +: (msg.lines.toVector map (" " + _)))
case Right(keys) => keys.map(getSettingValue(_)).foldLeft(zeroValues)(anyLeftsOrAllRights)
}
val jsonValues = values match {
case Left(errors) => errors
case Right(values) => values map (_.toString)
}
StandardMain.exchange publishEventMessage SettingQueryResponse(jsonValues)
}
def shutdown(): Unit = {
println("Shutting down client connection")
running.set(false)
out.close()
}
}
trait SettingQueryInstances {
import BasicJsonProtocol._
type SettingQueryRepr = String :*: LNil
implicit def settingQueryIso: IsoLList.Aux[SettingQuery, SettingQueryRepr] = LList.iso(
(x => "settingKey" -> x.setting :*: LNil),
(x => SettingQuery(x.head))
)
import sbt.internal.util._
type AttrKeyRepr[A] = String :*: Manifest[A] :*: Option[String] :*: Vector[AttributeKey[_]] :*: Boolean :*: Int :*: LNil
// FIXME: Can't go this IsoLList way because AttributeKey depends on AttributeKey (extend)
implicit def attrKeyIso[A]: IsoLList.Aux[AttributeKey[A], AttrKeyRepr[A]] = ???
// LList.iso[AttributeKey[A], AttrKeyRepr[A]](attrKeyToRepr, attrKeyFromRepr)
// def attrKeyToRepr[A](x: AttributeKey[A]): AttrKeyRepr[A] = (
// /* */ "label" -> x.label /* */ :*:
// /**/ "manifest" -> x.manifest /* */ :*:
// /* */ "desc" -> x.description /* */ :*:
// /* */ "extend" -> x.extend.toVector /**/ :*:
// /* */ "isLocal" -> x.isLocal /* */ :*:
// /* */ "rank" -> x.rank /* */ :*:
// LNil
// )
def attrKeyFromRepr[A](x: AttrKeyRepr[A]): AttributeKey[A] = {
val LCons("label", label,
LCons("manifest", manifest,
LCons("desc", desc,
LCons("extend", extend,
LCons("isLabel", isLocal,
LCons("rank", rank, LNil)
))))) = x
if (isLocal) AttributeKey.local[A](manifest)
else desc match {
case Some(desc) => AttributeKey(label, desc, extend, rank)(manifest)
case None => extend match {
case Seq() => AttributeKey(label, rank)(manifest)
case _ =>
// With the given API it's not possible to create an AttributeKey
// which extends other attribute keys without having a description
// But that's not enforced in the data types. So default description to ""
AttributeKey(label, "", extend, rank)(manifest)
}
}
}
// TODO: or use AttributeKey label? (String)
// implicit def attrMapFormat: JsonFormat[AttributeMap] = project[AttributeMap, Map[AttributeKey[_], Any]](
// attrMap => attrMap.entries.iterator.map(x => x.key -> x.value).toMap,
// map => AttributeMap(map.iterator.map { case (k: AttributeKey[kt], v) => AttributeEntry(k, v.asInstanceOf[kt]) }.toSeq)
// )
implicit def scopeAxisIso[A](implicit z: JsonFormat[A]): JsonFormat[ScopeAxis[A]] =
new JsonFormat[ScopeAxis[A]] {
def write[J](obj: ScopeAxis[A], builder: Builder[J]): Unit = obj match {
case This => builder writeString "This"
case Global => builder writeString "Global"
case Select(s) => z.write(s, builder)
}
def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): ScopeAxis[A] = jsOpt match {
case None => deserializationError("Expected some JSON but found None")
case Some("This") => This
case Some("Global") => Global
case Some(_) => Select(z.read(jsOpt, unbuilder))
}
}
type ScopeRepr = ScopeAxis[Reference] :*: ScopeAxis[ConfigKey] :*: ScopeAxis[AttributeKey[_]] :*: ScopeAxis[AttributeMap] :*: LNil
// implicit def scopeIso: IsoLList.Aux[Scope, ScopeRepr] = LList.iso[Scope, ScopeRepr](
// { x: Scope => "project" -> x.project :*: "config" -> x.config :*: "task" -> x.task :*: "extra" -> x.extra :*: LNil },
// { x: ScopeRepr => Scope(x.head, x.tail.head, x.tail.tail.head, x.tail.tail.tail.head) }
// )
type SettingKeyRepr[A] = Scope :*: AttributeKey[A] :*: LNil
// implicit def settingKeyIso[A]: IsoLList.Aux[SettingKey[A], SettingKeyRepr[A]] = LList.iso(
// { x: SettingKey[A] => "scope" -> x.scope :*: "attrKey" -> x.key :*: LNil },
// { x: SettingKeyRepr[A] => Scoped.scopedSetting(x.head, x.tail.head) }
// )
}

View File

@ -0,0 +1,32 @@
/**
* This code is generated using sbt-datatype.
*/
// DO NOT EDIT MANUALLY
package sbt.protocol
final class SettingQuery private (
val setting: String) extends sbt.protocol.CommandMessage() with Serializable {
override def equals(o: Any): Boolean = o match {
case x: SettingQuery => (this.setting == x.setting)
case _ => false
}
override def hashCode: Int = {
37 * (17 + setting.##)
}
override def toString: String = {
"SettingQuery(" + setting + ")"
}
protected[this] def copy(setting: String = setting): SettingQuery = {
new SettingQuery(setting)
}
def withSetting(setting: String): SettingQuery = {
copy(setting = setting)
}
}
object SettingQuery {
def apply(setting: String): SettingQuery = new SettingQuery(setting)
}

View File

@ -0,0 +1,32 @@
/**
* This code is generated using sbt-datatype.
*/
// DO NOT EDIT MANUALLY
package sbt.protocol
final class SettingQueryResponse private (
val values: Vector[String]) extends sbt.protocol.EventMessage() with Serializable {
override def equals(o: Any): Boolean = o match {
case x: SettingQueryResponse => (this.values == x.values)
case _ => false
}
override def hashCode: Int = {
37 * (17 + values.##)
}
override def toString: String = {
"SettingQueryResponse(" + values + ")"
}
protected[this] def copy(values: Vector[String] = values): SettingQueryResponse = {
new SettingQueryResponse(values)
}
def withValues(values: Vector[String]): SettingQueryResponse = {
copy(values = values)
}
}
object SettingQueryResponse {
def apply(values: Vector[String]): SettingQueryResponse = new SettingQueryResponse(values)
}

View File

@ -5,6 +5,6 @@
// DO NOT EDIT MANUALLY
package sbt.protocol.codec
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
trait CommandMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ExecCommandFormats =>
implicit lazy val CommandMessageFormat: JsonFormat[sbt.protocol.CommandMessage] = flatUnionFormat1[sbt.protocol.CommandMessage, sbt.protocol.ExecCommand]("type")
trait CommandMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ExecCommandFormats with sbt.protocol.codec.SettingQueryFormats =>
implicit lazy val CommandMessageFormat: JsonFormat[sbt.protocol.CommandMessage] = flatUnionFormat2[sbt.protocol.CommandMessage, sbt.protocol.ExecCommand, sbt.protocol.SettingQuery]("type")
}

View File

@ -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 =>
implicit lazy val EventMessageFormat: JsonFormat[sbt.protocol.EventMessage] = flatUnionFormat3[sbt.protocol.EventMessage, sbt.protocol.ChannelAcceptedEvent, sbt.protocol.LogEvent, sbt.protocol.ExecStatusEvent]("type")
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")
}

View File

@ -6,10 +6,12 @@
package sbt.protocol.codec
trait JsonProtocol extends sjsonnew.BasicJsonProtocol
with sbt.protocol.codec.ExecCommandFormats
with sbt.protocol.codec.SettingQueryFormats
with sbt.protocol.codec.CommandMessageFormats
with sbt.protocol.codec.ChannelAcceptedEventFormats
with sbt.protocol.codec.LogEventFormats
with sbt.protocol.codec.ExecStatusEventFormats
with sbt.protocol.codec.SettingQueryResponseFormats
with sbt.protocol.codec.EventMessageFormats
with sbt.protocol.codec.ExecutionEventFormats
object JsonProtocol extends JsonProtocol

View File

@ -0,0 +1,27 @@
/**
* This code is generated using sbt-datatype.
*/
// DO NOT EDIT MANUALLY
package sbt.protocol.codec
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
trait SettingQueryFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val SettingQueryFormat: JsonFormat[sbt.protocol.SettingQuery] = new JsonFormat[sbt.protocol.SettingQuery] {
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.SettingQuery = {
jsOpt match {
case Some(js) =>
unbuilder.beginObject(js)
val setting = unbuilder.readField[String]("setting")
unbuilder.endObject()
sbt.protocol.SettingQuery(setting)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.protocol.SettingQuery, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("setting", obj.setting)
builder.endObject()
}
}
}

View File

@ -0,0 +1,27 @@
/**
* This code is generated using sbt-datatype.
*/
// 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 values = unbuilder.readField[Vector[String]]("values")
unbuilder.endObject()
sbt.protocol.SettingQueryResponse(values)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.protocol.SettingQueryResponse, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("values", obj.values)
builder.endObject()
}
}
}

View File

@ -13,6 +13,11 @@ type ExecCommand implements CommandMessage {
execId: String @since("0.0.1")
}
type SettingQuery implements CommandMessage {
setting: String!
}
## Message for events.
interface EventMessage {
}
@ -35,6 +40,10 @@ type ExecStatusEvent implements EventMessage {
commandQueue: [String]
}
type SettingQueryResponse implements EventMessage {
values: [String]
}
# enum Status {
# Ready
# Processing