@@ -10,34 +10,67 @@ def initialize(verbose: false)
1010 @github_actions_markup = ENV [ "ENABLE_GITHUB_ACTIONS_MARKUP" ] != nil
1111 end
1212
13- def system ( *args , chdir : nil , out : nil , env : nil )
13+ def system ( *args , chdir : nil , env : nil )
14+ require "open3"
15+
1416 _print_command ( args , env )
1517
16- if @verbose
17- out ||= $stdout
18- else
19- # Capture stdout by default
20- out_pipe = IO . pipe
21- out = out_pipe [ 1 ]
22- end
2318 # @type var kwargs: Hash[Symbol, untyped]
24- kwargs = { exception : true , out : out }
19+ kwargs = { }
2520 kwargs [ :chdir ] = chdir if chdir
26- begin
27- if env
28- Kernel . system ( env , *args . to_a . map ( &:to_s ) , **kwargs )
21+
22+ args = args . to_a . map ( &:to_s )
23+ # TODO: Remove __skip__ once we have open3 RBS definitions.
24+ __skip__ =
25+ if @verbose || !$stdout. tty?
26+ kwargs [ :exception ] = true
27+ if env
28+ Kernel . system ( env , *args , **kwargs )
29+ else
30+ Kernel . system ( *args , **kwargs )
31+ end
2932 else
30- Kernel . system ( *args . to_a . map ( &:to_s ) , **kwargs )
33+ printer = StatusPrinter . new
34+ block =
35+ proc do |stdin , stdout , stderr , wait_thr |
36+ mux = Mutex . new
37+ out = String . new
38+ err = String . new
39+ readers =
40+ [
41+ [ stdout , :stdout , out ] ,
42+ [ stderr , :stderr , err ]
43+ ] . map do |io , name , str |
44+ reader =
45+ Thread . new do
46+ while ( line = io . gets )
47+ mux . synchronize do
48+ printer . send ( name , line )
49+ str << line
50+ end
51+ end
52+ end
53+ reader . report_on_exception = false
54+ reader
55+ end
56+
57+ readers . each ( &:join )
58+
59+ [ out , err , wait_thr . value ]
60+ end
61+ begin
62+ if env
63+ Open3 . popen3 ( env , *args , **kwargs , &block )
64+ else
65+ Open3 . popen3 ( *args , **kwargs , &block )
66+ end
67+ ensure
68+ printer . done
69+ end
3170 end
32- ensure
33- out . close if out_pipe
34- end
3571 rescue => e
36- if out_pipe
37- # Print the output of the failed command
38- puts out_pipe [ 0 ] . read
39- end
4072 $stdout. flush
73+ $stderr. puts "Try running with `rake --verbose` for more complete output."
4174 raise e
4275 end
4376
@@ -58,9 +91,7 @@ def begin_section(klass, name, note)
5891
5992 def end_section ( klass , name )
6093 took = Time . now - @start_times [ [ klass , name ] ]
61- if @github_actions_markup
62- puts "::endgroup::"
63- end
94+ puts "::endgroup::" if @github_actions_markup
6495 puts "\e [1;36m==>\e [0m \e [1m#{ klass } (#{ name } ) -- done in #{ took . round ( 2 ) } s\e [0m"
6596 end
6697
@@ -98,4 +129,46 @@ def _print_command(args, env)
98129 print args . map { |arg | Shellwords . escape ( arg . to_s ) } . join ( " " ) + "\n "
99130 end
100131 end
132+
133+ # Human readable status printer for the build.
134+ class StatusPrinter
135+ def initialize
136+ @mutex = Mutex . new
137+ @counter = 0
138+ @indicators = "|/-\\ "
139+ end
140+
141+ def stdout ( message )
142+ require "io/console"
143+ @mutex . synchronize do
144+ $stdout. print "\e [K"
145+ first_line = message . lines ( chomp : true ) . first || ""
146+
147+ # Make sure we don't line-wrap the output
148+ size =
149+ __skip__ =
150+ IO . respond_to? ( :console_size ) ? IO . console_size : IO . console . winsize
151+ terminal_width = size [ 1 ] . to_i . nonzero? || 80
152+ width_limit = terminal_width / 2 - 3
153+
154+ if first_line . length > width_limit
155+ first_line = ( first_line [ 0 ..width_limit - 5 ] || "" ) + "..."
156+ end
157+ indicator = @indicators [ @counter ] || " "
158+ to_print = " " + indicator + " " + first_line
159+ $stdout. print to_print
160+ $stdout. print "\e [1A\n "
161+ @counter += 1
162+ @counter = 0 if @counter >= @indicators . length
163+ end
164+ end
165+
166+ def stderr ( message )
167+ @mutex . synchronize { $stdout. print message }
168+ end
169+
170+ def done
171+ @mutex . synchronize { $stdout. print "\e [K" }
172+ end
173+ end
101174end
0 commit comments