Merge branch 'master' into 1.28.x

This commit is contained in:
Anca Iordache 2021-03-23 11:30:04 +01:00
commit b79b2a24ac
12 changed files with 85 additions and 20 deletions

View File

@ -23,6 +23,7 @@ from ..config import resolve_build_args
from ..config.environment import Environment
from ..config.serialize import serialize_config
from ..config.types import VolumeSpec
from ..const import IS_LINUX_PLATFORM
from ..const import IS_WINDOWS_PLATFORM
from ..errors import StreamParseError
from ..metrics.decorator import metrics
@ -78,6 +79,8 @@ def main(): # noqa: C901
try:
command_func = dispatch()
command_func()
if not IS_LINUX_PLATFORM and command == 'help':
print("\nDocker Compose is now in the Docker CLI, try `docker compose` help")
except (KeyboardInterrupt, signals.ShutdownException):
exit_with_metrics(command, "Aborting.", status=Status.FAILURE)
except (UserError, NoSuchService, ConfigurationError,
@ -98,6 +101,8 @@ def main(): # noqa: C901
e.service.name), status=Status.FAILURE)
except NoSuchCommand as e:
commands = "\n".join(parse_doc_section("commands:", getdoc(e.supercommand)))
if not IS_LINUX_PLATFORM:
commands += "\n\nDocker Compose is now in the Docker CLI, try `docker compose`"
exit_with_metrics(e.command, "No such command: {}\n\n{}".format(e.command, commands))
except (errors.ConnectionError, StreamParseError):
exit_with_metrics(command, status=Status.FAILURE)
@ -116,6 +121,10 @@ def main(): # noqa: C901
code = 0
if isinstance(e.code, int):
code = e.code
if not IS_LINUX_PLATFORM and not command:
msg += "\n\nDocker Compose is now in the Docker CLI, try `docker compose`"
exit_with_metrics(command, log_msg=msg, status=status,
exit_code=code)
@ -128,7 +137,7 @@ def get_filtered_args(args):
def exit_with_metrics(command, log_msg=None, status=Status.SUCCESS, exit_code=1):
if log_msg:
if log_msg and command != 'exec':
if not exit_code:
log.info(log_msg)
else:
@ -1123,6 +1132,9 @@ class TopLevelCommand:
attach_dependencies = options.get('--attach-dependencies')
keep_prefix = not options.get('--no-log-prefix')
if not IS_LINUX_PLATFORM:
print('Docker Compose is now in the Docker CLI, try `docker compose up`\n')
if detached and (cascade_stop or exit_value_from or attach_dependencies):
raise UserError(
"-d cannot be combined with --abort-on-container-exit or --attach-dependencies.")

View File

@ -335,7 +335,6 @@
"read_only": {"type": "boolean"},
"restart": {"type": "string"},
"runtime": {
"deprecated": true,
"type": "string"
},
"scale": {
@ -367,6 +366,7 @@
"stdin_open": {"type": "boolean"},
"stop_grace_period": {"type": "string", "format": "duration"},
"stop_signal": {"type": "string"},
"storage_opt": {"type": "object"},
"tmpfs": {"$ref": "#/definitions/string_or_list"},
"tty": {"type": "boolean"},
"ulimits": {

View File

@ -10,7 +10,11 @@ from operator import attrgetter
from operator import itemgetter
import yaml
from cached_property import cached_property
try:
from functools import cached_property
except ImportError:
from cached_property import cached_property
from . import types
from ..const import COMPOSE_SPEC as VERSION
@ -149,9 +153,14 @@ DOCKER_VALID_URL_PREFIXES = (
SUPPORTED_FILENAMES = [
'docker-compose.yml',
'docker-compose.yaml',
'compose.yml',
'compose.yaml',
]
DEFAULT_OVERRIDE_FILENAMES = ('docker-compose.override.yml', 'docker-compose.override.yaml')
DEFAULT_OVERRIDE_FILENAMES = ('docker-compose.override.yml',
'docker-compose.override.yaml',
'compose.override.yml',
'compose.override.yaml')
log = logging.getLogger(__name__)
@ -304,7 +313,16 @@ def find(base_dir, filenames, environment, override_dir=None):
if filenames:
filenames = [os.path.join(base_dir, f) for f in filenames]
else:
# search for compose files in the base dir and its parents
filenames = get_default_config_files(base_dir)
if not filenames and not override_dir:
# none found in base_dir and no override_dir defined
raise ComposeFileNotFound(SUPPORTED_FILENAMES)
if not filenames:
# search for compose files in the project directory and its parents
filenames = get_default_config_files(override_dir)
if not filenames:
raise ComposeFileNotFound(SUPPORTED_FILENAMES)
log.debug("Using configuration files: {}".format(",".join(filenames)))
return ConfigDetails(
@ -335,7 +353,7 @@ def get_default_config_files(base_dir):
(candidates, path) = find_candidates_in_parent_dirs(SUPPORTED_FILENAMES, base_dir)
if not candidates:
raise ComposeFileNotFound(SUPPORTED_FILENAMES)
return None
winner = candidates[0]
@ -556,8 +574,7 @@ def process_config_section(config_file, config, section, environment, interpolat
config_file.version,
config,
section,
environment
)
environment)
else:
return config

View File

@ -54,9 +54,10 @@ class Environment(dict):
if base_dir is None:
return result
if env_file:
env_file_path = os.path.join(base_dir, env_file)
else:
env_file_path = os.path.join(base_dir, '.env')
env_file_path = os.path.join(os.getcwd(), env_file)
return cls(env_vars_from_file(env_file_path))
env_file_path = os.path.join(base_dir, '.env')
try:
return cls(env_vars_from_file(env_file_path))
except EnvFileNotFound:

View File

@ -5,6 +5,7 @@ from .version import ComposeVersion
DEFAULT_TIMEOUT = 10
HTTP_TIMEOUT = 60
IS_WINDOWS_PLATFORM = (sys.platform == "win32")
IS_LINUX_PLATFORM = (sys.platform == "linux")
LABEL_CONTAINER_NUMBER = 'com.docker.compose.container-number'
LABEL_ONE_OFF = 'com.docker.compose.oneoff'
LABEL_PROJECT = 'com.docker.compose.project'

View File

@ -1855,7 +1855,7 @@ class _CLIBuilder:
Returns:
A generator for the build output.
"""
if dockerfile:
if dockerfile and os.path.isdir(path):
dockerfile = os.path.join(path, dockerfile)
iidfile = tempfile.mktemp()
@ -1877,8 +1877,10 @@ class _CLIBuilder:
command_builder.add_arg("--isolation", isolation)
if extra_hosts:
for host, ip in extra_hosts.items():
command_builder.add_arg("--add-host", "{}:{}".format(host, ip))
if isinstance(extra_hosts, dict):
extra_hosts = ["{}:{}".format(host, ip) for host, ip in extra_hosts.items()]
for host in extra_hosts:
command_builder.add_arg("--add-host", "{}".format(host))
args = command_builder.build([path])

View File

@ -1,5 +1,5 @@
backports.shutil_get_terminal_size==1.0.0
cached-property==1.5.1
cached-property==1.5.1; python_version < '3.8'
certifi==2020.6.20
chardet==3.0.4
colorama==0.4.3; sys_platform == 'win32'

View File

@ -25,7 +25,6 @@ def find_version(*file_paths):
install_requires = [
'cached-property >= 1.2.0, < 2',
'docopt >= 0.6.1, < 1',
'PyYAML >= 3.10, < 6',
'requests >= 2.20.0, < 3',
@ -50,6 +49,7 @@ if sys.version_info[:2] < (3, 4):
extras_require = {
':python_version < "3.5"': ['backports.ssl_match_hostname >= 3.5, < 4'],
':python_version < "3.8"': ['cached-property >= 1.2.0, < 2'],
':sys_platform == "win32"': ['colorama >= 0.4, < 1'],
'socks': ['PySocks >= 1.5.6, != 1.5.7, < 2'],
'tests': tests_require,

1
tests/fixtures/env-file-override/.env vendored Normal file
View File

@ -0,0 +1 @@
WHEREAMI=default

View File

@ -1,5 +1,6 @@
import tempfile
import pytest
from ddt import data
from ddt import ddt
@ -8,6 +9,7 @@ from ..acceptance.cli_test import dispatch
from compose.cli.command import get_project
from compose.cli.command import project_from_options
from compose.config.environment import Environment
from compose.config.errors import EnvFileNotFound
from tests.integration.testcases import DockerClientTestCase
@ -55,13 +57,36 @@ services:
class EnvironmentOverrideFileTest(DockerClientTestCase):
def test_env_file_override(self):
base_dir = 'tests/fixtures/env-file-override'
# '--env-file' are relative to the current working dir
env = Environment.from_env_file(base_dir, base_dir+'/.env.override')
dispatch(base_dir, ['--env-file', '.env.override', 'up'])
project = get_project(project_dir=base_dir,
config_path=['docker-compose.yml'],
environment=Environment.from_env_file(base_dir, '.env.override'),
environment=env,
override_dir=base_dir)
containers = project.containers(stopped=True)
assert len(containers) == 1
assert "WHEREAMI=override" in containers[0].get('Config.Env')
assert "DEFAULT_CONF_LOADED=true" in containers[0].get('Config.Env')
dispatch(base_dir, ['--env-file', '.env.override', 'down'], None)
def test_env_file_not_found_error(self):
base_dir = 'tests/fixtures/env-file-override'
with pytest.raises(EnvFileNotFound) as excinfo:
Environment.from_env_file(base_dir, '.env.override')
assert "Couldn't find env file" in excinfo.exconly()
def test_dot_env_file(self):
base_dir = 'tests/fixtures/env-file-override'
# '.env' is relative to the project_dir (base_dir)
env = Environment.from_env_file(base_dir, None)
dispatch(base_dir, ['up'])
project = get_project(project_dir=base_dir,
config_path=['docker-compose.yml'],
environment=env,
override_dir=base_dir)
containers = project.containers(stopped=True)
assert len(containers) == 1
assert "WHEREAMI=default" in containers[0].get('Config.Env')
dispatch(base_dir, ['down'], None)

View File

@ -3567,9 +3567,11 @@ class InterpolationTest(unittest.TestCase):
@mock.patch.dict(os.environ)
def test_config_file_with_options_environment_file(self):
project_dir = 'tests/fixtures/default-env-file'
# env-file is relative to current working dir
env = Environment.from_env_file(project_dir, project_dir + '/.env2')
service_dicts = config.load(
config.find(
project_dir, None, Environment.from_env_file(project_dir, '.env2')
project_dir, None, env
)
).services
@ -5233,6 +5235,8 @@ class GetDefaultConfigFilesTestCase(unittest.TestCase):
files = [
'docker-compose.yml',
'docker-compose.yaml',
'compose.yml',
'compose.yaml',
]
def test_get_config_path_default_file_in_basedir(self):
@ -5266,8 +5270,10 @@ def get_config_filename_for_files(filenames, subdir=None):
base_dir = tempfile.mkdtemp(dir=project_dir)
else:
base_dir = project_dir
filename, = config.get_default_config_files(base_dir)
return os.path.basename(filename)
filenames = config.get_default_config_files(base_dir)
if not filenames:
raise config.ComposeFileNotFound(config.SUPPORTED_FILENAMES)
return os.path.basename(filenames[0])
finally:
shutil.rmtree(project_dir)

View File

@ -50,7 +50,7 @@ directory = coverage-html
[flake8]
max-line-length = 105
# Set this high for now
max-complexity = 11
max-complexity = 12
exclude = compose/packages
[pytest]