diff options
author | Jakob Odersky <jakob@odersky.com> | 2017-04-01 13:21:15 -0700 |
---|---|---|
committer | Jakob Odersky <jakob@odersky.com> | 2017-04-01 13:21:15 -0700 |
commit | 26aa8adc30a84d983d020e34b488ac22a31cb544 (patch) | |
tree | 5e2cee54da5f64011f56a85c4b09bd1add4eacc7 /crashboxd/src/main/scala/io/crashbox/ci/yaml | |
parent | 8a4ebe76200a2e570bd959d8780c3c0a0bf71d5c (diff) | |
download | crashbox-ci-26aa8adc30a84d983d020e34b488ac22a31cb544.tar.gz crashbox-ci-26aa8adc30a84d983d020e34b488ac22a31cb544.tar.bz2 crashbox-ci-26aa8adc30a84d983d020e34b488ac22a31cb544.zip |
Add yaml parser and docker executor
Diffstat (limited to 'crashboxd/src/main/scala/io/crashbox/ci/yaml')
7 files changed, 157 insertions, 0 deletions
diff --git a/crashboxd/src/main/scala/io/crashbox/ci/yaml/CompositeReaders.scala b/crashboxd/src/main/scala/io/crashbox/ci/yaml/CompositeReaders.scala new file mode 100644 index 0000000..4df72e1 --- /dev/null +++ b/crashboxd/src/main/scala/io/crashbox/ci/yaml/CompositeReaders.scala @@ -0,0 +1,29 @@ +package io.crashbox.ci +package yaml + +trait CompositeReaders { + + implicit def mapReader[V: YamlReader] = new YamlReader[Map[String, V]] { + override def read(yml: YamlValue) = yml match { + case YamlMap(m) => + m.map { + case (key, value) => + key -> value.convertTo[V] + } + case YamlString.Empty => Map.empty[String, V] + case _ => formatError(yml, "mapping") + } + } + + implicit def seqReader[A: YamlReader] = new YamlReader[Seq[A]] { + override def read(yml: YamlValue) = yml match { + case YamlSeq(elements) => + elements.map { v => + v.convertTo[A] + } + case YamlString.Empty => Seq.empty[A] + case _ => formatError(yml, "sequence") + } + } + +} diff --git a/crashboxd/src/main/scala/io/crashbox/ci/yaml/DefaultReaders.scala b/crashboxd/src/main/scala/io/crashbox/ci/yaml/DefaultReaders.scala new file mode 100644 index 0000000..9d40bad --- /dev/null +++ b/crashboxd/src/main/scala/io/crashbox/ci/yaml/DefaultReaders.scala @@ -0,0 +1,6 @@ +package io.crashbox.ci +package yaml + +trait DefaultReaders extends SimpleReaders with CompositeReaders + +object DefaultReaders extends DefaultReaders diff --git a/crashboxd/src/main/scala/io/crashbox/ci/yaml/SimpleReaders.scala b/crashboxd/src/main/scala/io/crashbox/ci/yaml/SimpleReaders.scala new file mode 100644 index 0000000..df30a33 --- /dev/null +++ b/crashboxd/src/main/scala/io/crashbox/ci/yaml/SimpleReaders.scala @@ -0,0 +1,46 @@ +package io.crashbox.ci +package yaml + +import scala.util.Try + +trait SimpleReaders { + + class YamlStringReader[A](expected: String)(extract: String => Option[A]) + extends YamlReader[A] { + def read(yml: YamlValue) = yml match { + case YamlString(value) => + extract(value) match { + case Some(a) => a + case None => + throw new YamlFormatException( + s"""expected $expected, but found string type "$value"""") + } + case _ => formatError(yml, expected) + } + } + + implicit object valueReader extends YamlReader[YamlValue] { + def read(yaml: YamlValue) = yaml + } + + implicit object stringReader + extends YamlStringReader[String]("string")(s => Some(s)) + + implicit object byteReader + extends YamlStringReader[Byte]("byte")(s => Try { s.toByte }.toOption) + implicit object shortReader + extends YamlStringReader[Short]("short")(s => Try { s.toShort }.toOption) + implicit object intReader + extends YamlStringReader[Int]("integer")(s => Try { s.toInt }.toOption) + implicit object longReader + extends YamlStringReader[Long]("long")(s => Try { s.toLong }.toOption) + implicit object floatReader + extends YamlStringReader[Float]("float")(s => Try { s.toFloat }.toOption) + implicit object doubleReader + extends YamlStringReader[Double]("double")(s => + Try { s.toDouble }.toOption) + implicit object booleanReader + extends YamlStringReader[Boolean]("boolean")(s => + Try { s.toBoolean }.toOption) + +} diff --git a/crashboxd/src/main/scala/io/crashbox/ci/yaml/Yaml.scala b/crashboxd/src/main/scala/io/crashbox/ci/yaml/Yaml.scala new file mode 100644 index 0000000..0370c76 --- /dev/null +++ b/crashboxd/src/main/scala/io/crashbox/ci/yaml/Yaml.scala @@ -0,0 +1,36 @@ +package io.crashbox.ci +package yaml + +import java.util.{List => JList, Map => JMap} + +import scala.collection.JavaConverters._ + +import org.yaml.snakeyaml.{DumperOptions, Yaml => SYaml} +import org.yaml.snakeyaml.constructor.Constructor +import org.yaml.snakeyaml.representer.Representer +import org.yaml.snakeyaml.resolver.Resolver + +object Yaml { + + private def toYaml(yml: Any): YamlValue = yml match { + case m: JMap[_, _] => + YamlMap(m.asScala.toMap.map { case (k, v) => k.toString -> toYaml(v) }) + case l: JList[_] => YamlSeq(l.asScala.toList.map(toYaml(_))) + case s: String => YamlString(s) + case other => throw new YamlFormatException("Unknown YAML type: " + other) + } + + /** Strict parsing */ + def parse(data: String): YamlValue = { + val resolver = new Resolver { + override def addImplicitResolvers: Unit = {} + } + val yml = new SYaml(new Constructor(), + new Representer(), + new DumperOptions(), + resolver) + val node = yml.load(data) + toYaml(node) + } + +} diff --git a/crashboxd/src/main/scala/io/crashbox/ci/yaml/YamlFormatException.scala b/crashboxd/src/main/scala/io/crashbox/ci/yaml/YamlFormatException.scala new file mode 100644 index 0000000..1700900 --- /dev/null +++ b/crashboxd/src/main/scala/io/crashbox/ci/yaml/YamlFormatException.scala @@ -0,0 +1,4 @@ +package io.crashbox.ci +package yaml + +class YamlFormatException(message: String) extends RuntimeException(message) diff --git a/crashboxd/src/main/scala/io/crashbox/ci/yaml/YamlReader.scala b/crashboxd/src/main/scala/io/crashbox/ci/yaml/YamlReader.scala new file mode 100644 index 0000000..f486676 --- /dev/null +++ b/crashboxd/src/main/scala/io/crashbox/ci/yaml/YamlReader.scala @@ -0,0 +1,24 @@ +package io.crashbox.ci +package yaml + +trait YamlReader[A] { + + def read(yml: YamlValue): A + + protected def formatError(found: YamlValue, required: String) = { + val foundType = found match { + case _: YamlString => "string" + case _: YamlSeq => "sequence" + case _: YamlMap => "mapping" + } + + throw new YamlFormatException( + s"$found is of type $foundType, required: $required" + ) + } + + protected def readError(node: YamlValue, msg: String) = { + throw new YamlFormatException(node.toString + ": " + msg) + } + +} diff --git a/crashboxd/src/main/scala/io/crashbox/ci/yaml/values.scala b/crashboxd/src/main/scala/io/crashbox/ci/yaml/values.scala new file mode 100644 index 0000000..dd4fb0f --- /dev/null +++ b/crashboxd/src/main/scala/io/crashbox/ci/yaml/values.scala @@ -0,0 +1,12 @@ +package io.crashbox.ci +package yaml + +sealed trait YamlValue { + def convertTo[A: YamlReader]: A = implicitly[YamlReader[A]].read(this) +} +case class YamlString(value: String) extends YamlValue +object YamlString { + val Empty = YamlString("") +} +case class YamlMap(fields: Map[String, YamlValue]) extends YamlValue +case class YamlSeq(elements: Seq[YamlValue]) extends YamlValue |