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.net.{ Socket, SocketTimeoutException }
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import sbt.protocol.{ Serialization, CommandMessage, ExecCommand, EventMessage }
|
import scala.util.{ Left, Right }
|
||||||
import sjsonnew.JsonFormat
|
import sbt.protocol._
|
||||||
|
import sjsonnew._, LList.:*:
|
||||||
|
|
||||||
final class NetworkChannel(val name: String, connection: Socket, state: State) extends CommandChannel {
|
final class NetworkChannel(val name: String, connection: Socket, state: State) extends CommandChannel {
|
||||||
private val running = new AtomicBoolean(true)
|
private val running = new AtomicBoolean(true)
|
||||||
|
|
@ -72,14 +73,135 @@ final class NetworkChannel(val name: String, connection: Socket, state: State) e
|
||||||
|
|
||||||
def onCommand(command: CommandMessage): Unit = command match {
|
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) =
|
private def onExecCommand(cmd: ExecCommand) =
|
||||||
append(Exec(cmd.commandLine, cmd.execId orElse Some(Exec.newExecId), Some(CommandSource(name))))
|
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 = {
|
def shutdown(): Unit = {
|
||||||
println("Shutting down client connection")
|
println("Shutting down client connection")
|
||||||
running.set(false)
|
running.set(false)
|
||||||
out.close()
|
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
|
// DO NOT EDIT MANUALLY
|
||||||
package sbt.protocol.codec
|
package sbt.protocol.codec
|
||||||
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
||||||
trait CommandMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ExecCommandFormats =>
|
trait CommandMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ExecCommandFormats with sbt.protocol.codec.SettingQueryFormats =>
|
||||||
implicit lazy val CommandMessageFormat: JsonFormat[sbt.protocol.CommandMessage] = flatUnionFormat1[sbt.protocol.CommandMessage, sbt.protocol.ExecCommand]("type")
|
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
|
// DO NOT EDIT MANUALLY
|
||||||
package sbt.protocol.codec
|
package sbt.protocol.codec
|
||||||
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
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 =>
|
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] = flatUnionFormat3[sbt.protocol.EventMessage, sbt.protocol.ChannelAcceptedEvent, sbt.protocol.LogEvent, sbt.protocol.ExecStatusEvent]("type")
|
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
|
package sbt.protocol.codec
|
||||||
trait JsonProtocol extends sjsonnew.BasicJsonProtocol
|
trait JsonProtocol extends sjsonnew.BasicJsonProtocol
|
||||||
with sbt.protocol.codec.ExecCommandFormats
|
with sbt.protocol.codec.ExecCommandFormats
|
||||||
|
with sbt.protocol.codec.SettingQueryFormats
|
||||||
with sbt.protocol.codec.CommandMessageFormats
|
with sbt.protocol.codec.CommandMessageFormats
|
||||||
with sbt.protocol.codec.ChannelAcceptedEventFormats
|
with sbt.protocol.codec.ChannelAcceptedEventFormats
|
||||||
with sbt.protocol.codec.LogEventFormats
|
with sbt.protocol.codec.LogEventFormats
|
||||||
with sbt.protocol.codec.ExecStatusEventFormats
|
with sbt.protocol.codec.ExecStatusEventFormats
|
||||||
|
with sbt.protocol.codec.SettingQueryResponseFormats
|
||||||
with sbt.protocol.codec.EventMessageFormats
|
with sbt.protocol.codec.EventMessageFormats
|
||||||
with sbt.protocol.codec.ExecutionEventFormats
|
with sbt.protocol.codec.ExecutionEventFormats
|
||||||
object JsonProtocol extends JsonProtocol
|
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")
|
execId: String @since("0.0.1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SettingQuery implements CommandMessage {
|
||||||
|
setting: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
## Message for events.
|
## Message for events.
|
||||||
interface EventMessage {
|
interface EventMessage {
|
||||||
}
|
}
|
||||||
|
|
@ -35,6 +40,10 @@ type ExecStatusEvent implements EventMessage {
|
||||||
commandQueue: [String]
|
commandQueue: [String]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SettingQueryResponse implements EventMessage {
|
||||||
|
values: [String]
|
||||||
|
}
|
||||||
|
|
||||||
# enum Status {
|
# enum Status {
|
||||||
# Ready
|
# Ready
|
||||||
# Processing
|
# Processing
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue