Skip to content
This repository has been archived by the owner on Aug 16, 2023. It is now read-only.

Commit

Permalink
Merge pull request #30 from JuliaPackaging/sf/tail_control
Browse files Browse the repository at this point in the history
Increase the amount of control we have over tailing our output
  • Loading branch information
staticfloat authored Feb 5, 2018
2 parents 615b4d0 + f2e0355 commit 2ca0f33
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 12 deletions.
29 changes: 18 additions & 11 deletions src/OutputCollector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,17 @@ mutable struct OutputCollector
stdout_linestream::LineStream
stderr_linestream::LineStream
event::Condition
tee_stream::IO
verbose::Bool
done::Bool
tail_error::Bool

done::Bool
extra_tasks::Vector{Task}

function OutputCollector(cmd, P, out_ls, err_ls, event, verbose)
return new(cmd, P, out_ls, err_ls, event, verbose, false, Task[])
function OutputCollector(cmd, P, out_ls, err_ls, event, tee_stream,
verbose, tail_error)
return new(cmd, P, out_ls, err_ls, event, tee_stream, verbose,
tail_error, false, Task[])
end
end

Expand All @@ -102,7 +106,8 @@ Run `cmd`, and collect the output such that `stdout` and `stderr` are captured
independently, but with the time of each line recorded such that they can be
stored/analyzed independently, but replayed synchronously.
"""
function OutputCollector(cmd::Base.AbstractCmd; verbose::Bool=false, tee_stream=STDOUT)
function OutputCollector(cmd::Base.AbstractCmd; verbose::Bool=false,
tail_error::Bool=true, tee_stream::IO=STDOUT)
# First, launch the command
out_pipe = Pipe()
err_pipe = Pipe()
Expand All @@ -120,7 +125,8 @@ function OutputCollector(cmd::Base.AbstractCmd; verbose::Bool=false, tee_stream=

# Finally, wrap this up in an object so that we can merge stdout and stderr
# back together again at the end
self = OutputCollector(cmd, P, out_ls, err_ls, event, verbose)
self = OutputCollector(cmd, P, out_ls, err_ls, event, tee_stream,
verbose, tail_error)

# If we're set as verbose, then start reading ourselves out to stdout
if verbose
Expand Down Expand Up @@ -156,10 +162,10 @@ function wait(collector::OutputCollector)
# From this point on, we are actually done!
collector.done = true

# If we failed, then tail the output, unless we've been tee()'ing it out
# this whole time
if !success(collector.P) && !collector.verbose
print(tail(collector; colored=Base.have_color))
# If we failed, then print out the tail of the output, unless we've been
# tee()'ing it out this whole time, but only if the user said it's okay to.
if !success(collector.P) && !collector.verbose && collector.tail_error
print(collector.tee_stream, tail(collector; colored=Base.have_color))
end

# Shout to the world how we've done
Expand Down Expand Up @@ -271,12 +277,13 @@ function tail(collector::OutputCollector; len::Int = 100, colored::Bool = false)
end

"""
`tee(c::OutputCollector; colored::Bool = false)`
`tee(c::OutputCollector; colored::Bool = false, stream::IO = STDOUT)`
Spawn a background task to incrementally output lines from `collector` to the
standard output, optionally colored.
"""
function tee(c::OutputCollector; colored::Bool = Base.have_color, stream=STDOUT)
function tee(c::OutputCollector; colored::Bool=Base.have_color,
stream::IO=STDOUT)
tee_task = @async begin
out_idx = 1
err_idx = 1
Expand Down
43 changes: 42 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ const newlines_out = join(["marco$(d)polo$(d)" for d in ("\n","\r","\r\n")], "")
# CI debugging easier
BinaryProvider.probe_platform_engines!(;verbose=true)

# Helper function to strip out color codes from strings to make it easier to
# compare output within tests that has been colorized
function strip_colorization(s)
return replace(s, r"(\e\[\d+m)"m, "")
end

# Helper function to strip out log timestamps from strings
function strip_timestamps(s)
return replace(s, r"^(\[\d\d:\d\d:\d\d\] )"m, "")
end

@testset "OutputCollector" begin
cd("output_tests") do
# Collect the output of `simple.sh``
Expand Down Expand Up @@ -109,8 +120,38 @@ BinaryProvider.probe_platform_engines!(;verbose=true)
oc = OutputCollector(sh(`./simple.sh`); tee_stream=ios, verbose=true)
@test wait(oc)
@test merge(oc) == simple_out

seekstart(ios)
tee_out = readstring(ios)
tee_out = strip_colorization(tee_out)
tee_out = strip_timestamps(tee_out)
@test tee_out == simple_out
end

# Also test that auto-tail'ing can be can be directed to a stream
cd("output_tests") do
ios = IOBuffer()
oc = OutputCollector(sh(`./fail.sh`); tee_stream=ios)

@test !wait(oc)
@test merge(oc) == "1\n2\n"
seekstart(ios)
tee_out = readstring(ios)
tee_out = strip_colorization(tee_out)
tee_out = strip_timestamps(tee_out)
@test tee_out == "1\n2\n"
end

# Also test that auto-tail'ing can be turned off
cd("output_tests") do
ios = IOBuffer()
oc = OutputCollector(sh(`./fail.sh`); tee_stream=ios, tail_error=false)

@test !wait(oc)
@test merge(oc) == "1\n2\n"

seekstart(ios)
println(readstring(ios))
@test readstring(ios) == ""
end
end

Expand Down

0 comments on commit 2ca0f33

Please sign in to comment.