Merge pull request #5460 from docker/bump-1.18.0-rc2

Bump 1.18.0 rc2
This commit is contained in:
Joffrey F 2017-12-08 16:13:08 -08:00 committed by GitHub
commit 01cd2688bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 70 additions and 16 deletions

View File

@ -42,7 +42,7 @@ Change log
- Values interpolated from the environment will now be converted to the - Values interpolated from the environment will now be converted to the
proper type when used in non-string fields. proper type when used in non-string fields.
- Added support for `--labels` in `docker-compose run` - Added support for `--label` in `docker-compose run`
- Added support for `--timeout` in `docker-compose down` - Added support for `--timeout` in `docker-compose down`
@ -71,6 +71,8 @@ Change log
- Fixed a bug where missing secret files would generate an empty directory - Fixed a bug where missing secret files would generate an empty directory
in their place in their place
- Fixed character encoding issues in the CLI's error handlers
- Added validation for the `test` field in healthchecks - Added validation for the `test` field in healthchecks
- Added validation for the `subnet` field in IPAM configurations - Added validation for the `subnet` field in IPAM configurations

View File

@ -1,4 +1,4 @@
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import unicode_literals from __future__ import unicode_literals
__version__ = '1.18.0-rc1' __version__ = '1.18.0-rc2'

View File

@ -7,7 +7,6 @@ import socket
from distutils.spawn import find_executable from distutils.spawn import find_executable
from textwrap import dedent from textwrap import dedent
import six
from docker.errors import APIError from docker.errors import APIError
from requests.exceptions import ConnectionError as RequestsConnectionError from requests.exceptions import ConnectionError as RequestsConnectionError
from requests.exceptions import ReadTimeout from requests.exceptions import ReadTimeout
@ -15,6 +14,7 @@ from requests.exceptions import SSLError
from requests.packages.urllib3.exceptions import ReadTimeoutError from requests.packages.urllib3.exceptions import ReadTimeoutError
from ..const import API_VERSION_TO_ENGINE_VERSION from ..const import API_VERSION_TO_ENGINE_VERSION
from .utils import binarystr_to_unicode
from .utils import is_docker_for_mac_installed from .utils import is_docker_for_mac_installed
from .utils import is_mac from .utils import is_mac
from .utils import is_ubuntu from .utils import is_ubuntu
@ -75,7 +75,9 @@ def log_windows_pipe_error(exc):
) )
else: else:
log.error( log.error(
"Windows named pipe error: {} (code: {})".format(exc.strerror, exc.winerror) "Windows named pipe error: {} (code: {})".format(
binarystr_to_unicode(exc.strerror), exc.winerror
)
) )
@ -89,9 +91,7 @@ def log_timeout_error(timeout):
def log_api_error(e, client_version): def log_api_error(e, client_version):
explanation = e.explanation explanation = binarystr_to_unicode(e.explanation)
if isinstance(explanation, six.binary_type):
explanation = explanation.decode('utf-8')
if 'client is newer than server' not in explanation: if 'client is newer than server' not in explanation:
log.error(explanation) log.error(explanation)
@ -106,7 +106,8 @@ def log_api_error(e, client_version):
log.error( log.error(
"The Docker Engine version is less than the minimum required by " "The Docker Engine version is less than the minimum required by "
"Compose. Your current project requires a Docker Engine of " "Compose. Your current project requires a Docker Engine of "
"version {version} or greater.".format(version=version)) "version {version} or greater.".format(version=version)
)
def exit_with_error(msg): def exit_with_error(msg):
@ -115,12 +116,17 @@ def exit_with_error(msg):
def get_conn_error_message(url): def get_conn_error_message(url):
try:
if find_executable('docker') is None: if find_executable('docker') is None:
return docker_not_found_msg("Couldn't connect to Docker daemon.") return docker_not_found_msg("Couldn't connect to Docker daemon.")
if is_docker_for_mac_installed(): if is_docker_for_mac_installed():
return conn_error_docker_for_mac return conn_error_docker_for_mac
if find_executable('docker-machine') is not None: if find_executable('docker-machine') is not None:
return conn_error_docker_machine return conn_error_docker_machine
except UnicodeDecodeError:
# https://github.com/docker/compose/issues/5442
# Ignore the error and print the generic message instead.
pass
return conn_error_generic.format(url=url) return conn_error_generic.format(url=url)

