Browse code

Engine.ParseJob: create a new job from a shell-like text command.

Docker-DCO-1.1-Signed-off-by: Solomon Hykes <solomon@docker.com> (github: shykes)

Solomon Hykes authored on 2014/02/16 08:05:28
Showing 3 changed files
... ...
@@ -1,6 +1,7 @@
1 1
 package engine
2 2
 
3 3
 import (
4
+	"bufio"
4 5
 	"fmt"
5 6
 	"github.com/dotcloud/docker/utils"
6 7
 	"io"
... ...
@@ -136,6 +137,48 @@ func (eng *Engine) Job(name string, args ...string) *Job {
136 136
 	return job
137 137
 }
138 138
 
139
+// ParseJob creates a new job from a text description using a shell-like syntax.
140
+//
141
+// The following syntax is used to parse `input`:
142
+//
143
+// * Words are separated using standard whitespaces as separators.
144
+// * Quotes and backslashes are not interpreted.
145
+// * Words of the form 'KEY=[VALUE]' are added to the job environment.
146
+// * All other words are added to the job arguments.
147
+//
148
+// For example:
149
+//
150
+// job, _ := eng.ParseJob("VERBOSE=1 echo hello TEST=true world")
151
+//
152
+// The resulting job will have:
153
+//	job.Args={"echo", "hello", "world"}
154
+//	job.Env={"VERBOSE":"1", "TEST":"true"}
155
+//
156
+func (eng *Engine) ParseJob(input string) (*Job, error) {
157
+	// FIXME: use a full-featured command parser
158
+	scanner := bufio.NewScanner(strings.NewReader(input))
159
+	scanner.Split(bufio.ScanWords)
160
+	var (
161
+		cmd []string
162
+		env Env
163
+	)
164
+	for scanner.Scan() {
165
+		word := scanner.Text()
166
+		kv := strings.SplitN(word, "=", 2)
167
+		if len(kv) == 2 {
168
+			env.Set(kv[0], kv[1])
169
+		} else {
170
+			cmd = append(cmd, word)
171
+		}
172
+	}
173
+	if len(cmd) == 0 {
174
+		return nil, fmt.Errorf("empty command: '%s'", input)
175
+	}
176
+	job := eng.Job(cmd[0], cmd[1:]...)
177
+	job.Env().Init(&env)
178
+	return job, nil
179
+}
180
+
139 181
 func (eng *Engine) Logf(format string, args ...interface{}) (n int, err error) {
140 182
 	if os.Getenv("TEST") == "" {
141 183
 		prefixedFormat := fmt.Sprintf("[%s] %s\n", eng, strings.TrimRight(format, "\n"))
... ...
@@ -36,6 +36,13 @@ func (env *Env) Exists(key string) bool {
36 36
 	return exists
37 37
 }
38 38
 
39
+func (env *Env) Init(src *Env) {
40
+	*env = make([]string, 0, len(*src))
41
+	for _, val := range *src {
42
+		(*env) = append((*env), val)
43
+	}
44
+}
45
+
39 46
 func (env *Env) GetBool(key string) (value bool) {
40 47
 	s := strings.ToLower(strings.Trim(env.Get(key), " \t"))
41 48
 	if s == "" || s == "0" || s == "no" || s == "false" || s == "none" {
... ...
@@ -102,6 +102,10 @@ func (job *Job) String() string {
102 102
 	return fmt.Sprintf("%s.%s%s", job.Eng, job.CallString(), job.StatusString())
103 103
 }
104 104
 
105
+func (job *Job) Env() *Env {
106
+	return job.env
107
+}
108
+
105 109
 func (job *Job) EnvExists(key string) (value bool) {
106 110
 	return job.env.Exists(key)
107 111
 }