github.com/sams1990/dockerrepo@v17.12.1-ce-rc2+incompatible/builder/dockerfile/parser/split_command.go (about)

     1  package parser
     2  
     3  import (
     4  	"strings"
     5  	"unicode"
     6  )
     7  
     8  // splitCommand takes a single line of text and parses out the cmd and args,
     9  // which are used for dispatching to more exact parsing functions.
    10  func splitCommand(line string) (string, []string, string, error) {
    11  	var args string
    12  	var flags []string
    13  
    14  	// Make sure we get the same results irrespective of leading/trailing spaces
    15  	cmdline := tokenWhitespace.Split(strings.TrimSpace(line), 2)
    16  	cmd := strings.ToLower(cmdline[0])
    17  
    18  	if len(cmdline) == 2 {
    19  		var err error
    20  		args, flags, err = extractBuilderFlags(cmdline[1])
    21  		if err != nil {
    22  			return "", nil, "", err
    23  		}
    24  	}
    25  
    26  	return cmd, flags, strings.TrimSpace(args), nil
    27  }
    28  
    29  func extractBuilderFlags(line string) (string, []string, error) {
    30  	// Parses the BuilderFlags and returns the remaining part of the line
    31  
    32  	const (
    33  		inSpaces = iota // looking for start of a word
    34  		inWord
    35  		inQuote
    36  	)
    37  
    38  	words := []string{}
    39  	phase := inSpaces
    40  	word := ""
    41  	quote := '\000'
    42  	blankOK := false
    43  	var ch rune
    44  
    45  	for pos := 0; pos <= len(line); pos++ {
    46  		if pos != len(line) {
    47  			ch = rune(line[pos])
    48  		}
    49  
    50  		if phase == inSpaces { // Looking for start of word
    51  			if pos == len(line) { // end of input
    52  				break
    53  			}
    54  			if unicode.IsSpace(ch) { // skip spaces
    55  				continue
    56  			}
    57  
    58  			// Only keep going if the next word starts with --
    59  			if ch != '-' || pos+1 == len(line) || rune(line[pos+1]) != '-' {
    60  				return line[pos:], words, nil
    61  			}
    62  
    63  			phase = inWord // found something with "--", fall through
    64  		}
    65  		if (phase == inWord || phase == inQuote) && (pos == len(line)) {
    66  			if word != "--" && (blankOK || len(word) > 0) {
    67  				words = append(words, word)
    68  			}
    69  			break
    70  		}
    71  		if phase == inWord {
    72  			if unicode.IsSpace(ch) {
    73  				phase = inSpaces
    74  				if word == "--" {
    75  					return line[pos:], words, nil
    76  				}
    77  				if blankOK || len(word) > 0 {
    78  					words = append(words, word)
    79  				}
    80  				word = ""
    81  				blankOK = false
    82  				continue
    83  			}
    84  			if ch == '\'' || ch == '"' {
    85  				quote = ch
    86  				blankOK = true
    87  				phase = inQuote
    88  				continue
    89  			}
    90  			if ch == '\\' {
    91  				if pos+1 == len(line) {
    92  					continue // just skip \ at end
    93  				}
    94  				pos++
    95  				ch = rune(line[pos])
    96  			}
    97  			word += string(ch)
    98  			continue
    99  		}
   100  		if phase == inQuote {
   101  			if ch == quote {
   102  				phase = inWord
   103  				continue
   104  			}
   105  			if ch == '\\' {
   106  				if pos+1 == len(line) {
   107  					phase = inWord
   108  					continue // just skip \ at end
   109  				}
   110  				pos++
   111  				ch = rune(line[pos])
   112  			}
   113  			word += string(ch)
   114  		}
   115  	}
   116  
   117  	return "", words, nil
   118  }