mirror of https://github.com/docker/compose.git
commit
de00770d60
|
@ -10,7 +10,7 @@ jobs:
|
||||||
command: brew update > /dev/null && brew upgrade python
|
command: brew update > /dev/null && brew upgrade python
|
||||||
- run:
|
- run:
|
||||||
name: install tox
|
name: install tox
|
||||||
command: sudo pip install --upgrade tox==2.1.1
|
command: sudo pip3 install --upgrade tox==2.1.1
|
||||||
- run:
|
- run:
|
||||||
name: unit tests
|
name: unit tests
|
||||||
command: tox -e py27,py36 -- tests/unit
|
command: tox -e py27,py36 -- tests/unit
|
||||||
|
|
|
@ -86,6 +86,8 @@ Change log
|
||||||
- Fixed a bug occurring during builds caused by files with a negative `mtime`
|
- Fixed a bug occurring during builds caused by files with a negative `mtime`
|
||||||
values in the build context
|
values in the build context
|
||||||
|
|
||||||
|
- Fixed an encoding bug when streaming build progress
|
||||||
|
|
||||||
1.19.0 (2018-02-07)
|
1.19.0 (2018-02-07)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
|
|
@ -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.20.0-rc2'
|
__version__ = '1.20.0'
|
||||||
|
|
|
@ -8,6 +8,14 @@ class StreamOutputError(Exception):
|
||||||
pass
|
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):
|
def stream_output(output, stream):
|
||||||
is_terminal = hasattr(stream, 'isatty') and stream.isatty()
|
is_terminal = hasattr(stream, 'isatty') and stream.isatty()
|
||||||
stream = utils.get_output_stream(stream)
|
stream = utils.get_output_stream(stream)
|
||||||
|
@ -34,18 +42,18 @@ def stream_output(output, stream):
|
||||||
|
|
||||||
if image_id not in lines:
|
if image_id not in lines:
|
||||||
lines[image_id] = len(lines)
|
lines[image_id] = len(lines)
|
||||||
stream.write("\n")
|
write_to_stream("\n", stream)
|
||||||
|
|
||||||
diff = len(lines) - lines[image_id]
|
diff = len(lines) - lines[image_id]
|
||||||
|
|
||||||
# move cursor up `diff` rows
|
# 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)
|
print_output_event(event, stream, is_terminal)
|
||||||
|
|
||||||
if 'id' in event:
|
if 'id' in event:
|
||||||
# move cursor back down
|
# move cursor back down
|
||||||
stream.write("%c[%dB" % (27, diff))
|
write_to_stream("%c[%dB" % (27, diff), stream)
|
||||||
|
|
||||||
stream.flush()
|
stream.flush()
|
||||||
|
|
||||||
|
@ -60,36 +68,36 @@ def print_output_event(event, stream, is_terminal):
|
||||||
|
|
||||||
if is_terminal and 'stream' not in event:
|
if is_terminal and 'stream' not in event:
|
||||||
# erase current line
|
# erase current line
|
||||||
stream.write("%c[2K\r" % 27)
|
write_to_stream("%c[2K\r" % 27, stream)
|
||||||
terminator = "\r"
|
terminator = "\r"
|
||||||
elif 'progressDetail' in event:
|
elif 'progressDetail' in event:
|
||||||
return
|
return
|
||||||
|
|
||||||
if 'time' in event:
|
if 'time' in event:
|
||||||
stream.write("[%s] " % event['time'])
|
write_to_stream("[%s] " % event['time'], stream)
|
||||||
|
|
||||||
if 'id' in event:
|
if 'id' in event:
|
||||||
stream.write("%s: " % event['id'])
|
write_to_stream("%s: " % event['id'], stream)
|
||||||
|
|
||||||
if 'from' in event:
|
if 'from' in event:
|
||||||
stream.write("(from %s) " % event['from'])
|
write_to_stream("(from %s) " % event['from'], stream)
|
||||||
|
|
||||||
status = event.get('status', '')
|
status = event.get('status', '')
|
||||||
|
|
||||||
if 'progress' in event:
|
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:
|
elif 'progressDetail' in event:
|
||||||
detail = event['progressDetail']
|
detail = event['progressDetail']
|
||||||
total = detail.get('total')
|
total = detail.get('total')
|
||||||
if 'current' in detail and total:
|
if 'current' in detail and total:
|
||||||
percentage = float(detail['current']) / float(total) * 100
|
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:
|
else:
|
||||||
stream.write('%s%s' % (status, terminator))
|
write_to_stream('%s%s' % (status, terminator), stream)
|
||||||
elif 'stream' in event:
|
elif 'stream' in event:
|
||||||
stream.write("%s%s" % (event['stream'], terminator))
|
write_to_stream("%s%s" % (event['stream'], terminator), stream)
|
||||||
else:
|
else:
|
||||||
stream.write("%s%s\n" % (status, terminator))
|
write_to_stream("%s%s\n" % (status, terminator), stream)
|
||||||
|
|
||||||
|
|
||||||
def get_digest_from_pull(events):
|
def get_digest_from_pull(events):
|
||||||
|
|
|
@ -2,7 +2,7 @@ backports.ssl-match-hostname==3.5.0.1; python_version < '3'
|
||||||
cached-property==1.3.0
|
cached-property==1.3.0
|
||||||
certifi==2017.4.17
|
certifi==2017.4.17
|
||||||
chardet==3.0.4
|
chardet==3.0.4
|
||||||
docker==3.1.1
|
docker==3.1.3
|
||||||
docker-pycreds==0.2.1
|
docker-pycreds==0.2.1
|
||||||
dockerpty==0.4.1
|
dockerpty==0.4.1
|
||||||
docopt==0.6.2
|
docopt==0.6.2
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
VERSION="1.20.0-rc2"
|
VERSION="1.20.0"
|
||||||
IMAGE="docker/compose:$VERSION"
|
IMAGE="docker/compose:$VERSION"
|
||||||
|
|
||||||
|
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -36,7 +36,7 @@ install_requires = [
|
||||||
'requests >= 2.6.1, != 2.11.0, != 2.12.2, != 2.18.0, < 2.19',
|
'requests >= 2.6.1, != 2.11.0, != 2.12.2, != 2.18.0, < 2.19',
|
||||||
'texttable >= 0.9.0, < 0.10',
|
'texttable >= 0.9.0, < 0.10',
|
||||||
'websocket-client >= 0.32.0, < 1.0',
|
'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',
|
'dockerpty >= 0.4.1, < 0.5',
|
||||||
'six >= 1.3.0, < 2',
|
'six >= 1.3.0, < 2',
|
||||||
'jsonschema >= 2.5.1, < 3',
|
'jsonschema >= 2.5.1, < 3',
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
|
# ~*~ encoding: utf-8 ~*~
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
from six import StringIO
|
from six import StringIO
|
||||||
|
|
||||||
from compose import progress_stream
|
from compose import progress_stream
|
||||||
|
@ -66,6 +73,30 @@ class ProgressStreamTestCase(unittest.TestCase):
|
||||||
events = progress_stream.stream_output(events, output)
|
events = progress_stream.stream_output(events, output)
|
||||||
assert len(output.getvalue()) > 0
|
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():
|
def test_get_digest_from_push():
|
||||||
digest = "sha256:abcd"
|
digest = "sha256:abcd"
|
||||||
|
|
Loading…
Reference in New Issue