mirror of
https://github.com/docker/compose.git
synced 2025-07-23 13:45:00 +02:00
allow a local .env file to override compose.yaml sibling .env
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
da8189cf22
commit
9e8c8caa2b
@ -171,7 +171,7 @@ func (o *ProjectOptions) addProjectFlags(f *pflag.FlagSet) {
|
|||||||
f.StringArrayVar(&o.Profiles, "profile", []string{}, "Specify a profile to enable")
|
f.StringArrayVar(&o.Profiles, "profile", []string{}, "Specify a profile to enable")
|
||||||
f.StringVarP(&o.ProjectName, "project-name", "p", "", "Project name")
|
f.StringVarP(&o.ProjectName, "project-name", "p", "", "Project name")
|
||||||
f.StringArrayVarP(&o.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
|
f.StringArrayVarP(&o.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
|
||||||
f.StringArrayVar(&o.EnvFiles, "env-file", nil, "Specify an alternate environment file")
|
f.StringArrayVar(&o.EnvFiles, "env-file", defaultStringArrayVar(ComposeEnvFiles), "Specify an alternate environment file")
|
||||||
f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the, first specified, Compose file)")
|
f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the, first specified, Compose file)")
|
||||||
f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the, first specified, Compose file)")
|
f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the, first specified, Compose file)")
|
||||||
f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
|
f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
|
||||||
@ -180,6 +180,13 @@ func (o *ProjectOptions) addProjectFlags(f *pflag.FlagSet) {
|
|||||||
_ = f.MarkHidden("workdir")
|
_ = f.MarkHidden("workdir")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get default value for a command line flag that is set by a coma-separated value in environment variable
|
||||||
|
func defaultStringArrayVar(env string) []string {
|
||||||
|
return strings.FieldsFunc(os.Getenv(env), func(c rune) bool {
|
||||||
|
return c == ','
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (o *ProjectOptions) projectOrName(ctx context.Context, dockerCli command.Cli, services ...string) (*types.Project, string, error) {
|
func (o *ProjectOptions) projectOrName(ctx context.Context, dockerCli command.Cli, services ...string) (*types.Project, string, error) {
|
||||||
name := o.ProjectName
|
name := o.ProjectName
|
||||||
var project *types.Project
|
var project *types.Project
|
||||||
@ -384,7 +391,7 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli
|
|||||||
ctx := cmd.Context()
|
ctx := cmd.Context()
|
||||||
|
|
||||||
// (1) process env vars
|
// (1) process env vars
|
||||||
err := setEnvWithDotEnv(&opts)
|
err := setEnvWithLocalDotEnv(&opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -594,18 +601,29 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func setEnvWithDotEnv(prjOpts *ProjectOptions) error {
|
// If user has a local .env file, load it as os.environment so it can be used to set COMPOSE_ variables
|
||||||
if len(prjOpts.EnvFiles) == 0 {
|
// This also allows to override values set by the default .env in a compose project when ran from a distinct folder
|
||||||
if envFiles := os.Getenv(ComposeEnvFiles); envFiles != "" {
|
func setEnvWithLocalDotEnv(prjOpts *ProjectOptions) error {
|
||||||
prjOpts.EnvFiles = strings.Split(envFiles, ",")
|
if len(prjOpts.EnvFiles) > 0 {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
options, err := prjOpts.toProjectOptions()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return compose.WrapComposeError(err)
|
return compose.WrapComposeError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
envFromFile, err := dotenv.GetEnvFromFile(composegoutils.GetAsEqualsMap(os.Environ()), options.EnvFiles)
|
defaultDotEnv := filepath.Join(wd, ".env")
|
||||||
|
|
||||||
|
s, err := os.Stat(defaultDotEnv)
|
||||||
|
if os.IsNotExist(err) || s.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
envFromFile, err := dotenv.GetEnvFromFile(composegoutils.GetAsEqualsMap(os.Environ()), []string{defaultDotEnv})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,8 @@ func TestEnvPriority(t *testing.T) {
|
|||||||
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
|
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
|
||||||
cmd.Env = append(cmd.Env, "COMPOSE_ENV_FILES=./fixtures/environment/env-priority/.env.override.with.default")
|
cmd.Env = append(cmd.Env, "COMPOSE_ENV_FILES=./fixtures/environment/env-priority/.env.override.with.default")
|
||||||
res := icmd.RunCmd(cmd)
|
res := icmd.RunCmd(cmd)
|
||||||
assert.Equal(t, strings.TrimSpace(res.Stdout()), "EnvFileDefaultValue")
|
stdout := res.Stdout()
|
||||||
|
assert.Equal(t, strings.TrimSpace(stdout), "EnvFileDefaultValue")
|
||||||
})
|
})
|
||||||
|
|
||||||
// No Compose file and env variable pass to the run command
|
// No Compose file and env variable pass to the run command
|
||||||
|
@ -329,3 +329,24 @@ func TestResolveDotEnv(t *testing.T) {
|
|||||||
Out: "image: backend:latest",
|
Out: "image: backend:latest",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNestedDotEnv(t *testing.T) {
|
||||||
|
c := NewCLI(t)
|
||||||
|
|
||||||
|
cmd := c.NewDockerComposeCmd(t, "run", "echo")
|
||||||
|
cmd.Dir = filepath.Join(".", "fixtures", "nested")
|
||||||
|
res := icmd.RunCmd(cmd)
|
||||||
|
res.Assert(t, icmd.Expected{
|
||||||
|
ExitCode: 0,
|
||||||
|
Out: "root win=root",
|
||||||
|
})
|
||||||
|
|
||||||
|
cmd = c.NewDockerComposeCmd(t, "run", "echo")
|
||||||
|
cmd.Dir = filepath.Join(".", "fixtures", "nested", "sub")
|
||||||
|
res = icmd.RunCmd(cmd)
|
||||||
|
res.Assert(t, icmd.Expected{
|
||||||
|
ExitCode: 0,
|
||||||
|
Out: "root sub win=sub",
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
services:
|
services:
|
||||||
env-compose-priority:
|
env-compose-priority:
|
||||||
image: env-compose-priority
|
image: env-compose-priority
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
2
pkg/e2e/fixtures/nested/.env
Normal file
2
pkg/e2e/fixtures/nested/.env
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ROOT=root
|
||||||
|
WIN=root
|
4
pkg/e2e/fixtures/nested/compose.yaml
Normal file
4
pkg/e2e/fixtures/nested/compose.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
services:
|
||||||
|
echo:
|
||||||
|
image: alpine
|
||||||
|
command: echo $ROOT $SUB win=$WIN
|
2
pkg/e2e/fixtures/nested/sub/.env
Normal file
2
pkg/e2e/fixtures/nested/sub/.env
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
SUB=sub
|
||||||
|
WIN=sub
|
Loading…
x
Reference in New Issue
Block a user