Improve handling of build log output

This makes sure build logs don’t leak escape sequences and new lines and they don’t break the output. Also improved “inline” logs by normalising the stream before passing it to “transpose build stream”.

Fixes: #808
Change-Type: patch
This commit is contained in:
Akis Kesoglou 2018-03-15 15:16:33 +02:00
parent e5fb954645
commit 1833f6ff0a
2 changed files with 20 additions and 22 deletions

View File

@ -144,6 +144,7 @@ exports.buildProject = (
) -> ) ->
_ = require('lodash') _ = require('lodash')
humanize = require('humanize') humanize = require('humanize')
split = require('split')
compose = require('resin-compose-parse') compose = require('resin-compose-parse')
builder = require('resin-multibuild') builder = require('resin-multibuild')
transpose = require('docker-qemu-transpose') transpose = require('docker-qemu-transpose')
@ -225,6 +226,7 @@ exports.buildProject = (
task.progressHook = pullProgressAdapter(captureStream) task.progressHook = pullProgressAdapter(captureStream)
else else
task.streamHook = (stream) -> task.streamHook = (stream) ->
stream = createLogStream(stream)
if qemuPath? if qemuPath?
buildThroughStream = transpose.getBuildThroughStream buildThroughStream = transpose.getBuildThroughStream
hostQemuPath: toPosixPath(qemuPath) hostQemuPath: toPosixPath(qemuPath)
@ -236,6 +238,7 @@ exports.buildProject = (
# where we're given objects. capture these strings as they come # where we're given objects. capture these strings as they come
# before we parse them. # before we parse them.
rawStream rawStream
.pipe(dropEmptyLinesStream())
.pipe(captureStream) .pipe(captureStream)
.pipe(buildProgressAdapter(inlineLogs)) .pipe(buildProgressAdapter(inlineLogs))
.pipe(task.logStream) .pipe(task.logStream)
@ -440,13 +443,22 @@ pushProgressRenderer = (tty, prefix) ->
tty.clearLine() tty.clearLine()
return fn return fn
createLogStream = (input) ->
split = require('split')
stripAnsi = require('strip-ansi-stream')
return input.pipe(stripAnsi()).pipe(split())
dropEmptyLinesStream = ->
through = require('through2')
through (data, enc, cb) ->
str = data.toString('utf-8')
@push(str) if str.trim()
cb()
buildLogCapture = (objectMode, buffer) -> buildLogCapture = (objectMode, buffer) ->
_ = require('lodash')
through = require('through2') through = require('through2')
through { objectMode }, (data, enc, cb) -> through { objectMode }, (data, enc, cb) ->
return cb(null, data) if not data?
# data from pull stream # data from pull stream
if data.error if data.error
buffer.push("#{data.error}") buffer.push("#{data.error}")
@ -457,30 +469,14 @@ buildLogCapture = (objectMode, buffer) ->
# data from build stream # data from build stream
else else
# normalise build log output here. it is somewhat ugly buffer.push(data)
# that this supposedly "passthrough" stream mutates the
# values before forwarding them, but it's convenient
# as it allows to both forward and save normalised logs
# convert to string, split to lines, trim each one and
# filter out empty ones.
lines = _(data.toString('utf-8').split(/\r?\n$/))
.map(_.trimEnd)
.reject(_.isEmpty)
# forward each line separately
lines.forEach (line) =>
buffer.push(line)
@push(line)
return cb()
cb(null, data) cb(null, data)
buildProgressAdapter = (inline) -> buildProgressAdapter = (inline) ->
through = require('through2') through = require('through2')
stepRegex = /^\s*Step\s+(\d+)\/(\d+)\s*:\s+(.+)$/ stepRegex = /^\s*Step\s+(\d+)\/(\d+)\s*: (.+)$/
[ step, numSteps, progress ] = [ null, null, undefined ] [ step, numSteps, progress ] = [ null, null, undefined ]
@ -495,7 +491,7 @@ buildProgressAdapter = (inline) ->
else else
if (match = stepRegex.exec(str)) if (match = stepRegex.exec(str))
step = match[1] step = match[1]
numSteps = match[2] numSteps ?= match[2]
str = match[3] str = match[3]
if step? if step?
str = "Step #{step}/#{numSteps}: #{str}" str = "Step #{step}/#{numSteps}: #{str}"

View File

@ -148,8 +148,10 @@
"rimraf": "^2.4.3", "rimraf": "^2.4.3",
"rindle": "^1.0.0", "rindle": "^1.0.0",
"semver": "^5.3.0", "semver": "^5.3.0",
"split": "^1.0.1",
"stream-to-promise": "^2.2.0", "stream-to-promise": "^2.2.0",
"string-width": "^2.1.1", "string-width": "^2.1.1",
"strip-ansi-stream": "^1.0.0",
"through2": "^2.0.3", "through2": "^2.0.3",
"tmp": "0.0.31", "tmp": "0.0.31",
"umount": "^1.1.6", "umount": "^1.1.6",