Browse Source

Added additional argument (--env-file) for docker-compose to import environment variables from a given PATH.

Signed-off-by: Dimitrios Mavrommatis <[email protected]>
slowr 6 năm trước cách đây
mục cha
commit
b09d8802ed

+ 4 - 2
compose/cli/command.py

@@ -39,7 +39,8 @@ SILENT_COMMANDS = set((
 
 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)
 
@@ -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
     )

+ 14 - 5
compose/cli/main.py

@@ -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
@@ -274,7 +275,8 @@ class TopLevelCommand(object):
                     '--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(
@@ -423,8 +425,10 @@ class TopLevelCommand(object):
                                     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']:
@@ -481,8 +485,10 @@ class TopLevelCommand(object):
             -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'])
@@ -1038,6 +1044,7 @@ class TopLevelCommand(object):
                                        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']
@@ -1052,7 +1059,8 @@ class TopLevelCommand(object):
         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:
@@ -1345,7 +1353,8 @@ def run_one_off_container(container_options, project, service, options, toplevel
         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()

+ 5 - 2
compose/config/environment.py

@@ -59,12 +59,15 @@ class Environment(dict):
         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:

+ 15 - 0
tests/acceptance/cli_test.py

@@ -324,6 +324,21 @@ class CLITestCase(DockerClientTestCase):
             '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'])

+ 4 - 0
tests/fixtures/default-env-file/.env2

@@ -0,0 +1,4 @@
+IMAGE=alpine:latest
+COMMAND=false
+PORT1=5644
+PORT2=9998

+ 19 - 0
tests/unit/config/config_test.py

@@ -3465,6 +3465,25 @@ class InterpolationTest(unittest.TestCase):
             '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'