mirror of https://github.com/sbt/sbt.git
Add and handle GetSetting
This commit is contained in:
parent
164b0fe830
commit
d9d741851a
|
|
@ -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) }
|
||||
// )
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue