harness-drone/engine/runner/parse/parse.go
2016-04-16 00:51:05 -07:00

221 lines
4.3 KiB
Go

package parse
import "encoding/json"
// Tree is the intermediate representation of a pipeline.
type Tree struct {
*ListNode // top-level Tree node
}
// New allocates a new Tree.
func NewTree() *Tree {
return &Tree{
NewListNode(),
}
}
// Parse parses a JSON encoded Tree.
func Parse(data []byte) (*Tree, error) {
tree := &Tree{}
err := tree.UnmarshalJSON(data)
return tree, err
}
// MarshalJSON implements the Marshaler interface and returns
// a JSON encoded representation of the Tree.
func (t *Tree) MarshalJSON() ([]byte, error) {
return json.Marshal(t.ListNode)
}
// UnmarshalJSON implements the Unmarshaler interface and returns
// a Tree from a JSON representation.
func (t *Tree) UnmarshalJSON(data []byte) error {
block, err := decodeList(data)
if err != nil {
return nil
}
t.ListNode = block.(*ListNode)
return nil
}
//
// below are custom decoding functions. We cannot use the default json
// decoder because the tree structure uses interfaces and the json decoder
// has difficulty ascertaining the interface type when decoding.
//
func decodeNode(data []byte) (Node, error) {
node := &nodeType{}
err := json.Unmarshal(data, node)
if err != nil {
return nil, err
}
switch node.Type {
case NodeList:
return decodeList(data)
case NodeDefer:
return decodeDefer(data)
case NodeError:
return decodeError(data)
case NodeRecover:
return decodeRecover(data)
case NodeParallel:
return decodeParallel(data)
case NodeRun:
return decodeRun(data)
}
return nil, nil
}
func decodeNodes(data []json.RawMessage) ([]Node, error) {
var nodes []Node
for _, d := range data {
node, err := decodeNode(d)
if err != nil {
return nil, err
}
nodes = append(nodes, node)
}
return nodes, nil
}
func decodeList(data []byte) (Node, error) {
v := &nodeList{}
err := json.Unmarshal(data, v)
if err != nil {
return nil, err
}
b, err := decodeNodes(v.Body)
if err != nil {
return nil, err
}
n := NewListNode()
n.Body = b
return n, nil
}
func decodeDefer(data []byte) (Node, error) {
v := &nodeDefer{}
err := json.Unmarshal(data, v)
if err != nil {
return nil, err
}
b, err := decodeNode(v.Body)
if err != nil {
return nil, err
}
d, err := decodeNode(v.Defer)
if err != nil {
return nil, err
}
n := NewDeferNode()
n.Body = b
n.Defer = d
return n, nil
}
func decodeError(data []byte) (Node, error) {
v := &nodeError{}
err := json.Unmarshal(data, v)
if err != nil {
return nil, err
}
b, err := decodeNode(v.Body)
if err != nil {
return nil, err
}
d, err := decodeNode(v.Defer)
if err != nil {
return nil, err
}
n := NewErrorNode()
n.Body = b
n.Defer = d
return n, nil
}
func decodeRecover(data []byte) (Node, error) {
v := &nodeRecover{}
err := json.Unmarshal(data, v)
if err != nil {
return nil, err
}
b, err := decodeNode(v.Body)
if err != nil {
return nil, err
}
n := NewRecoverNode()
n.Body = b
return n, nil
}
func decodeParallel(data []byte) (Node, error) {
v := &nodeParallel{}
err := json.Unmarshal(data, v)
if err != nil {
return nil, err
}
b, err := decodeNodes(v.Body)
if err != nil {
return nil, err
}
n := NewParallelNode()
n.Body = b
n.Limit = v.Limit
return n, nil
}
func decodeRun(data []byte) (Node, error) {
v := &nodeRun{}
err := json.Unmarshal(data, v)
if err != nil {
return nil, err
}
return &RunNode{NodeRun, v.Name, v.Detach, v.Silent}, nil
}
//
// below are intermediate representations of the node structures
// since we cannot simply encode / decode using the built-in json
// encoding and decoder.
//
type nodeType struct {
Type NodeType `json:"type"`
}
type nodeDefer struct {
Type NodeType `json:"type"`
Body json.RawMessage `json:"body"`
Defer json.RawMessage `json:"defer"`
}
type nodeError struct {
Type NodeType `json:"type"`
Body json.RawMessage `json:"body"`
Defer json.RawMessage `json:"defer"`
}
type nodeList struct {
Type NodeType `json:"type"`
Body []json.RawMessage `json:"body"`
}
type nodeRecover struct {
Type NodeType `json:"type"`
Body json.RawMessage `json:"body"`
}
type nodeParallel struct {
Type NodeType `json:"type"`
Body []json.RawMessage `json:"body"`
Limit int `json:"limit"`
}
type nodeRun struct {
Type NodeType `json:"type"`
Name string `json:"name"`
Detach bool `json:"detach,omitempty"`
Silent bool `json:"silent,omitempty"`
}