github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/build/kubefile/parser/split_command.go (about)

     1  // Copyright © 2022 Alibaba Group Holding Ltd.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package parser
    16  
    17  import (
    18  	"strings"
    19  	"unicode"
    20  )
    21  
    22  // splitCommand takes a single line of text and parses out the cmd and args,
    23  // which are used for dispatching to more exact parsing functions.
    24  //
    25  //nolint:unparam
    26  func splitCommand(line string) (string, []string, string, error) {
    27  	var args string
    28  	var flags []string
    29  
    30  	// Make sure we get the same results irrespective of leading/trailing spaces
    31  	cmdline := tokenWhitespace.Split(strings.TrimSpace(line), 2)
    32  	cmd := strings.ToLower(cmdline[0])
    33  
    34  	if len(cmdline) == 2 {
    35  		args, flags = extractBuilderFlags(cmdline[1])
    36  	}
    37  
    38  	return cmd, flags, strings.TrimSpace(args), nil
    39  }
    40  
    41  func extractBuilderFlags(line string) (string, []string) {
    42  	// Parses the BuilderFlags and returns the remaining part of the line
    43  
    44  	const (
    45  		inSpaces = iota // looking for start of a word
    46  		inWord
    47  		inQuote
    48  	)
    49  
    50  	words := []string{}
    51  	phase := inSpaces
    52  	word := ""
    53  	quote := '\000'
    54  	blankOK := false
    55  	var ch rune
    56  
    57  	for pos := 0; pos <= len(line); pos++ {
    58  		if pos != len(line) {
    59  			ch = rune(line[pos])
    60  		}
    61  
    62  		if phase == inSpaces { // Looking for start of word
    63  			if pos == len(line) { // end of input
    64  				break
    65  			}
    66  			if unicode.IsSpace(ch) { // skip spaces
    67  				continue
    68  			}
    69  
    70  			// Only keep going if the next word starts with --
    71  			if ch != '-' || pos+1 == len(line) || rune(line[pos+1]) != '-' {
    72  				return line[pos:], words
    73  			}
    74  
    75  			phase = inWord // found something with "--", fall through
    76  		}
    77  		if (phase == inWord || phase == inQuote) && (pos == len(line)) {
    78  			if word != "--" && (blankOK || len(word) > 0) {
    79  				words = append(words, word)
    80  			}
    81  			break
    82  		}
    83  		if phase == inWord {
    84  			if unicode.IsSpace(ch) {
    85  				phase = inSpaces
    86  				if word == "--" {
    87  					return line[pos:], words
    88  				}
    89  				if blankOK || len(word) > 0 {
    90  					words = append(words, word)
    91  				}
    92  				word = ""
    93  				blankOK = false
    94  				continue
    95  			}
    96  			if ch == '\'' || ch == '"' {
    97  				quote = ch
    98  				blankOK = true
    99  				phase = inQuote
   100  				continue
   101  			}
   102  			if ch == '\\' {
   103  				if pos+1 == len(line) {
   104  					continue // just skip \ at end
   105  				}
   106  				pos++
   107  				ch = rune(line[pos])
   108  			}
   109  			word += string(ch)
   110  			continue
   111  		}
   112  		if phase == inQuote {
   113  			if ch == quote {
   114  				phase = inWord
   115  				continue
   116  			}
   117  			if ch == '\\' {
   118  				if pos+1 == len(line) {
   119  					phase = inWord
   120  					continue // just skip \ at end
   121  				}
   122  				pos++
   123  				ch = rune(line[pos])
   124  			}
   125  			word += string(ch)
   126  		}
   127  	}
   128  
   129  	return "", words
   130  }