Skip to content

Commit a3b22bd

Browse files
committed
support mulitple env-files to be set
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent cb8843f commit a3b22bd

File tree

7 files changed

+75
-45
lines changed

7 files changed

+75
-45
lines changed

cli/options.go

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package cli
1818

1919
import (
20+
"bytes"
2021
"fmt"
2122
"io"
2223
"os"
@@ -39,7 +40,7 @@ type ProjectOptions struct {
3940
WorkingDir string
4041
ConfigPaths []string
4142
Environment map[string]string
42-
EnvFile string
43+
EnvFiles []string
4344
loadOptions []func(*loader.Options)
4445
}
4546

@@ -187,9 +188,15 @@ func WithOsEnv(o *ProjectOptions) error {
187188
}
188189

189190
// WithEnvFile set an alternate env file
191+
// deprecated - use WithEnvFiles
190192
func WithEnvFile(file string) ProjectOptionsFn {
193+
return WithEnvFiles(file)
194+
}
195+
196+
// WithEnvFiles set alternate env files
197+
func WithEnvFiles(file ...string) ProjectOptionsFn {
191198
return func(options *ProjectOptions) error {
192-
options.EnvFile = file
199+
options.EnvFiles = file
193200
return nil
194201
}
195202
}
@@ -200,7 +207,7 @@ func WithDotEnv(o *ProjectOptions) error {
200207
if err != nil {
201208
return err
202209
}
203-
envMap, err := GetEnvFromFile(o.Environment, wd, o.EnvFile)
210+
envMap, err := GetEnvFromFile(o.Environment, wd, o.EnvFiles)
204211
if err != nil {
205212
return err
206213
}
@@ -213,55 +220,48 @@ func WithDotEnv(o *ProjectOptions) error {
213220
return nil
214221
}
215222

216-
func GetEnvFromFile(currentEnv map[string]string, workingDir string, filename string) (map[string]string, error) {
223+
func GetEnvFromFile(currentEnv map[string]string, workingDir string, filenames []string) (map[string]string, error) {
217224
envMap := make(map[string]string)
218225

219-
dotEnvFile := filename
220-
if dotEnvFile == "" {
221-
dotEnvFile = filepath.Join(workingDir, ".env")
222-
}
223-
abs, err := filepath.Abs(dotEnvFile)
224-
if err != nil {
225-
return envMap, err
226+
dotEnvFiles := filenames
227+
if len(dotEnvFiles) == 0 {
228+
dotEnvFiles = append(dotEnvFiles, filepath.Join(workingDir, ".env"))
226229
}
227-
dotEnvFile = abs
228-
229-
s, err := os.Stat(dotEnvFile)
230-
if os.IsNotExist(err) {
231-
if filename != "" {
232-
return nil, errors.Errorf("Couldn't find env file: %s", filename)
230+
for _, dotEnvFile := range dotEnvFiles {
231+
abs, err := filepath.Abs(dotEnvFile)
232+
if err != nil {
233+
return envMap, err
233234
}
234-
return envMap, nil
235-
}
236-
if err != nil {
237-
return envMap, err
238-
}
235+
dotEnvFile = abs
239236

240-
if s.IsDir() {
241-
if filename == "" {
237+
b, err := os.ReadFile(dotEnvFile)
238+
if os.IsNotExist(err) {
239+
if len(filenames) > 0 {
240+
return nil, errors.Errorf("Couldn't read env file: %s", dotEnvFile)
241+
}
242242
return envMap, nil
243243
}
244-
return envMap, errors.Errorf("%s is a directory", dotEnvFile)
245-
}
246-
247-
file, err := os.Open(dotEnvFile)
248-
if err != nil {
249-
return envMap, errors.Wrapf(err, "failed to read %s", dotEnvFile)
250-
}
251-
defer file.Close()
244+
if err != nil {
245+
return envMap, err
246+
}
252247

253-
env, err := dotenv.ParseWithLookup(file, func(k string) (string, bool) {
254-
v, ok := currentEnv[k]
255-
if !ok {
256-
return "", false
248+
env, err := dotenv.ParseWithLookup(bytes.NewReader(b), func(k string) (string, bool) {
249+
v, ok := envMap[k]
250+
if ok {
251+
return v, true
252+
}
253+
v, ok = currentEnv[k]
254+
if !ok {
255+
return "", false
256+
}
257+
return v, true
258+
})
259+
if err != nil {
260+
return envMap, errors.Wrapf(err, "failed to read %s", dotEnvFile)
261+
}
262+
for k, v := range env {
263+
envMap[k] = v
257264
}
258-
return v, true
259-
})
260-
if err != nil {
261-
return envMap, errors.Wrapf(err, "failed to read %s", dotEnvFile)
262-
}
263-
for k, v := range env {
264-
envMap[k] = v
265265
}
266266

267267
return envMap, nil

cli/options_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,24 @@ func TestProjectWithDiscardEnvFile(t *testing.T) {
226226
assert.NilError(t, err)
227227
assert.Equal(t, *service.Environment["DEFAULT_PORT"], "8080")
228228
assert.Assert(t, service.EnvFile == nil)
229+
assert.Equal(t, service.Ports[0].Published, "8000")
230+
}
231+
232+
func TestProjectWithMultipleEnvFile(t *testing.T) {
233+
opts, err := NewProjectOptions([]string{
234+
"testdata/env-file/compose-with-env-files.yaml",
235+
}, WithDiscardEnvFile,
236+
WithEnvFiles("testdata/env-file/.env", "testdata/env-file/override.env"),
237+
WithDotEnv)
238+
239+
assert.NilError(t, err)
240+
p, err := ProjectFromOptions(opts)
241+
assert.NilError(t, err)
242+
service, err := p.GetService("simple")
243+
assert.NilError(t, err)
244+
assert.Equal(t, *service.Environment["DEFAULT_PORT"], "9090")
245+
assert.Assert(t, service.EnvFile == nil)
246+
assert.Equal(t, service.Ports[0].Published, "9000")
229247
}
230248

231249
func TestProjectNameFromWorkingDir(t *testing.T) {

cli/testdata/env-file/.env

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
COMPOSE_FILE=compose-with-env-file.yaml
2-
COMPOSE_PROJECT_NAME=my_project_from_dot_env
2+
COMPOSE_PROJECT_NAME=my_project_from_dot_env
3+
PORT=8000
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: "3"
2+
services:
3+
simple:
4+
image: nginx
5+
env_file:
6+
- ./simple-env
7+
- ./second-env
8+
ports:
9+
- ${PORT}:80

cli/testdata/env-file/override.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PORT=9000

cli/testdata/env-file/second-env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DEFAULT_PORT=9090

cli/testdata/env-file/simple-env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
DEFAULT_PORT=8080
1+
DEFAULT_PORT=8080

0 commit comments

Comments
 (0)