travis-web/assets/scripts/lib/travis/log.coffee
Piotr Sarnacki fc40190c29 Optimize log viewer
Till now, log viewer was rendered in handlebars, which was the simplest
solution, but it had a major drawback - every append to log caused it to
rerender which was not efficient and memory consuming.

The new approach is to make Travis.Log interpret the log and send lines
with instructions to the view, so for example if view should add a line,
it gets something like:

    { number: 1, content: '$ bundle install' }

Such approach is required to handle cases where data coming from pusher
is not actually a new line. For example output containing dots from
tests needs to be appended:

    $ rake
    ....

Such output could be sent to client in 2 chunks: "$ rake\n.." and "..".
In such situation we would need to send 3 instructions:

  { number: 1, content: '$ rake' }
  { number: 2, content: '..'     }
  { number: 2, content: '..', append: true }

The third instruction can come much later, because tests can take a
while to run, so we can't assume that each line will come in one piece.

The other scenario is \r, for example when showing progress:

    \rDownloading: 10%
    \rDownloading: 50%
    \rDownloading: 100%

Such input should be changed into such instructions:

  { number: 1, content: 'Downloading: 10%' }
  { number: 1, content: 'Downloading: 50%',  replace: true }
  { number: 1, content: 'Downloading: 100%', replace: true }

Travis.Log also supports folds, for example on bundle install, the code
was rewritten to make folds management simpler.
2012-12-04 22:57:57 +01:00

133 lines
3.4 KiB
CoffeeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TODO: revisit those patterns
FOLDS = [
Em.Object.create(name: 'schema', startPattern: /^\$ (?:bundle exec )?rake( db:create)? db:schema:load/, endPattern: /^\$/)
Em.Object.create(name: 'migrate', startPattern: /^\$ (?:bundle exec )?rake( db:create)? db:migrate/, endPattern: /^\$/)
Em.Object.create(name: 'bundle', startPattern: /^\$ bundle install/, endPattern: /^\$/)
]
@Travis.Log = Em.Object.extend
init: ->
@set 'folds', []
@set 'line', 1
for fold in FOLDS
@addFold fold
append: (lines) ->
log = @join lines
log = @escape log
log = @deansi log
lines = @split log
target = @get 'target'
index = 0
currentFold = @currentFold
@set 'lineNumber', 1 unless @get 'lineNumber'
result = []
for line in lines
if line == '\r'
@set 'replace', true
else if line == '\n'
@set 'newline', true
index += 1
else
if currentFold && ( @isFoldEnding(currentFold, line) )
# end of the fold, send fold to target
if result.length > 0
result.slice(-1)[0].foldEnd = true
target.appendLog result
@currentFold = currentFold = null
@set 'foldContinuation', false
result = []
if !currentFold && ( currentFold = @foldByStart(line) )
# beginning new fold, send current lines to target
if result.length > 0
target.appendLog result
result = []
start = index
payload = { content: line }
if currentFold
payload.fold = currentFold.get('name')
if @get 'foldContinuation'
payload.foldContinuation = true
payload.number = @get('lineNumber') + index
if @get 'replace'
@set 'replace', false
payload.replace = true
else if @get 'newline'
@set 'newline', false
else if payload.number != 1
payload.append = true
result.pushObject payload
if currentFold
@set 'foldContinuation', true
if result.length > 0
if currentFold
@currentFold = currentFold
target.appendLog result
nextLineNumber = @get('lineNumber') + index
@set 'lineNumber', nextLineNumber
join: (lines) ->
if typeof lines == 'string'
lines
else
lines.toArray().join ''
split: (log) ->
log = log.replace /\r\n/g, '\n'
lines = log.split(/(\n)/)
result = []
for line in lines
result.pushObjects line.split(/(\r)/)
result
escape: (log) ->
Handlebars.Utils.escapeExpression log
deansi: (log) ->
log = log.replace(/\r\r/g, '\r')
.replace(/\033\[K\r/g, '\r')
.replace(/\[2K/g, '')
.replace(/\033\(B/g, '')
.replace(/\033\[\d+G/, '')
ansi = ansiparse(log)
text = ''
ansi.forEach (part) ->
classes = []
part.foreground and classes.push(part.foreground)
part.background and classes.push('bg-' + part.background)
part.bold and classes.push('bold')
part.italic and classes.push('italic')
text += (if classes.length then ('<span class=\'' + classes.join(' ') + '\'>' + part.text + '</span>') else part.text)
text.replace /\033/g, ''
addFold: (fold) ->
@get('folds').pushObject fold
foldByStart: (line) ->
@get('folds').find (fold) -> line.match(fold.get('startPattern'))
isFoldEnding: (fold, line) ->
line.match(fold.get('endPattern'))