Allow for env vars to have spaces in some cases

Closes #17781

This allows for env vars in EXPOSE to be parsed for spaces so that each
"word" is then treated independently instead of as a single word/arg.

Signed-off-by: Doug Davis <dug@us.ibm.com>
Upstream-commit: 6990f8c6162b5b05118ab54f155eb5d86c85f2d4
Component: engine
This commit is contained in:
Doug Davis
2015-11-07 12:05:55 -08:00
parent 28903f924d
commit 81b8a4871f
6 changed files with 202 additions and 21 deletions

View File

@ -29,17 +29,85 @@ func ProcessWord(word string, env []string) (string, error) {
pos: 0,
}
sw.scanner.Init(strings.NewReader(word))
return sw.process()
word, _, err := sw.process()
return word, err
}
func (sw *shellWord) process() (string, error) {
// ProcessWords will use the 'env' list of environment variables,
// and replace any env var references in 'word' then it will also
// return a slice of strings which represents the 'word'
// split up based on spaces - taking into account quotes. Note that
// this splitting is done **after** the env var substitutions are done.
// Note, each one is trimmed to remove leading and trailing spaces (unless
// they are quoted", but ProcessWord retains spaces between words.
func ProcessWords(word string, env []string) ([]string, error) {
sw := &shellWord{
word: word,
envs: env,
pos: 0,
}
sw.scanner.Init(strings.NewReader(word))
_, words, err := sw.process()
return words, err
}
func (sw *shellWord) process() (string, []string, error) {
return sw.processStopOn(scanner.EOF)
}
type wordsStruct struct {
word string
words []string
inWord bool
}
func (w *wordsStruct) addChar(ch rune) {
if unicode.IsSpace(ch) && w.inWord {
if len(w.word) != 0 {
w.words = append(w.words, w.word)
w.word = ""
w.inWord = false
}
} else if !unicode.IsSpace(ch) {
w.addRawChar(ch)
}
}
func (w *wordsStruct) addRawChar(ch rune) {
w.word += string(ch)
w.inWord = true
}
func (w *wordsStruct) addString(str string) {
var scan scanner.Scanner
scan.Init(strings.NewReader(str))
for scan.Peek() != scanner.EOF {
w.addChar(scan.Next())
}
}
func (w *wordsStruct) addRawString(str string) {
w.word += str
w.inWord = true
}
func (w *wordsStruct) getWords() []string {
if len(w.word) > 0 {
w.words = append(w.words, w.word)
// Just in case we're called again by mistake
w.word = ""
w.inWord = false
}
return w.words
}
// Process the word, starting at 'pos', and stop when we get to the
// end of the word or the 'stopChar' character
func (sw *shellWord) processStopOn(stopChar rune) (string, error) {
func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) {
var result string
var words wordsStruct
var charFuncMapping = map[rune]func() (string, error){
'\'': sw.processSingleQuote,
'"': sw.processDoubleQuote,
@ -57,9 +125,15 @@ func (sw *shellWord) processStopOn(stopChar rune) (string, error) {
// Call special processing func for certain chars
tmp, err := fn()
if err != nil {
return "", err
return "", []string{}, err
}
result += tmp
if ch == rune('$') {
words.addString(tmp)
} else {
words.addRawString(tmp)
}
} else {
// Not special, just add it to the result
ch = sw.scanner.Next()
@ -73,13 +147,16 @@ func (sw *shellWord) processStopOn(stopChar rune) (string, error) {
break
}
words.addRawChar(ch)
} else {
words.addChar(ch)
}
result += string(ch)
}
}
return result, nil
return result, words.getWords(), nil
}
func (sw *shellWord) processSingleQuote() (string, error) {
@ -160,7 +237,7 @@ func (sw *shellWord) processDollar() (string, error) {
sw.scanner.Next() // skip over :
modifier := sw.scanner.Next()
word, err := sw.processStopOn('}')
word, _, err := sw.processStopOn('}')
if err != nil {
return "", err
}