From 2a96495e8333ea55b1cabf5c8615cf01e5ba279f Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 26 Jun 2017 22:44:49 -0400 Subject: [PATCH] wait for in-progress subcommands to complete on build failure - close #39 --- .../simple/wait_for_builds_on_failure.rb | 20 ++++++++++++++++ lib/rscons/cli.rb | 1 - lib/rscons/environment.rb | 23 +++++++++++++++---- spec/build_tests_spec.rb | 10 ++++++++ 4 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 build_tests/simple/wait_for_builds_on_failure.rb diff --git a/build_tests/simple/wait_for_builds_on_failure.rb b/build_tests/simple/wait_for_builds_on_failure.rb new file mode 100644 index 0000000..550cf73 --- /dev/null +++ b/build_tests/simple/wait_for_builds_on_failure.rb @@ -0,0 +1,20 @@ +class Fail < Rscons::Builder + def run(options) + target, cache, env, vars = options.values_at(:target, :cache, :env, :vars) + wait_time = env.expand_varref("${wait_time}", vars) + ruby_command = %[sleep #{wait_time}; exit 2] + command = %W[ruby -e #{ruby_command}] + standard_threaded_build("Fail #{target}", target, command, [], env, cache) + end + def finalize(options) + standard_finalize(options) + end +end + +Rscons::Environment.new do |env| + env.add_builder(Fail.new) + 4.times do |i| + wait_time = i + 1 + env.Fail("foo_#{wait_time}", [], "wait_time" => wait_time.to_s) + end +end diff --git a/lib/rscons/cli.rb b/lib/rscons/cli.rb index 4776128..80bb1a5 100644 --- a/lib/rscons/cli.rb +++ b/lib/rscons/cli.rb @@ -70,7 +70,6 @@ module Rscons begin load rsconsfile rescue Rscons::BuildError => e - $stderr.puts e.message exit 1 end diff --git a/lib/rscons/environment.rb b/lib/rscons/environment.rb index d85e821..6fef4c4 100644 --- a/lib/rscons/environment.rb +++ b/lib/rscons/environment.rb @@ -302,13 +302,19 @@ module Rscons # @return [void] def process cache = Cache.instance + failure = nil begin while @job_set.size > 0 or @threaded_commands.size > 0 - targets_still_building = @threaded_commands.map do |tc| - tc.build_operation[:target] + if failure + @job_set.clear! + job = nil + else + targets_still_building = @threaded_commands.map do |tc| + tc.build_operation[:target] + end + job = @job_set.get_next_job_to_run(targets_still_building) end - job = @job_set.get_next_job_to_run(targets_still_building) # TODO: have Cache determine when checksums may be invalid based on # file size and/or timestamp. @@ -323,7 +329,9 @@ module Rscons allow_delayed_execution: true, setup_info: job[:setup_info]) unless result - raise BuildError.new("Failed to build #{job[:target]}") + failure = "Failed to build #{job[:target]}" + $stderr.puts failure + next end end @@ -351,7 +359,9 @@ module Rscons unless @echo == :command $stdout.puts "Failed command was: #{command_to_s(tc.command)}" end - raise BuildError.new("Failed to build #{tc.build_operation[:target]}") + failure = "Failed to build #{tc.build_operation[:target]}" + $stderr.puts failure + break end end @@ -359,6 +369,9 @@ module Rscons ensure cache.write end + if failure + raise BuildError.new(failure) + end end # Clear all targets registered for the Environment. diff --git a/spec/build_tests_spec.rb b/spec/build_tests_spec.rb index 9b96fc8..0f80eb7 100644 --- a/spec/build_tests_spec.rb +++ b/spec/build_tests_spec.rb @@ -752,6 +752,16 @@ EOF expect(result.stderr).to eq "" end + it "waits for all parallelized builds to complete if one fails" do + test_dir("simple") + result = run_test(rsconsfile: "wait_for_builds_on_failure.rb", rscons_args: %w[-j4]) + expect(result.status).to_not eq 0 + expect(result.stderr).to match /Failed to build foo_1/ + expect(result.stderr).to match /Failed to build foo_2/ + expect(result.stderr).to match /Failed to build foo_3/ + expect(result.stderr).to match /Failed to build foo_4/ + end + context "backward compatibility" do it "allows a builder to call Environment#run_builder in a non-threaded manner" do test_dir("simple")