mirror of https://github.com/docker/compose.git
config: case-insensitive env vars on Windows (#9438)
Signed-off-by: IKEDA Yasuyuki <devld@ikedam.jp>
This commit is contained in:
parent
d0d06d414d
commit
bbaaa6a9de
|
@ -50,10 +50,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
|
|||
opts := map[string]build.Options{}
|
||||
var imagesToBuild []string
|
||||
|
||||
args := flatten(options.Args.Resolve(func(s string) (string, bool) {
|
||||
s, ok := project.Environment[s]
|
||||
return s, ok
|
||||
}))
|
||||
args := flatten(options.Args.Resolve(envResolver(project.Environment)))
|
||||
|
||||
services, err := project.GetServices(options.Services...)
|
||||
if err != nil {
|
||||
|
@ -214,10 +211,7 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
|
|||
var tags []string
|
||||
tags = append(tags, imageTag)
|
||||
|
||||
buildArgs := flatten(service.Build.Args.Resolve(func(s string) (string, bool) {
|
||||
s, ok := project.Environment[s]
|
||||
return s, ok
|
||||
}))
|
||||
buildArgs := flatten(service.Build.Args.Resolve(envResolver(project.Environment)))
|
||||
|
||||
var plats []specs.Platform
|
||||
if platform, ok := project.Environment["DOCKER_DEFAULT_PLATFORM"]; ok {
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// isCaseInsensitiveEnvVars is true on platforms where environment variable names are treated case-insensitively.
|
||||
isCaseInsensitiveEnvVars = (runtime.GOOS == "windows")
|
||||
)
|
||||
|
||||
// envResolver returns resolver for environment variables suitable for the current platform.
|
||||
// Expected to be used with `MappingWithEquals.Resolve`.
|
||||
// Updates in `environment` may not be reflected.
|
||||
func envResolver(environment map[string]string) func(string) (string, bool) {
|
||||
return envResolverWithCase(environment, isCaseInsensitiveEnvVars)
|
||||
}
|
||||
|
||||
// envResolverWithCase returns resolver for environment variables with the specified case-sensitive condition.
|
||||
// Expected to be used with `MappingWithEquals.Resolve`.
|
||||
// Updates in `environment` may not be reflected.
|
||||
func envResolverWithCase(environment map[string]string, caseInsensitive bool) func(string) (string, bool) {
|
||||
if environment == nil {
|
||||
return func(s string) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
if !caseInsensitive {
|
||||
return func(s string) (string, bool) {
|
||||
v, ok := environment[s]
|
||||
return v, ok
|
||||
}
|
||||
}
|
||||
// variable names must be treated case-insensitively.
|
||||
// Resolves in this way:
|
||||
// * Return the value if its name matches with the passed name case-sensitively.
|
||||
// * Otherwise, return the value if its lower-cased name matches lower-cased passed name.
|
||||
// * The value is indefinite if multiple variable matches.
|
||||
loweredEnvironment := make(map[string]string, len(environment))
|
||||
for k, v := range environment {
|
||||
loweredEnvironment[strings.ToLower(k)] = v
|
||||
}
|
||||
return func(s string) (string, bool) {
|
||||
v, ok := environment[s]
|
||||
if ok {
|
||||
return v, ok
|
||||
}
|
||||
v, ok = loweredEnvironment[strings.ToLower(s)]
|
||||
return v, ok
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func Test_EnvResolverWithCase(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
environment map[string]string
|
||||
caseInsensitive bool
|
||||
search string
|
||||
expectedValue string
|
||||
expectedOk bool
|
||||
}{
|
||||
{
|
||||
name: "case sensitive/case match",
|
||||
environment: map[string]string{
|
||||
"Env1": "Value1",
|
||||
"Env2": "Value2",
|
||||
},
|
||||
caseInsensitive: false,
|
||||
search: "Env1",
|
||||
expectedValue: "Value1",
|
||||
expectedOk: true,
|
||||
},
|
||||
{
|
||||
name: "case sensitive/case unmatch",
|
||||
environment: map[string]string{
|
||||
"Env1": "Value1",
|
||||
"Env2": "Value2",
|
||||
},
|
||||
caseInsensitive: false,
|
||||
search: "ENV1",
|
||||
expectedValue: "",
|
||||
expectedOk: false,
|
||||
},
|
||||
{
|
||||
name: "case sensitive/nil environment",
|
||||
environment: nil,
|
||||
caseInsensitive: false,
|
||||
search: "Env1",
|
||||
expectedValue: "",
|
||||
expectedOk: false,
|
||||
},
|
||||
{
|
||||
name: "case insensitive/case match",
|
||||
environment: map[string]string{
|
||||
"Env1": "Value1",
|
||||
"Env2": "Value2",
|
||||
},
|
||||
caseInsensitive: true,
|
||||
search: "Env1",
|
||||
expectedValue: "Value1",
|
||||
expectedOk: true,
|
||||
},
|
||||
{
|
||||
name: "case insensitive/case unmatch",
|
||||
environment: map[string]string{
|
||||
"Env1": "Value1",
|
||||
"Env2": "Value2",
|
||||
},
|
||||
caseInsensitive: true,
|
||||
search: "ENV1",
|
||||
expectedValue: "Value1",
|
||||
expectedOk: true,
|
||||
},
|
||||
{
|
||||
name: "case insensitive/unmatch",
|
||||
environment: map[string]string{
|
||||
"Env1": "Value1",
|
||||
"Env2": "Value2",
|
||||
},
|
||||
caseInsensitive: true,
|
||||
search: "Env3",
|
||||
expectedValue: "",
|
||||
expectedOk: false,
|
||||
},
|
||||
{
|
||||
name: "case insensitive/nil environment",
|
||||
environment: nil,
|
||||
caseInsensitive: true,
|
||||
search: "Env1",
|
||||
expectedValue: "",
|
||||
expectedOk: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
f := envResolverWithCase(test.environment, test.caseInsensitive)
|
||||
v, ok := f(test.search)
|
||||
assert.Equal(t, v, test.expectedValue)
|
||||
assert.Equal(t, ok, test.expectedOk)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -116,7 +116,7 @@ func applyRunOptions(project *types.Project, service *types.ServiceConfig, opts
|
|||
if len(opts.Environment) > 0 {
|
||||
cmdEnv := types.NewMappingWithEquals(opts.Environment)
|
||||
serviceOverrideEnv := cmdEnv.Resolve(func(s string) (string, bool) {
|
||||
v, ok := project.Environment[s]
|
||||
v, ok := envResolver(project.Environment)(s)
|
||||
return v, ok
|
||||
}).RemoveEmpty()
|
||||
service.Environment.OverrideBy(serviceOverrideEnv)
|
||||
|
|
Loading…
Reference in New Issue