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  }