Explorar o código

Merge pull request #5807 from docker/bump-1.20.0

Bump 1.20.0
Joffrey F %!s(int64=7) %!d(string=hai) anos
pai
achega
de00770d60

+ 1 - 1
.circleci/config.yml

@@ -10,7 +10,7 @@ jobs:
         command: brew update > /dev/null && brew upgrade python
     - run:
         name: install tox
-        command: sudo pip install --upgrade tox==2.1.1
+        command: sudo pip3 install --upgrade tox==2.1.1
     - run:
         name: unit tests
         command: tox -e py27,py36 -- tests/unit

+ 2 - 0
CHANGELOG.md

@@ -86,6 +86,8 @@ Change log
 - Fixed a bug occurring during builds caused by files with a negative `mtime`
   values in the build context
 
+- Fixed an encoding bug when streaming build progress
+
 1.19.0 (2018-02-07)
 -------------------
 

+ 1 - 1
compose/__init__.py

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

+ 20 - 12
compose/progress_stream.py

@@ -8,6 +8,14 @@ class StreamOutputError(Exception):
     pass
 
 
+def write_to_stream(s, stream):
+    try:
+        stream.write(s)
+    except UnicodeEncodeError:
+        encoding = getattr(stream, 'encoding', 'ascii')
+        stream.write(s.encode(encoding, errors='replace').decode(encoding))
+
+
 def stream_output(output, stream):
     is_terminal = hasattr(stream, 'isatty') and stream.isatty()
     stream = utils.get_output_stream(stream)
@@ -34,18 +42,18 @@ def stream_output(output, stream):
 
         if image_id not in lines:
             lines[image_id] = len(lines)
-            stream.write("\n")
+            write_to_stream("\n", stream)
 
         diff = len(lines) - lines[image_id]
 
         # move cursor up `diff` rows
-        stream.write("%c[%dA" % (27, diff))
+        write_to_stream("%c[%dA" % (27, diff), stream)
 
         print_output_event(event, stream, is_terminal)
 
         if 'id' in event:
             # move cursor back down
-            stream.write("%c[%dB" % (27, diff))
+            write_to_stream("%c[%dB" % (27, diff), stream)
 
         stream.flush()
 
@@ -60,36 +68,36 @@ def print_output_event(event, stream, is_terminal):
 
     if is_terminal and 'stream' not in event:
         # erase current line
-        stream.write("%c[2K\r" % 27)
+        write_to_stream("%c[2K\r" % 27, stream)
         terminator = "\r"
     elif 'progressDetail' in event:
         return
 
     if 'time' in event:
-        stream.write("[%s] " % event['time'])
+        write_to_stream("[%s] " % event['time'], stream)
 
     if 'id' in event:
-        stream.write("%s: " % event['id'])
+        write_to_stream("%s: " % event['id'], stream)
 
     if 'from' in event:
-        stream.write("(from %s) " % event['from'])
+        write_to_stream("(from %s) " % event['from'], stream)
 
     status = event.get('status', '')
 
     if 'progress' in event:
-        stream.write("%s %s%s" % (status, event['progress'], terminator))
+        write_to_stream("%s %s%s" % (status, event['progress'], terminator), stream)
     elif 'progressDetail' in event:
         detail = event['progressDetail']
         total = detail.get('total')
         if 'current' in detail and total:
             percentage = float(detail['current']) / float(total) * 100
-            stream.write('%s (%.1f%%)%s' % (status, percentage, terminator))
+            write_to_stream('%s (%.1f%%)%s' % (status, percentage, terminator), stream)
         else:
-            stream.write('%s%s' % (status, terminator))
+            write_to_stream('%s%s' % (status, terminator), stream)
     elif 'stream' in event:
-        stream.write("%s%s" % (event['stream'], terminator))
+        write_to_stream("%s%s" % (event['stream'], terminator), stream)
     else:
-        stream.write("%s%s\n" % (status, terminator))
+        write_to_stream("%s%s\n" % (status, terminator), stream)
 
 
 def get_digest_from_pull(events):

+ 1 - 1
requirements.txt

@@ -2,7 +2,7 @@ backports.ssl-match-hostname==3.5.0.1; python_version < '3'
 cached-property==1.3.0
 certifi==2017.4.17
 chardet==3.0.4
-docker==3.1.1
+docker==3.1.3
 docker-pycreds==0.2.1
 dockerpty==0.4.1
 docopt==0.6.2

+ 1 - 1
script/run/run.sh

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

+ 1 - 1
setup.py

@@ -36,7 +36,7 @@ install_requires = [
     'requests >= 2.6.1, != 2.11.0, != 2.12.2, != 2.18.0, < 2.19',
     'texttable >= 0.9.0, < 0.10',
     'websocket-client >= 0.32.0, < 1.0',
-    'docker >= 3.1.1, < 4.0',
+    'docker >= 3.1.3, < 4.0',
     'dockerpty >= 0.4.1, < 0.5',
     'six >= 1.3.0, < 2',
     'jsonschema >= 2.5.1, < 3',

+ 31 - 0
tests/unit/progress_stream_test.py

@@ -1,6 +1,13 @@
+# ~*~ encoding: utf-8 ~*~
 from __future__ import absolute_import
 from __future__ import unicode_literals
 
+import io
+import os
+import random
+import shutil
+import tempfile
+
 from six import StringIO
 
 from compose import progress_stream
@@ -66,6 +73,30 @@ class ProgressStreamTestCase(unittest.TestCase):
         events = progress_stream.stream_output(events, output)
         assert len(output.getvalue()) > 0
 
+    def test_mismatched_encoding_stream_write(self):
+        tmpdir = tempfile.mkdtemp()
+        self.addCleanup(shutil.rmtree, tmpdir, True)
+
+        def mktempfile(encoding):
+            fname = os.path.join(tmpdir, hex(random.getrandbits(128))[2:-1])
+            return io.open(fname, mode='w+', encoding=encoding)
+
+        text = '就吃饭'
+        with mktempfile(encoding='utf-8') as tf:
+            progress_stream.write_to_stream(text, tf)
+            tf.seek(0)
+            assert tf.read() == text
+
+        with mktempfile(encoding='utf-32') as tf:
+            progress_stream.write_to_stream(text, tf)
+            tf.seek(0)
+            assert tf.read() == text
+
+        with mktempfile(encoding='ascii') as tf:
+            progress_stream.write_to_stream(text, tf)
+            tf.seek(0)
+            assert tf.read() == '???'
+
 
 def test_get_digest_from_push():
     digest = "sha256:abcd"