Skip to content

Commit 2b17f4c

Browse files
committed
Fix --label-file weird behavior
`--label-file` has the exact same behavior as `--env-file`, meaning any placeholder (i.e. a simple key, no `=` sign, no value), it will get the value from the environment variable. For `--label-file` it should just add an empty label. Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent 819df0e commit 2b17f4c

File tree

6 files changed

+98
-74
lines changed

6 files changed

+98
-74
lines changed

cli/command/container/opts.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
145145
expose: opts.NewListOpts(nil),
146146
extraHosts: opts.NewListOpts(opts.ValidateExtraHost),
147147
groupAdd: opts.NewListOpts(nil),
148-
labels: opts.NewListOpts(opts.ValidateEnv),
148+
labels: opts.NewListOpts(opts.ValidateLabel),
149149
labelsFile: opts.NewListOpts(nil),
150150
linkLocalIPs: opts.NewListOpts(nil),
151151
links: opts.NewListOpts(opts.ValidateLink),
@@ -410,7 +410,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
410410
}
411411

412412
// collect all the environment variables for the container
413-
envVariables, err := opts.ReadKVStrings(copts.envFile.GetAll(), copts.env.GetAll())
413+
envVariables, err := opts.ReadKVEnvStrings(copts.envFile.GetAll(), copts.env.GetAll())
414414
if err != nil {
415415
return nil, err
416416
}

cli/command/service/opts.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ func (options *serviceOptions) ToStopGracePeriod(flags *pflag.FlagSet) *time.Dur
560560
func (options *serviceOptions) ToService(ctx context.Context, apiClient client.NetworkAPIClient, flags *pflag.FlagSet) (swarm.ServiceSpec, error) {
561561
var service swarm.ServiceSpec
562562

563-
envVariables, err := opts.ReadKVStrings(options.envFile.GetAll(), options.env.GetAll())
563+
envVariables, err := opts.ReadKVEnvStrings(options.envFile.GetAll(), options.env.GetAll())
564564
if err != nil {
565565
return service, err
566566
}

opts/envfile.go

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
package opts
22

33
import (
4-
"bufio"
5-
"bytes"
6-
"fmt"
74
"os"
8-
"strings"
9-
"unicode"
10-
"unicode/utf8"
115
)
126

137
// ParseEnvFile reads a file with environment variables enumerated by lines
@@ -24,58 +18,5 @@ import (
2418
// environment variables, that's why we just strip leading whitespace and
2519
// nothing more.
2620
func ParseEnvFile(filename string) ([]string, error) {
27-
fh, err := os.Open(filename)
28-
if err != nil {
29-
return []string{}, err
30-
}
31-
defer fh.Close()
32-
33-
lines := []string{}
34-
scanner := bufio.NewScanner(fh)
35-
currentLine := 0
36-
utf8bom := []byte{0xEF, 0xBB, 0xBF}
37-
for scanner.Scan() {
38-
scannedBytes := scanner.Bytes()
39-
if !utf8.Valid(scannedBytes) {
40-
return []string{}, fmt.Errorf("env file %s contains invalid utf8 bytes at line %d: %v", filename, currentLine+1, scannedBytes)
41-
}
42-
// We trim UTF8 BOM
43-
if currentLine == 0 {
44-
scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
45-
}
46-
// trim the line from all leading whitespace first
47-
line := strings.TrimLeftFunc(string(scannedBytes), unicode.IsSpace)
48-
currentLine++
49-
// line is not empty, and not starting with '#'
50-
if len(line) > 0 && !strings.HasPrefix(line, "#") {
51-
data := strings.SplitN(line, "=", 2)
52-
53-
// trim the front of a variable, but nothing else
54-
variable := strings.TrimLeft(data[0], whiteSpaces)
55-
if strings.ContainsAny(variable, whiteSpaces) {
56-
return []string{}, ErrBadEnvVariable{fmt.Sprintf("variable '%s' has white spaces", variable)}
57-
}
58-
59-
if len(data) > 1 {
60-
61-
// pass the value through, no trimming
62-
lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1]))
63-
} else {
64-
// if only a pass-through variable is given, clean it up.
65-
lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), os.Getenv(line)))
66-
}
67-
}
68-
}
69-
return lines, scanner.Err()
70-
}
71-
72-
var whiteSpaces = " \t"
73-
74-
// ErrBadEnvVariable typed error for bad environment variable
75-
type ErrBadEnvVariable struct {
76-
msg string
77-
}
78-
79-
func (e ErrBadEnvVariable) Error() string {
80-
return fmt.Sprintf("poorly formatted environment: %s", e.msg)
21+
return parseKeyValueFile(filename, os.Getenv)
8122
}

