rework showing failed command - close #89

This commit is contained in:
Josh Holtrop 2019-02-26 06:52:43 -05:00
parent ab2fa1662f
commit bf136e79f2
4 changed files with 48 additions and 31 deletions

View File

@ -80,13 +80,14 @@ module Rscons
# Exit code. # Exit code.
def build(options) def build(options)
begin begin
Cache.instance["failed_commands"] = []
@script.build @script.build
Environment.environments.each do |env| Environment.environments.each do |env|
env.process env.process
end end
0 0
rescue BuildError => be rescue BuildError => be
$stderr.puts be Ansi.write($stderr, :red, be.message, :reset, "\n")
1 1
end end
end end
@ -137,6 +138,7 @@ module Rscons
options[:build_dir] ||= "build" options[:build_dir] ||= "build"
options[:prefix] ||= "/usr/local" options[:prefix] ||= "/usr/local"
cache = Cache.instance cache = Cache.instance
cache["failed_commands"] = []
cache["configuration_data"] = {} cache["configuration_data"] = {}
if project_name = @script.project_name if project_name = @script.project_name
Ansi.write($stdout, "Configuring ", :cyan, project_name, :reset, "...\n") Ansi.write($stdout, "Configuring ", :cyan, project_name, :reset, "...\n")

View File

@ -5,6 +5,7 @@ USAGE = <<EOF
Usage: #{$0} [global options] [operation] [operation options] Usage: #{$0} [global options] [operation] [operation options]
Global options: Global options:
-F, --show-failure Show previous failed command(s) and exit
--version Show rscons version and exit --version Show rscons version and exit
-h, --help Show rscons help and exit -h, --help Show rscons help and exit
-r COLOR, --color=COLOR Set color mode (off, auto, force) -r COLOR, --color=COLOR Set color mode (off, auto, force)
@ -86,6 +87,11 @@ module Rscons
rsconscript = f rsconscript = f
end end
opts.on("-F", "--show-failure") do
show_failure
exit 0
end
opts.on("--version") do opts.on("--version") do
puts "Rscons version #{Rscons::VERSION}" puts "Rscons version #{Rscons::VERSION}"
exit 0 exit 0
@ -157,6 +163,14 @@ module Rscons
end end
end end
def show_failure
failed_commands = Cache.instance["failed_commands"]
failed_commands.each_with_index do |command, i|
Ansi.write($stdout, :red, "Failed command (#{i + 1}/#{failed_commands.size}):", :reset, "\n")
$stdout.puts Util.command_to_s(command)
end
end
end end
end end
end end

View File

@ -261,7 +261,7 @@ module Rscons
unless Cache.instance["configuration_data"]["configured"] unless Cache.instance["configuration_data"]["configured"]
raise "Project must be configured before processing an Environment" raise "Project must be configured before processing an Environment"
end end
@process_failure = nil @process_failures = []
@process_blocking_wait = false @process_blocking_wait = false
@process_commands_waiting_to_run = [] @process_commands_waiting_to_run = []
@process_builder_waits = {} @process_builder_waits = {}
@ -269,7 +269,7 @@ module Rscons
begin begin
while @builder_set.size > 0 or @threads.size > 0 or @process_commands_waiting_to_run.size > 0 while @builder_set.size > 0 or @threads.size > 0 or @process_commands_waiting_to_run.size > 0
process_step process_step
if @process_failure unless @process_failures.empty?
# On a build failure, do not start any more builders or commands, # On a build failure, do not start any more builders or commands,
# but let the threads that have already been started complete. # but let the threads that have already been started complete.
@builder_set.clear @builder_set.clear
@ -279,8 +279,12 @@ module Rscons
ensure ensure
Cache.instance.write Cache.instance.write
end end
if @process_failure unless @process_failures.empty?
raise BuildError.new(@process_failure) msg = @process_failures.join("\n")
if Cache.instance["failed_commands"].size > 0
msg += "\nRun `#{$0} -F` to see the failed command(s)."
end
raise BuildError.new(msg)
end end
end end
@ -537,29 +541,8 @@ module Rscons
Ansi.write($stdout, :cyan, message, :reset, "\n") if message Ansi.write($stdout, :cyan, message, :reset, "\n") if message
end end
# Print a failed command.
#
# @param command [Array<String>]
# Builder command.
#
# @return [void]
def print_failed_command(command)
Ansi.write($stdout, :red, "Failed command was: #{Util.command_to_s(command)}", :reset, "\n")
end
private private
# Signal a build failure to the {#process} method.
#
# @param target [String]
# Build target name.
#
# @return [void]
def process_failure(target)
@process_failure = "Failed to build #{target}"
Ansi.write($stderr, :red, @process_failure, :reset, "\n")
end
# Run a builder and process its return value. # Run a builder and process its return value.
# #
# @param builder [Builder] # @param builder [Builder]
@ -587,7 +570,7 @@ module Rscons
end end
end end
when false when false
process_failure(builder.target) @process_failures << "Failed to build #{builder.target}."
when true when true
# Register side-effect files as build targets so that a Cache # Register side-effect files as build targets so that a Cache
# clean operation will remove them. # clean operation will remove them.
@ -644,10 +627,9 @@ module Rscons
process_remove_wait(completed_command) process_remove_wait(completed_command)
completed_command.status = thread.value completed_command.status = thread.value
unless completed_command.status unless completed_command.status
unless @echo == :command Cache.instance["failed_commands"] << completed_command.command
print_failed_command(completed_command.command) @process_failures << "Failed to build #{builder.target}."
end return
return process_failure(builder.target)
end end
end end
end end

View File

@ -853,6 +853,25 @@ EOF
expect(lines(result.stdout)).to include *["MyBuilder foo command"] expect(lines(result.stdout)).to include *["MyBuilder foo command"]
end end
it "stores the failed command for later display with -F command line option" do
test_dir("simple")
File.open("simple.c", "wb") do |fh|
fh.write("foo")
end
result = run_rscons
expect(result.stderr).to match /Failed to build/
expect(result.stderr).to match /^Run.*-F.*to see the failed command/
expect(result.status).to_not eq 0
result = run_rscons(rscons_args: %w[-F])
expect(result.stderr).to eq ""
expect(result.stdout).to match %r{Failed command \(1/1\):}
expect(result.stdout).to match %r{^gcc -}
expect(result.status).to eq 0
end
context "colored output" do context "colored output" do
it "does not output in color with --color=off" do it "does not output in color with --color=off" do
test_dir("simple") test_dir("simple")