Browse code

Engine: Output.AddEnv decodes structured data from the standard output of a job

Solomon Hykes authored on 2013/12/08 15:16:10
Showing 2 changed files
... ...
@@ -164,3 +164,30 @@ func Tail(src io.Reader, n int, dst *[]string) {
164 164
 		*dst = append(*dst, v.(string))
165 165
 	})
166 166
 }
167
+
168
+// AddEnv starts a new goroutine which will decode all subsequent data
169
+// as a stream of json-encoded objects, and point `dst` to the last
170
+// decoded object.
171
+// The result `env` can be queried using the type-neutral Env interface. 
172
+// It is not safe to query `env` until the Output is closed.
173
+func (o *Output) AddEnv() (dst *Env, err error) {
174
+	src, err := o.AddPipe()
175
+	if err != nil {
176
+		return nil, err
177
+	}
178
+	dst = &Env{}
179
+	o.tasks.Add(1)
180
+	go func() {
181
+		defer o.tasks.Done()
182
+		decoder := NewDecoder(src)
183
+		for {
184
+			env, err := decoder.Decode()
185
+			if err != nil {
186
+				return
187
+			}
188
+			*dst= *env
189
+		}
190
+	}()
191
+	return dst, nil
192
+}
193
+
... ...
@@ -72,6 +72,26 @@ func (w *sentinelWriteCloser) Close() error {
72 72
 	return nil
73 73
 }
74 74
 
75
+func TestOutputAddEnv(t *testing.T) {
76
+	input := "{\"foo\": \"bar\", \"answer_to_life_the_universe_and_everything\": 42}"
77
+	o := NewOutput()
78
+	result, err := o.AddEnv()
79
+	if err != nil {
80
+		t.Fatal(err)
81
+	}
82
+	o.Write([]byte(input))
83
+	o.Close()
84
+	if v := result.Get("foo"); v != "bar" {
85
+		t.Errorf("Expected %v, got %v", "bar", v)
86
+	}
87
+	if v := result.GetInt("answer_to_life_the_universe_and_everything"); v != 42 {
88
+		t.Errorf("Expected %v, got %v", 42, v)
89
+	}
90
+	if v := result.Get("this-value-doesnt-exist"); v != "" {
91
+		t.Errorf("Expected %v, got %v", "", v)
92
+	}
93
+}
94
+
75 95
 func TestOutputAddClose(t *testing.T) {
76 96
 	o := NewOutput()
77 97
 	var s sentinelWriteCloser