Fix build against the swarm cluster by joining buffered output before parsing json.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
Daniel Nephin 2015-10-02 19:47:27 -04:00
parent fe65c0258d
commit 3661e8bc74
7 changed files with 49 additions and 37 deletions

View File

@ -6,8 +6,8 @@ from itertools import cycle
from . import colors
from .multiplexer import Multiplexer
from .utils import split_buffer
from compose import utils
from compose.utils import split_buffer
class LogPrinter(object):
@ -75,7 +75,7 @@ def build_no_log_generator(container, prefix, color_func):
def build_log_generator(container, prefix, color_func):
# Attach to container before log printer starts running
stream = container.attach(stdout=True, stderr=True, stream=True, logs=True)
line_generator = split_buffer(stream, u'\n')
line_generator = split_buffer(stream)
for line in line_generator:
yield prefix + line

View File

@ -7,7 +7,6 @@ import platform
import ssl
import subprocess
import six
from docker import version as docker_py_version
from six.moves import input
@ -36,31 +35,6 @@ def yesno(prompt, default=None):
return None
def split_buffer(reader, separator):
"""
Given a generator which yields strings and a separator string,
joins all input, splits on the separator and yields each chunk.
Unlike string.split(), each chunk includes the trailing
separator, except for the last one if none was found on the end
of the input.
"""
buffered = six.text_type('')
separator = six.text_type(separator)
for data in reader:
buffered += data.decode('utf-8')
while True:
index = buffered.find(separator)
if index == -1:
break
yield buffered[:index + 1]
buffered = buffered[index + 1:]
if len(buffered) > 0:
yield buffered
def call_silently(*args, **kwargs):
"""
Like subprocess.call(), but redirects stdout and stderr to /dev/null.

View File

@ -1,7 +1,5 @@
import json
import six
from compose import utils
@ -16,9 +14,7 @@ def stream_output(output, stream):
lines = {}
diff = 0
for chunk in output:
if six.PY3:
chunk = chunk.decode('utf-8')
for chunk in utils.stream_as_text(output):
event = json.loads(chunk)
all_events.append(event)

View File

@ -33,6 +33,8 @@ from .progress_stream import stream_output
from .progress_stream import StreamOutputError
from .utils import json_hash
from .utils import parallel_execute
from .utils import split_buffer
log = logging.getLogger(__name__)
@ -722,7 +724,7 @@ class Service(object):
)
try:
all_events = stream_output(build_output, sys.stdout)
all_events = stream_output(split_buffer(build_output), sys.stdout)
except StreamOutputError as e:
raise BuildError(self, six.text_type(e))

View File

@ -83,6 +83,44 @@ def get_output_stream(stream):
return codecs.getwriter('utf-8')(stream)
def stream_as_text(stream):
"""Given a stream of bytes or text, if any of the items in the stream
are bytes convert them to text.
This function can be removed once docker-py returns text streams instead
of byte streams.
"""
for data in stream:
if not isinstance(data, six.text_type):
data = data.decode('utf-8')
yield data
def split_buffer(reader, separator=u'\n'):
"""
Given a generator which yields strings and a separator string,
joins all input, splits on the separator and yields each chunk.
Unlike string.split(), each chunk includes the trailing
separator, except for the last one if none was found on the end
of the input.
"""
buffered = six.text_type('')
separator = six.text_type(separator)
for data in stream_as_text(reader):
buffered += data
while True:
index = buffered.find(separator)
if index == -1:
break
yield buffered[:index + 1]
buffered = buffered[index + 1:]
if len(buffered) > 0:
yield buffered
def write_out_msg(stream, lines, msg_index, msg, status="done"):
"""
Using special ANSI code characters we can write out the msg over the top of

View File

@ -9,6 +9,8 @@ from compose.config.config import ServiceLoader
from compose.const import LABEL_PROJECT
from compose.progress_stream import stream_output
from compose.service import Service
from compose.utils import split_buffer
from compose.utils import stream_as_text
def pull_busybox(client):
@ -71,5 +73,5 @@ class DockerClientTestCase(unittest.TestCase):
def check_build(self, *args, **kwargs):
kwargs.setdefault('rm', True)
build_output = self.client.build(*args, **kwargs)
stream_output(build_output, open('/dev/null', 'w'))
build_output = stream_as_text(self.client.build(*args, **kwargs))
stream_output(split_buffer(build_output), open('/dev/null', 'w'))

View File

@ -2,7 +2,7 @@ from __future__ import absolute_import
from __future__ import unicode_literals
from .. import unittest
from compose.cli.utils import split_buffer
from compose.utils import split_buffer
class SplitBufferTest(unittest.TestCase):