Selaa lähdekoodia

Merge pull request #5833 from docker/5826-load_retry_utf8

On load error, retry reading the file with UTF-8 encoding
Joffrey F 7 vuotta sitten
vanhempi
sitoutus
8d96980ba4
2 muutettua tiedostoa jossa 25 lisäystä ja 3 poistoa
  1. 9 3
      compose/config/config.py
  2. 16 0
      tests/unit/config/config_test.py

+ 9 - 3
compose/config/config.py

@@ -2,6 +2,7 @@ from __future__ import absolute_import
 from __future__ import unicode_literals
 
 import functools
+import io
 import logging
 import os
 import string
@@ -1431,10 +1432,15 @@ def has_uppercase(name):
     return any(char in string.ascii_uppercase for char in name)
 
 
-def load_yaml(filename):
+def load_yaml(filename, encoding=None):
     try:
-        with open(filename, 'r') as fh:
+        with io.open(filename, 'r', encoding=encoding) as fh:
             return yaml.safe_load(fh)
-    except (IOError, yaml.YAMLError) as e:
+    except (IOError, yaml.YAMLError, UnicodeDecodeError) as e:
+        if encoding is None:
+            # Sometimes the user's locale sets an encoding that doesn't match
+            # the YAML files. Im such cases, retry once with the "default"
+            # UTF-8 encoding
+            return load_yaml(filename, encoding='utf-8')
         error_name = getattr(e, '__module__', '') + '.' + e.__class__.__name__
         raise ConfigurationError(u"{}: {}".format(error_name, e))

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

@@ -3,6 +3,7 @@ from __future__ import absolute_import
 from __future__ import print_function
 from __future__ import unicode_literals
 
+import codecs
 import os
 import shutil
 import tempfile
@@ -1623,6 +1624,21 @@ class ConfigTest(unittest.TestCase):
 
         assert 'line 3, column 32' in exc.exconly()
 
+    def test_load_yaml_with_bom(self):
+        tmpdir = py.test.ensuretemp('bom_yaml')
+        self.addCleanup(tmpdir.remove)
+        bom_yaml = tmpdir.join('docker-compose.yml')
+        with codecs.open(str(bom_yaml), 'w', encoding='utf-8') as f:
+            f.write('''\ufeff
+                version: '2.3'
+                volumes:
+                    park_bom:
+            ''')
+        assert config.load_yaml(str(bom_yaml)) == {
+            'version': '2.3',
+            'volumes': {'park_bom': None}
+        }
+
     def test_validate_extra_hosts_invalid(self):
         with pytest.raises(ConfigurationError) as exc:
             config.load(build_config_details({