opts/envfile_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,10 @@ func TestParseEnvFileBadlyFormattedFile(t *testing.T) {
9595

9696
_, err := ParseEnvFile(tmpFile)
9797
if err == nil {
98-
t.Fatalf("Expected an ErrBadEnvVariable, got nothing")
98+
t.Fatalf("Expected an ErrBadKey, got nothing")
9999
}
100-
if _, ok := err.(ErrBadEnvVariable); !ok {
101-
t.Fatalf("Expected an ErrBadEnvVariable, got [%v]", err)
100+
if _, ok := err.(ErrBadKey); !ok {
101+
t.Fatalf("Expected an ErrBadKey, got [%v]", err)
102102
}
103103
expectedMessage := "poorly formatted environment: variable 'f ' has white spaces"
104104
if err.Error() != expectedMessage {
@@ -129,10 +129,10 @@ another invalid line`
129129

130130
_, err := ParseEnvFile(tmpFile)
131131
if err == nil {
132-
t.Fatalf("Expected an ErrBadEnvVariable, got nothing")
132+
t.Fatalf("Expected an ErrBadKey, got nothing")
133133
}
134-
if _, ok := err.(ErrBadEnvVariable); !ok {
135-
t.Fatalf("Expected an ErrBadEnvVariable, got [%v]", err)
134+
if _, ok := err.(ErrBadKey); !ok {
135+
t.Fatalf("Expected an ErrBadKey, got [%v]", err)
136136
}
137137
expectedMessage := "poorly formatted environment: variable 'first line' has white spaces"
138138
if err.Error() != expectedMessage {

opts/file.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package opts
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"fmt"
7+
"os"
8+
"strings"
9+
"unicode"
10+
"unicode/utf8"
11+
)
12+
13+
var 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) ([]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' has white spaces", variable)}
55+
}
56+
57+
if len(data) > 1 {
58+
// pass the value through, no trimming
59+
lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1]))
60+
} else {
61+
var value string
62+
if emptyFn != nil {
63+
value = emptyFn(line)
64+
}
65+
// if only a pass-through variable is given, clean it up.
66+
lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), value))
67+
}
68+
}
69+
}
70+
return lines, scanner.Err()
71+
}

opts/parse.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package opts
22

33
import (
44
"fmt"
5+
"os"
56
"strconv"
67
"strings"
78

@@ -11,18 +12,29 @@ import (
1112
// ReadKVStrings reads a file of line terminated key=value pairs, and overrides any keys
1213
// present in the file with additional pairs specified in the override parameter
1314
func ReadKVStrings(files []string, override []string) ([]string, error) {
14-
envVariables := []string{}
15+
return readKVStrings(files, override, nil)
16+
}
17+
18+
// ReadKVEnvStrings reads a file of line terminated key=value pairs, and overrides any keys
19+
// present in the file with additional pairs specified in the override parameter.
20+
// If a key has no value, it will get the value from the environment.
21+
func ReadKVEnvStrings(files []string, override []string) ([]string, error) {
22+
return readKVStrings(files, override, os.Getenv)
23+
}
24+
25+
func readKVStrings(files []string, override []string, emptyFn func(string) string) ([]string, error) {
26+
variables := []string{}
1527
for _, ef := range files {
16-
parsedVars, err := ParseEnvFile(ef)
28+
parsedVars, err := parseKeyValueFile(ef, emptyFn)
1729
if err != nil {
1830
return nil, err
1931
}
20-
envVariables = append(envVariables, parsedVars...)
32+
variables = append(variables, parsedVars...)
2133
}
2234
// parse the '-e' and '--env' after, to allow override
23-
envVariables = append(envVariables, override...)
35+
variables = append(variables, override...)
2436

25-
return envVariables, nil
37+
return variables, nil
2638
}
2739

2840
// ConvertKVStringsToMap converts ["key=value"] to {"key":"value"}

0 commit comments

Comments
 (0)