From 2019a73f0387af273be3b6e085fdae0e5a67ba3b Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Sat, 15 Feb 2014 15:05:28 -0800 Subject: [PATCH] Engine.ParseJob: create a new job from a shell-like text command. Docker-DCO-1.1-Signed-off-by: Solomon Hykes (github: shykes) --- engine/engine.go | 43 +++++++++++++++++++++++++++++++++++++++++++ engine/env.go | 7 +++++++ engine/job.go | 4 ++++ 3 files changed, 54 insertions(+) diff --git a/engine/engine.go b/engine/engine.go index ec880b9c85..5814955fdd 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -1,6 +1,7 @@ package engine import ( + "bufio" "fmt" "github.com/dotcloud/docker/utils" "io" @@ -136,6 +137,48 @@ func (eng *Engine) Job(name string, args ...string) *Job { return job } +// ParseJob creates a new job from a text description using a shell-like syntax. +// +// The following syntax is used to parse `input`: +// +// * Words are separated using standard whitespaces as separators. +// * Quotes and backslashes are not interpreted. +// * Words of the form 'KEY=[VALUE]' are added to the job environment. +// * All other words are added to the job arguments. +// +// For example: +// +// job, _ := eng.ParseJob("VERBOSE=1 echo hello TEST=true world") +// +// The resulting job will have: +// job.Args={"echo", "hello", "world"} +// job.Env={"VERBOSE":"1", "TEST":"true"} +// +func (eng *Engine) ParseJob(input string) (*Job, error) { + // FIXME: use a full-featured command parser + scanner := bufio.NewScanner(strings.NewReader(input)) + scanner.Split(bufio.ScanWords) + var ( + cmd []string + env Env + ) + for scanner.Scan() { + word := scanner.Text() + kv := strings.SplitN(word, "=", 2) + if len(kv) == 2 { + env.Set(kv[0], kv[1]) + } else { + cmd = append(cmd, word) + } + } + if len(cmd) == 0 { + return nil, fmt.Errorf("empty command: '%s'", input) + } + job := eng.Job(cmd[0], cmd[1:]...) + job.Env().Init(&env) + return job, nil +} + func (eng *Engine) Logf(format string, args ...interface{}) (n int, err error) { if os.Getenv("TEST") == "" { prefixedFormat := fmt.Sprintf("[%s] %s\n", eng, strings.TrimRight(format, "\n")) diff --git a/engine/env.go b/engine/env.go index ce8c34bb24..7a6d946444 100644 --- a/engine/env.go +++ b/engine/env.go @@ -36,6 +36,13 @@ func (env *Env) Exists(key string) bool { return exists } +func (env *Env) Init(src *Env) { + *env = make([]string, 0, len(*src)) + for _, val := range *src { + (*env) = append((*env), val) + } +} + func (env *Env) GetBool(key string) (value bool) { s := strings.ToLower(strings.Trim(env.Get(key), " \t")) if s == "" || s == "0" || s == "no" || s == "false" || s == "none" { diff --git a/engine/job.go b/engine/job.go index 1f35ac85ff..9edb077a6d 100644 --- a/engine/job.go +++ b/engine/job.go @@ -102,6 +102,10 @@ func (job *Job) String() string { return fmt.Sprintf("%s.%s%s", job.Eng, job.CallString(), job.StatusString()) } +func (job *Job) Env() *Env { + return job.env +} + func (job *Job) EnvExists(key string) (value bool) { return job.env.Exists(key) }