View File

@ -10,6 +10,7 @@ import subprocess
import sys import sys
import docker import docker
import six
import compose import compose
from ..const import IS_WINDOWS_PLATFORM from ..const import IS_WINDOWS_PLATFORM
@ -148,3 +149,15 @@ def human_readable_file_size(size):
size / float(1 << (order * 10)), size / float(1 << (order * 10)),
suffixes[order] suffixes[order]
) )
def binarystr_to_unicode(s):
if not isinstance(s, six.binary_type):
return s
if IS_WINDOWS_PLATFORM:
try:
return s.decode('windows-1250')
except UnicodeDecodeError:
pass
return s.decode('utf-8', 'replace')

View File

@ -1153,7 +1153,7 @@ def resolve_volume_paths(working_dir, service_dict):
def resolve_volume_path(working_dir, volume): def resolve_volume_path(working_dir, volume):
if isinstance(volume, dict): if isinstance(volume, dict):
if volume.get('source', '').startswith('.') and volume['type'] == 'mount': if volume.get('source', '').startswith('.') and volume['type'] == 'bind':
volume['source'] = expand_path(working_dir, volume['source']) volume['source'] = expand_path(working_dir, volume['source'])
return volume return volume

View File

@ -15,7 +15,7 @@
set -e set -e
VERSION="1.18.0-rc1" VERSION="1.18.0-rc2"
IMAGE="docker/compose:$VERSION" IMAGE="docker/compose:$VERSION"

View File

@ -86,3 +86,13 @@ class TestHandleConnectionErrors(object):
_, args, _ = mock_logging.error.mock_calls[0] _, args, _ = mock_logging.error.mock_calls[0]
assert "Windows named pipe error: The pipe is busy. (code: 231)" == args[0] assert "Windows named pipe error: The pipe is busy. (code: 231)" == args[0]
@pytest.mark.skipif(not IS_WINDOWS_PLATFORM, reason='Needs pywin32')
def test_windows_pipe_error_encoding_issue(self, mock_logging):
import pywintypes
with pytest.raises(errors.ConnectionError):
with handle_connection_errors(mock.Mock(api_version='1.22')):
raise pywintypes.error(9999, 'WriteFile', 'I use weird characters \xe9')
_, args, _ = mock_logging.error.mock_calls[0]
assert 'Windows named pipe error: I use weird characters \xe9 (code: 9999)' == args[0]

View File

@ -1304,6 +1304,29 @@ class ConfigTest(unittest.TestCase):
assert npipe_mount.target == '/named_pipe' assert npipe_mount.target == '/named_pipe'
assert not npipe_mount.is_named_volume assert not npipe_mount.is_named_volume
def test_load_bind_mount_relative_path(self):
expected_source = 'C:\\tmp\\web' if IS_WINDOWS_PLATFORM else '/tmp/web'
base_file = config.ConfigFile(
'base.yaml', {
'version': '3.4',
'services': {
'web': {
'image': 'busybox:latest',
'volumes': [
{'type': 'bind', 'source': './web', 'target': '/web'},
],
},
},
},
)
details = config.ConfigDetails('/tmp', [base_file])
config_data = config.load(details)
mount = config_data.services[0].get('volumes')[0]
assert mount.target == '/web'
assert mount.type == 'bind'
assert mount.source == expected_source
def test_config_valid_service_names(self): def test_config_valid_service_names(self):
for valid_name in ['_', '-', '.__.', '_what-up.', 'what_.up----', 'whatup']: for valid_name in ['_', '-', '.__.', '_what-up.', 'what_.up----', 'whatup']:
services = config.load( services = config.load(