Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions compose/cli/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@

def project_from_options(project_dir, options):
override_dir = options.get('--project-directory')
environment = Environment.from_env_file(override_dir or project_dir)
environment_file = options.get('--env-file')
environment = Environment.from_env_file(override_dir or project_dir, environment_file)
environment.silent = options.get('COMMAND', None) in SILENT_COMMANDS
set_parallel_limit(environment)

Expand Down Expand Up @@ -77,7 +78,8 @@ def set_parallel_limit(environment):

def get_config_from_options(base_dir, options):
override_dir = options.get('--project-directory')
environment = Environment.from_env_file(override_dir or base_dir)
environment_file = options.get('--env-file')
environment = Environment.from_env_file(override_dir or base_dir, environment_file)
config_path = get_config_path_from_options(
base_dir, options, environment
)
Expand Down
19 changes: 14 additions & 5 deletions compose/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ class TopLevelCommand(object):
(default: the path of the Compose file)
--compatibility If set, Compose will attempt to convert keys
in v3 files to their non-Swarm equivalent
--env-file PATH Specify an alternate environment file

Commands:
build Build or rebuild services
Expand Down Expand Up @@ -274,7 +275,8 @@ def build(self, options):
'--build-arg is only supported when services are specified for API version < 1.25.'
' Please use a Compose file version > 2.2 or specify which services to build.'
)
environment = Environment.from_env_file(self.project_dir)
environment_file = options.get('--env-file')
environment = Environment.from_env_file(self.project_dir, environment_file)
build_args = resolve_build_args(build_args, environment)

self.project.build(
Expand Down Expand Up @@ -423,8 +425,10 @@ def down(self, options):
Compose file
-t, --timeout TIMEOUT Specify a shutdown timeout in seconds.
(default: 10)
--env-file PATH Specify an alternate environment file
"""
environment = Environment.from_env_file(self.project_dir)
environment_file = options.get('--env-file')
environment = Environment.from_env_file(self.project_dir, environment_file)
ignore_orphans = environment.get_boolean('COMPOSE_IGNORE_ORPHANS')

if ignore_orphans and options['--remove-orphans']:
Expand Down Expand Up @@ -481,8 +485,10 @@ def exec_command(self, options):
-e, --env KEY=VAL Set environment variables (can be used multiple times,
not supported in API < 1.25)
-w, --workdir DIR Path to workdir directory for this command.
--env-file PATH Specify an alternate environment file
"""
environment = Environment.from_env_file(self.project_dir)
environment_file = options.get('--env-file')
environment = Environment.from_env_file(self.project_dir, environment_file)
use_cli = not environment.get_boolean('COMPOSE_INTERACTIVE_NO_CLI')
index = int(options.get('--index'))
service = self.project.get_service(options['SERVICE'])
Expand Down Expand Up @@ -1038,6 +1044,7 @@ def up(self, options):
container. Implies --abort-on-container-exit.
--scale SERVICE=NUM Scale SERVICE to NUM instances. Overrides the
`scale` setting in the Compose file if present.
--env-file PATH Specify an alternate environment file
"""
start_deps = not options['--no-deps']
always_recreate_deps = options['--always-recreate-deps']
Expand All @@ -1052,7 +1059,8 @@ def up(self, options):
if detached and (cascade_stop or exit_value_from):
raise UserError("--abort-on-container-exit and -d cannot be combined.")

environment = Environment.from_env_file(self.project_dir)
environment_file = options.get('--env-file')
environment = Environment.from_env_file(self.project_dir, environment_file)
ignore_orphans = environment.get_boolean('COMPOSE_IGNORE_ORPHANS')

if ignore_orphans and remove_orphans:
Expand Down Expand Up @@ -1345,7 +1353,8 @@ def remove_container(force=False):
if options['--rm']:
project.client.remove_container(container.id, force=True, v=True)

environment = Environment.from_env_file(project_dir)
environment_file = options.get('--env-file')
environment = Environment.from_env_file(project_dir, environment_file)
use_cli = not environment.get_boolean('COMPOSE_INTERACTIVE_NO_CLI')

signals.set_signal_handler_to_shutdown()
Expand Down
7 changes: 5 additions & 2 deletions compose/config/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,15 @@ def __init__(self, *args, **kwargs):
self.silent = False

@classmethod
def from_env_file(cls, base_dir):
def from_env_file(cls, base_dir, env_file=None):
def _initialize():
result = cls()
if base_dir is None:
return result
env_file_path = os.path.join(base_dir, '.env')
if env_file:
env_file_path = os.path.join(base_dir, env_file)
else:
env_file_path = os.path.join(base_dir, '.env')
try:
return cls(env_vars_from_file(env_file_path))
except EnvFileNotFound:
Expand Down
15 changes: 15 additions & 0 deletions tests/acceptance/cli_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,21 @@ def test_config_with_dot_env(self):
'version': '2.4'
}

def test_config_with_env_file(self):
self.base_dir = 'tests/fixtures/default-env-file'
result = self.dispatch(['--env-file', '.env2', 'config'])
json_result = yaml.load(result.stdout)
assert json_result == {
'services': {
'web': {
'command': 'false',
'image': 'alpine:latest',
'ports': ['5644/tcp', '9998/tcp']
}
},
'version': '2.4'
}

def test_config_with_dot_env_and_override_dir(self):
self.base_dir = 'tests/fixtures/default-env-file'
result = self.dispatch(['--project-directory', 'alt/', 'config'])
Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/default-env-file/.env2
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
IMAGE=alpine:latest
COMMAND=false
PORT1=5644
PORT2=9998
19 changes: 19 additions & 0 deletions tests/unit/config/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3465,6 +3465,25 @@ def test_config_file_with_environment_file(self):
'command': 'true'
}

@mock.patch.dict(os.environ)
def test_config_file_with_options_environment_file(self):
project_dir = 'tests/fixtures/default-env-file'
service_dicts = config.load(
config.find(
project_dir, None, Environment.from_env_file(project_dir, '.env2')
)
).services

assert service_dicts[0] == {
'name': 'web',
'image': 'alpine:latest',
'ports': [
types.ServicePort.parse('5644')[0],
types.ServicePort.parse('9998')[0]
],
'command': 'false'
}

@mock.patch.dict(os.environ)
def test_config_file_with_environment_variable(self):
project_dir = 'tests/fixtures/environment-interpolation'
Expand Down