فهرست منبع

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

Bump 1.18.0 rc2
Joffrey F 8 سال پیش
والد
کامیت
01cd2688bb
8فایلهای تغییر یافته به همراه70 افزوده شده و 16 حذف شده
  1. 3 1
      CHANGELOG.md
  2. 1 1
      compose/__init__.py
  3. 18 12
      compose/cli/errors.py
  4. 13 0
      compose/cli/utils.py
  5. 1 1
      compose/config/config.py
  6. 1 1
      script/run/run.sh
  7. 10 0
      tests/unit/cli/errors_test.py
  8. 23 0
      tests/unit/config/config_test.py

+ 3 - 1
CHANGELOG.md

@@ -42,7 +42,7 @@ Change log
 - Values interpolated from the environment will now be converted to the
   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`
 
@@ -71,6 +71,8 @@ Change log
 - Fixed a bug where missing secret files would generate an empty directory
   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 `subnet` field in IPAM configurations

+ 1 - 1
compose/__init__.py

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

+ 18 - 12
compose/cli/errors.py

@@ -7,7 +7,6 @@ import socket
 from distutils.spawn import find_executable
 from textwrap import dedent
 
-import six
 from docker.errors import APIError
 from requests.exceptions import ConnectionError as RequestsConnectionError
 from requests.exceptions import ReadTimeout
@@ -15,6 +14,7 @@ from requests.exceptions import SSLError
 from requests.packages.urllib3.exceptions import ReadTimeoutError
 
 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_mac
 from .utils import is_ubuntu
@@ -75,7 +75,9 @@ def log_windows_pipe_error(exc):
         )
     else:
         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):
-    explanation = e.explanation
-    if isinstance(explanation, six.binary_type):
-        explanation = explanation.decode('utf-8')
+    explanation = binarystr_to_unicode(e.explanation)
 
     if 'client is newer than server' not in explanation:
         log.error(explanation)
@@ -106,7 +106,8 @@ def log_api_error(e, client_version):
     log.error(
         "The Docker Engine version is less than the minimum required by "
         "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):
@@ -115,12 +116,17 @@ def exit_with_error(msg):
 
 
 def get_conn_error_message(url):
-    if find_executable('docker') is None:
-        return docker_not_found_msg("Couldn't connect to Docker daemon.")
-    if is_docker_for_mac_installed():
-        return conn_error_docker_for_mac
-    if find_executable('docker-machine') is not None:
-        return conn_error_docker_machine
+    try:
+        if find_executable('docker') is None:
+            return docker_not_found_msg("Couldn't connect to Docker daemon.")
+        if is_docker_for_mac_installed():
+            return conn_error_docker_for_mac
+        if find_executable('docker-machine') is not None:
+            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)
 
 

+ 13 - 0
compose/cli/utils.py

@@ -10,6 +10,7 @@ import subprocess
 import sys
 
 import docker
+import six
 
 import compose
 from ..const import IS_WINDOWS_PLATFORM
@@ -148,3 +149,15 @@ def human_readable_file_size(size):
         size / float(1 << (order * 10)),
         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')

+ 1 - 1
compose/config/config.py

@@ -1153,7 +1153,7 @@ def resolve_volume_paths(working_dir, service_dict):
 
 def resolve_volume_path(working_dir, volume):
     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'])
         return volume
 

+ 1 - 1
script/run/run.sh

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

+ 10 - 0
tests/unit/cli/errors_test.py

@@ -86,3 +86,13 @@ class TestHandleConnectionErrors(object):
 
         _, args, _ = mock_logging.error.mock_calls[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]

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

@@ -1304,6 +1304,29 @@ class ConfigTest(unittest.TestCase):
         assert npipe_mount.target == '/named_pipe'
         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):
         for valid_name in ['_', '-', '.__.', '_what-up.', 'what_.up----', 'whatup']:
             services = config.load(