update github.com/compose-spec/compose-go to v1.9.0

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2023-02-03 03:19:59 +01:00
parent d2fa4a5724
commit 21ac4c34fb
14 changed files with 284 additions and 233 deletions

View File

@ -15,13 +15,9 @@ package dotenv
import (
"bytes"
"fmt"
"io"
"os"
"os/exec"
"regexp"
"sort"
"strconv"
"strings"
"github.com/compose-spec/compose-go/template"
@ -72,21 +68,6 @@ func Load(filenames ...string) error {
return load(false, filenames...)
}
// Overload will read your env file(s) and load them into ENV for this process.
//
// Call this function as close as possible to the start of your program (ideally in main).
//
// If you call Overload without any args it will default to loading .env in the current path.
//
// You can otherwise tell it which files to load (there can be more than one) like:
//
// godotenv.Overload("fileone", "filetwo")
//
// It's important to note this WILL OVERRIDE an env variable that already exists - consider the .env file to forcefilly set all vars.
func Overload(filenames ...string) error {
return load(true, filenames...)
}
func load(overload bool, filenames ...string) error {
filenames = filenamesOrDefault(filenames)
for _, filename := range filenames {
@ -128,82 +109,13 @@ func Read(filenames ...string) (map[string]string, error) {
return ReadWithLookup(nil, filenames...)
}
// Unmarshal reads an env file from a string, returning a map of keys and values.
func Unmarshal(str string) (map[string]string, error) {
return UnmarshalBytes([]byte(str))
}
// UnmarshalBytes parses env file from byte slice of chars, returning a map of keys and values.
func UnmarshalBytes(src []byte) (map[string]string, error) {
return UnmarshalBytesWithLookup(src, nil)
}
// UnmarshalBytesWithLookup parses env file from byte slice of chars, returning a map of keys and values.
func UnmarshalBytesWithLookup(src []byte, lookupFn LookupFn) (map[string]string, error) {
out := make(map[string]string)
err := parseBytes(src, out, lookupFn)
err := newParser().parseBytes(src, out, lookupFn)
return out, err
}
// Exec loads env vars from the specified filenames (empty map falls back to default)
// then executes the cmd specified.
//
// Simply hooks up os.Stdin/err/out to the command and calls Run()
//
// If you want more fine grained control over your command it's recommended
// that you use `Load()` or `Read()` and the `os/exec` package yourself.
//
// Deprecated: Use the `os/exec` package directly.
func Exec(filenames []string, cmd string, cmdArgs []string) error {
if err := Load(filenames...); err != nil {
return err
}
command := exec.Command(cmd, cmdArgs...)
command.Stdin = os.Stdin
command.Stdout = os.Stdout
command.Stderr = os.Stderr
return command.Run()
}
// Write serializes the given environment and writes it to a file
//
// Deprecated: The serialization functions are untested and unmaintained.
func Write(envMap map[string]string, filename string) error {
//goland:noinspection GoDeprecation
content, err := Marshal(envMap)
if err != nil {
return err
}
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(content + "\n")
if err != nil {
return err
}
return file.Sync()
}
// Marshal outputs the given environment as a dotenv-formatted environment file.
// Each line is in the format: KEY="VALUE" where VALUE is backslash-escaped.
//
// Deprecated: The serialization functions are untested and unmaintained.
func Marshal(envMap map[string]string) (string, error) {
lines := make([]string, 0, len(envMap))
for k, v := range envMap {
if d, err := strconv.Atoi(v); err == nil {
lines = append(lines, fmt.Sprintf(`%s=%d`, k, d))
} else {
lines = append(lines, fmt.Sprintf(`%s="%s"`, k, doubleQuoteEscape(v))) // nolint // Cannot use %q here
}
}
sort.Strings(lines)
return strings.Join(lines, "\n"), nil
}
func filenamesOrDefault(filenames []string) []string {
if len(filenames) == 0 {
return []string{".env"}
@ -255,19 +167,3 @@ func expandVariables(value string, envMap map[string]string, lookupFn LookupFn)
}
return retVal, nil
}
// Deprecated: only used by unsupported/untested code for Marshal/Write.
func doubleQuoteEscape(line string) string {
const doubleQuoteSpecialChars = "\\\n\r\"!$`"
for _, c := range doubleQuoteSpecialChars {
toReplace := "\\" + string(c)
if c == '\n' {
toReplace = `\n`
}
if c == '\r' {
toReplace = `\r`
}
line = strings.ReplaceAll(line, string(c), toReplace)
}
return line
}

View File

@ -21,24 +21,34 @@ var (
exportRegex = regexp.MustCompile(`^export\s+`)
)
func parseBytes(src []byte, out map[string]string, lookupFn LookupFn) error {
type parser struct {
line int
}
func newParser() *parser {
return &parser{
line: 1,
}
}
func (p *parser) parseBytes(src []byte, out map[string]string, lookupFn LookupFn) error {
cutset := src
if lookupFn == nil {
lookupFn = noLookupFn
}
for {
cutset = getStatementStart(cutset)
cutset = p.getStatementStart(cutset)
if cutset == nil {
// reached end of file
break
}
key, left, inherited, err := locateKeyName(cutset)
key, left, inherited, err := p.locateKeyName(cutset)
if err != nil {
return err
}
if strings.Contains(key, " ") {
return errors.New("key cannot contain a space")
return fmt.Errorf("line %d: key cannot contain a space", p.line)
}
if inherited {
@ -50,7 +60,7 @@ func parseBytes(src []byte, out map[string]string, lookupFn LookupFn) error {
continue
}
value, left, err := extractVarValue(left, out, lookupFn)
value, left, err := p.extractVarValue(left, out, lookupFn)
if err != nil {
return err
}
@ -65,8 +75,8 @@ func parseBytes(src []byte, out map[string]string, lookupFn LookupFn) error {
// getStatementPosition returns position of statement begin.
//
// It skips any comment line or non-whitespace character.
func getStatementStart(src []byte) []byte {
pos := indexOfNonSpaceChar(src)
func (p *parser) getStatementStart(src []byte) []byte {
pos := p.indexOfNonSpaceChar(src)
if pos == -1 {
return nil
}
@ -81,12 +91,11 @@ func getStatementStart(src []byte) []byte {
if pos == -1 {
return nil
}
return getStatementStart(src[pos:])
return p.getStatementStart(src[pos:])
}
// locateKeyName locates and parses key name and returns rest of slice
func locateKeyName(src []byte) (string, []byte, bool, error) {
func (p *parser) locateKeyName(src []byte) (string, []byte, bool, error) {
var key string
var inherited bool
// trim "export" and space at beginning
@ -108,16 +117,16 @@ loop:
offset = i + 1
inherited = char == '\n'
break loop
case '_', '.':
case '_', '.', '-', '[', ']':
default:
// variable name should match [A-Za-z0-9_.]
// variable name should match [A-Za-z0-9_.-]
if unicode.IsLetter(rchar) || unicode.IsNumber(rchar) {
continue
}
return "", nil, inherited, fmt.Errorf(
`unexpected character %q in variable name near %q`,
string(char), string(src))
`line %d: unexpected character %q in variable name`,
p.line, string(char))
}
}
@ -132,11 +141,12 @@ loop:
}
// extractVarValue extracts variable value and returns rest of slice
func extractVarValue(src []byte, envMap map[string]string, lookupFn LookupFn) (string, []byte, error) {
func (p *parser) extractVarValue(src []byte, envMap map[string]string, lookupFn LookupFn) (string, []byte, error) {
quote, isQuoted := hasQuotePrefix(src)
if !isQuoted {
// unquoted value - read until new line
value, rest, _ := bytes.Cut(src, []byte("\n"))
p.line++
// Remove inline comments on unquoted lines
value, _, _ = bytes.Cut(value, []byte(" #"))
@ -147,6 +157,9 @@ func extractVarValue(src []byte, envMap map[string]string, lookupFn LookupFn) (s
// lookup quoted string terminator
for i := 1; i < len(src); i++ {
if src[i] == '\n' {
p.line++
}
if char := src[i]; char != quote {
continue
}
@ -177,7 +190,7 @@ func extractVarValue(src []byte, envMap map[string]string, lookupFn LookupFn) (s
valEndIndex = len(src)
}
return "", nil, fmt.Errorf("unterminated quoted value %s", src[:valEndIndex])
return "", nil, fmt.Errorf("line %d: unterminated quoted value %s", p.line, src[:valEndIndex])
}
func expandEscapes(str string) string {
@ -212,8 +225,11 @@ func expandEscapes(str string) string {
return out
}
func indexOfNonSpaceChar(src []byte) int {
func (p *parser) indexOfNonSpaceChar(src []byte) int {
return bytes.IndexFunc(src, func(r rune) bool {
if r == '\n' {
p.line++
}
return !unicode.IsSpace(r)
})
}