github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/lintcmd/config.go (about) 1 package lintcmd 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "io" 8 "strings" 9 "unicode" 10 ) 11 12 type parseBuildConfigError struct { 13 line int 14 err error 15 } 16 17 func (err parseBuildConfigError) Error() string { return err.err.Error() } 18 19 func parseBuildConfigs(r io.Reader) ([]buildConfig, error) { 20 var builds []buildConfig 21 br := bufio.NewReader(r) 22 i := 0 23 for { 24 line, err := br.ReadString('\n') 25 if err != nil { 26 if err == io.EOF { 27 break 28 } else { 29 return nil, err 30 } 31 } 32 line = strings.TrimSpace(line) 33 if line == "" { 34 continue 35 } 36 name, envs, flags, err := parseBuildConfig(line) 37 if err != nil { 38 return nil, parseBuildConfigError{line: i + 1, err: err} 39 } 40 41 bc := buildConfig{ 42 Name: name, 43 Envs: envs, 44 Flags: flags, 45 } 46 builds = append(builds, bc) 47 48 i++ 49 } 50 return builds, nil 51 } 52 53 func parseBuildConfig(line string) (name string, envs []string, flags []string, err error) { 54 if line == "" { 55 return "", nil, nil, errors.New("couldn't parse empty build config") 56 } 57 if strings.Index(line, ":") == len(line)-1 { 58 name = line[:len(line)-1] 59 } else { 60 idx := strings.Index(line, ": ") 61 if idx == -1 { 62 return name, envs, flags, errors.New("missing build name") 63 } 64 name = line[:idx] 65 66 var buf []rune 67 var inQuote bool 68 args := &envs 69 for _, r := range strings.TrimSpace(line[idx+2:]) { 70 switch r { 71 case ' ': 72 if inQuote { 73 buf = append(buf, r) 74 } else if len(buf) != 0 { 75 if buf[0] == '-' { 76 args = &flags 77 } 78 *args = append(*args, string(buf)) 79 buf = buf[:0] 80 } 81 case '"': 82 inQuote = !inQuote 83 default: 84 buf = append(buf, r) 85 } 86 } 87 88 if len(buf) > 0 { 89 if inQuote { 90 return "", nil, nil, errors.New("unterminated quoted string") 91 } 92 if buf[0] == '-' { 93 args = &flags 94 } 95 *args = append(*args, string(buf)) 96 } 97 } 98 99 for _, r := range name { 100 if !(r == '_' || unicode.IsLetter(r) || unicode.IsNumber(r)) { 101 return "", nil, nil, fmt.Errorf("invalid build name %q", name) 102 } 103 } 104 return name, envs, flags, nil 105 }