Merge pull request #505 from yui-knk/use_string_map

Add `ProcessWordWithMap` to `Lex`
docker-18.09
Tõnis Tiigi 2018-07-16 15:36:34 -07:00 committed by GitHub
commit 64511e0ebf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 24 deletions

View File

@ -28,7 +28,7 @@ func NewLex(escapeToken rune) *Lex {
// ProcessWord will use the 'env' list of environment variables, // ProcessWord will use the 'env' list of environment variables,
// and replace any env var references in 'word'. // and replace any env var references in 'word'.
func (s *Lex) ProcessWord(word string, env []string) (string, error) { func (s *Lex) ProcessWord(word string, env []string) (string, error) {
word, _, err := s.process(word, env) word, _, err := s.process(word, buildEnvs(env))
return word, err return word, err
} }
@ -40,11 +40,18 @@ func (s *Lex) ProcessWord(word string, env []string) (string, error) {
// Note, each one is trimmed to remove leading and trailing spaces (unless // Note, each one is trimmed to remove leading and trailing spaces (unless
// they are quoted", but ProcessWord retains spaces between words. // they are quoted", but ProcessWord retains spaces between words.
func (s *Lex) ProcessWords(word string, env []string) ([]string, error) { func (s *Lex) ProcessWords(word string, env []string) ([]string, error) {
_, words, err := s.process(word, env) _, words, err := s.process(word, buildEnvs(env))
return words, err return words, err
} }
func (s *Lex) process(word string, env []string) (string, []string, error) { // ProcessWordWithMap will use the 'env' list of environment variables,
// and replace any env var references in 'word'.
func (s *Lex) ProcessWordWithMap(word string, env map[string]string) (string, error) {
word, _, err := s.process(word, env)
return word, err
}
func (s *Lex) process(word string, env map[string]string) (string, []string, error) {
sw := &shellWord{ sw := &shellWord{
envs: env, envs: env,
escapeToken: s.escapeToken, escapeToken: s.escapeToken,
@ -55,7 +62,7 @@ func (s *Lex) process(word string, env []string) (string, []string, error) {
type shellWord struct { type shellWord struct {
scanner scanner.Scanner scanner scanner.Scanner
envs []string envs map[string]string
escapeToken rune escapeToken rune
} }
@ -353,21 +360,33 @@ func isSpecialParam(char rune) bool {
} }
func (sw *shellWord) getEnv(name string) string { func (sw *shellWord) getEnv(name string) string {
for _, env := range sw.envs { for key, value := range sw.envs {
i := strings.Index(env, "=") if EqualEnvKeys(name, key) {
if i < 0 { return value
if EqualEnvKeys(name, env) {
// Should probably never get here, but just in case treat
// it like "var" and "var=" are the same
return ""
}
continue
} }
compareName := env[:i]
if !EqualEnvKeys(name, compareName) {
continue
}
return env[i+1:]
} }
return "" return ""
} }
func buildEnvs(env []string) map[string]string {
envs := map[string]string{}
for _, e := range env {
i := strings.Index(e, "=")
if i < 0 {
envs[e] = ""
} else {
k := e[:i]
v := e[i+1:]
// If key already exists, keep previous value.
if _, ok := envs[k]; ok {
continue
}
envs[k] = v
}
}
return envs
}

View File

@ -22,6 +22,7 @@ func TestShellParser4EnvVars(t *testing.T) {
shlex := NewLex('\\') shlex := NewLex('\\')
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
envs := []string{"PWD=/home", "SHELL=bash", "KOREAN=한국어"} envs := []string{"PWD=/home", "SHELL=bash", "KOREAN=한국어"}
envsMap := buildEnvs(envs)
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
lineCount++ lineCount++
@ -56,6 +57,14 @@ func TestShellParser4EnvVars(t *testing.T) {
assert.Check(t, err, "at line %d of %s", lineCount, fn) assert.Check(t, err, "at line %d of %s", lineCount, fn)
assert.Check(t, is.Equal(newWord, expected), "at line %d of %s", lineCount, fn) assert.Check(t, is.Equal(newWord, expected), "at line %d of %s", lineCount, fn)
} }
newWord, err = shlex.ProcessWordWithMap(source, envsMap)
if expected == "error" {
assert.Check(t, is.ErrorContains(err, ""), "input: %q, result: %q", source, newWord)
} else {
assert.Check(t, err, "at line %d of %s", lineCount, fn)
assert.Check(t, is.Equal(newWord, expected), "at line %d of %s", lineCount, fn)
}
} }
} }
} }
@ -114,27 +123,27 @@ func TestShellParser4Words(t *testing.T) {
func TestGetEnv(t *testing.T) { func TestGetEnv(t *testing.T) {
sw := &shellWord{envs: nil} sw := &shellWord{envs: nil}
sw.envs = []string{} sw.envs = buildEnvs([]string{})
if sw.getEnv("foo") != "" { if sw.getEnv("foo") != "" {
t.Fatal("2 - 'foo' should map to ''") t.Fatal("2 - 'foo' should map to ''")
} }
sw.envs = []string{"foo"} sw.envs = buildEnvs([]string{"foo"})
if sw.getEnv("foo") != "" { if sw.getEnv("foo") != "" {
t.Fatal("3 - 'foo' should map to ''") t.Fatal("3 - 'foo' should map to ''")
} }
sw.envs = []string{"foo="} sw.envs = buildEnvs([]string{"foo="})
if sw.getEnv("foo") != "" { if sw.getEnv("foo") != "" {
t.Fatal("4 - 'foo' should map to ''") t.Fatal("4 - 'foo' should map to ''")
} }
sw.envs = []string{"foo=bar"} sw.envs = buildEnvs([]string{"foo=bar"})
if sw.getEnv("foo") != "bar" { if sw.getEnv("foo") != "bar" {
t.Fatal("5 - 'foo' should map to 'bar'") t.Fatal("5 - 'foo' should map to 'bar'")
} }
sw.envs = []string{"foo=bar", "car=hat"} sw.envs = buildEnvs([]string{"foo=bar", "car=hat"})
if sw.getEnv("foo") != "bar" { if sw.getEnv("foo") != "bar" {
t.Fatal("6 - 'foo' should map to 'bar'") t.Fatal("6 - 'foo' should map to 'bar'")
} }
@ -143,7 +152,7 @@ func TestGetEnv(t *testing.T) {
} }
// Make sure we grab the first 'car' in the list // Make sure we grab the first 'car' in the list
sw.envs = []string{"foo=bar", "car=hat", "car=bike"} sw.envs = buildEnvs([]string{"foo=bar", "car=hat", "car=bike"})
if sw.getEnv("car") != "hat" { if sw.getEnv("car") != "hat" {
t.Fatal("8 - 'car' should map to 'hat'") t.Fatal("8 - 'car' should map to 'hat'")
} }