github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/cli/opts/file.go (about) 1 package opts 2 3 import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "os" 8 "strings" 9 "unicode" 10 "unicode/utf8" 11 ) 12 13 const whiteSpaces = " \t" 14 15 // ErrBadKey typed error for bad environment variable 16 type ErrBadKey struct { 17 msg string 18 } 19 20 func (e ErrBadKey) Error() string { 21 return fmt.Sprintf("poorly formatted environment: %s", e.msg) 22 } 23 24 func parseKeyValueFile(filename string, emptyFn func(string) (string, bool)) ([]string, error) { 25 fh, err := os.Open(filename) 26 if err != nil { 27 return []string{}, err 28 } 29 defer fh.Close() 30 31 lines := []string{} 32 scanner := bufio.NewScanner(fh) 33 currentLine := 0 34 utf8bom := []byte{0xEF, 0xBB, 0xBF} 35 for scanner.Scan() { 36 scannedBytes := scanner.Bytes() 37 if !utf8.Valid(scannedBytes) { 38 return []string{}, fmt.Errorf("env file %s contains invalid utf8 bytes at line %d: %v", filename, currentLine+1, scannedBytes) 39 } 40 // We trim UTF8 BOM 41 if currentLine == 0 { 42 scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom) 43 } 44 // trim the line from all leading whitespace first 45 line := strings.TrimLeftFunc(string(scannedBytes), unicode.IsSpace) 46 currentLine++ 47 // line is not empty, and not starting with '#' 48 if len(line) > 0 && !strings.HasPrefix(line, "#") { 49 data := strings.SplitN(line, "=", 2) 50 51 // trim the front of a variable, but nothing else 52 variable := strings.TrimLeft(data[0], whiteSpaces) 53 if strings.ContainsAny(variable, whiteSpaces) { 54 return []string{}, ErrBadKey{fmt.Sprintf("variable '%s' contains whitespaces", variable)} 55 } 56 if len(variable) == 0 { 57 return []string{}, ErrBadKey{fmt.Sprintf("no variable name on line '%s'", line)} 58 } 59 60 if len(data) > 1 { 61 // pass the value through, no trimming 62 lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1])) 63 } else { 64 var value string 65 var present bool 66 if emptyFn != nil { 67 value, present = emptyFn(line) 68 } 69 if present { 70 // if only a pass-through variable is given, clean it up. 71 lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), value)) 72 } 73 } 74 } 75 } 76 return lines, scanner.Err() 77 }