From e0edc908b5a5ef244dff6caa64c44ba3078b4a9e Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Wed, 2 Dec 2020 09:34:28 -0300 Subject: [PATCH] Fix project_dir to take first file in account The order of precedence is: - '--project-directory' option - first file directory in '--file' option - current directory Signed-off-by: Ulysses Souza --- compose/cli/command.py | 22 +++++++++++++++------- compose/cli/main.py | 18 ++++++++++-------- tests/unit/cli/command_test.py | 22 +++++++--------------- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/compose/cli/command.py b/compose/cli/command.py index ee991309a..599df9969 100644 --- a/compose/cli/command.py +++ b/compose/cli/command.py @@ -35,7 +35,7 @@ SILENT_COMMANDS = { def project_from_options(project_dir, options, additional_options=None): additional_options = additional_options or {} - override_dir = options.get('--project-directory') + override_dir = get_project_dir(options) 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 @@ -59,7 +59,7 @@ def project_from_options(project_dir, options, additional_options=None): return get_project( project_dir, - get_config_path_from_options(project_dir, options, environment), + get_config_path_from_options(options, environment), project_name=options.get('--project-name'), verbose=options.get('--verbose'), context=context, @@ -87,21 +87,29 @@ def set_parallel_limit(environment): parallel.GlobalLimit.set_global_limit(parallel_limit) +def get_project_dir(options): + override_dir = None + files = get_config_path_from_options(options, os.environ) + if files: + if files[0] == '-': + return '.' + override_dir = os.path.dirname(files[0]) + return options.get('--project-directory') or override_dir + + def get_config_from_options(base_dir, options, additional_options=None): additional_options = additional_options or {} - override_dir = options.get('--project-directory') + override_dir = get_project_dir(options) 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 - ) + config_path = get_config_path_from_options(options, environment) return config.load( config.find(base_dir, config_path, environment, override_dir), not additional_options.get('--no-interpolate') ) -def get_config_path_from_options(base_dir, options, environment): +def get_config_path_from_options(options, environment): def unicode_paths(paths): return [p.decode('utf-8') if isinstance(p, bytes) else p for p in paths] diff --git a/compose/cli/main.py b/compose/cli/main.py index 55b8ccadc..9b2a5d0b0 100644 --- a/compose/cli/main.py +++ b/compose/cli/main.py @@ -39,6 +39,7 @@ from ..service import ImageType from ..service import NeedsBuildError from ..service import OperationFailedError from .command import get_config_from_options +from .command import get_project_dir from .command import project_from_options from .docopt_command import DocoptDispatcher from .docopt_command import get_handler @@ -245,7 +246,7 @@ class TopLevelCommand: @property def project_dir(self): - return self.toplevel_options.get('--project-directory') or '.' + return get_project_dir(self.toplevel_options) @property def toplevel_environment(self): @@ -431,6 +432,7 @@ class TopLevelCommand: Options: --json Output events as a stream of json objects """ + def format_event(event): attributes = ["%s=%s" % item for item in event['attributes'].items()] return ("{time} {type} {action} {id} ({attrs})").format( @@ -1382,13 +1384,13 @@ def get_docker_start_call(container_options, container_id): def log_printer_from_project( - project, - containers, - monochrome, - log_args, - cascade_stop=False, - event_stream=None, - keep_prefix=True, + project, + containers, + monochrome, + log_args, + cascade_stop=False, + event_stream=None, + keep_prefix=True, ): return LogPrinter( containers, diff --git a/tests/unit/cli/command_test.py b/tests/unit/cli/command_test.py index 9d4db5b59..60638864c 100644 --- a/tests/unit/cli/command_test.py +++ b/tests/unit/cli/command_test.py @@ -14,49 +14,41 @@ class TestGetConfigPathFromOptions: paths = ['one.yml', 'two.yml'] opts = {'--file': paths} environment = Environment.from_env_file('.') - assert get_config_path_from_options('.', opts, environment) == paths + assert get_config_path_from_options(opts, environment) == paths def test_single_path_from_env(self): with mock.patch.dict(os.environ): os.environ['COMPOSE_FILE'] = 'one.yml' environment = Environment.from_env_file('.') - assert get_config_path_from_options('.', {}, environment) == ['one.yml'] + assert get_config_path_from_options({}, environment) == ['one.yml'] @pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='posix separator') def test_multiple_path_from_env(self): with mock.patch.dict(os.environ): os.environ['COMPOSE_FILE'] = 'one.yml:two.yml' environment = Environment.from_env_file('.') - assert get_config_path_from_options( - '.', {}, environment - ) == ['one.yml', 'two.yml'] + assert get_config_path_from_options({}, environment) == ['one.yml', 'two.yml'] @pytest.mark.skipif(not IS_WINDOWS_PLATFORM, reason='windows separator') def test_multiple_path_from_env_windows(self): with mock.patch.dict(os.environ): os.environ['COMPOSE_FILE'] = 'one.yml;two.yml' environment = Environment.from_env_file('.') - assert get_config_path_from_options( - '.', {}, environment - ) == ['one.yml', 'two.yml'] + assert get_config_path_from_options({}, environment) == ['one.yml', 'two.yml'] def test_multiple_path_from_env_custom_separator(self): with mock.patch.dict(os.environ): os.environ['COMPOSE_PATH_SEPARATOR'] = '^' os.environ['COMPOSE_FILE'] = 'c:\\one.yml^.\\semi;colon.yml' environment = Environment.from_env_file('.') - assert get_config_path_from_options( - '.', {}, environment - ) == ['c:\\one.yml', '.\\semi;colon.yml'] + assert get_config_path_from_options({}, environment) == ['c:\\one.yml', '.\\semi;colon.yml'] def test_no_path(self): environment = Environment.from_env_file('.') - assert not get_config_path_from_options('.', {}, environment) + assert not get_config_path_from_options({}, environment) def test_unicode_path_from_options(self): paths = [b'\xe5\xb0\xb1\xe5\x90\x83\xe9\xa5\xad/docker-compose.yml'] opts = {'--file': paths} environment = Environment.from_env_file('.') - assert get_config_path_from_options( - '.', opts, environment - ) == ['就吃饭/docker-compose.yml'] + assert get_config_path_from_options(opts, environment) == ['就吃饭/docker-compose.yml']