From 4e9f273d9c4a2d19ad15169ff1f244c4b1e7bbd1 Mon Sep 17 00:00:00 2001 From: Evan Martin Date: Sun, 8 May 2011 21:47:03 -0700 Subject: add support for ignoring failures of some subtasks --- src/build.cc | 12 ++++++++---- src/build.h | 5 ++++- src/build_test.cc | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/build.cc b/src/build.cc index 913bc31..2a280e0 100644 --- a/src/build.cc +++ b/src/build.cc @@ -366,7 +366,7 @@ struct DryRunCommandRunner : public CommandRunner { }; Builder::Builder(State* state, const BuildConfig& config) - : state_(state) { + : state_(state), config_(config) { disk_interface_ = new RealDiskInterface; if (config.dry_run) command_runner_ = new DryRunCommandRunner; @@ -410,6 +410,7 @@ bool Builder::Build(string* err) { } status_->PlanHasTotalEdges(plan_.command_edge_count()); + int failures_allowed = config_.swallow_failures; while (plan_.more_to_do()) { while (command_runner_->CanRunMore()) { Edge* edge = plan_.FindWork(); @@ -429,10 +430,13 @@ bool Builder::Build(string* err) { bool success; if (Edge* edge = command_runner_->NextFinishedCommand(&success)) { if (!success) { - *err = "subcommand failed"; - return false; + if (--failures_allowed < 0) { + *err = "subcommand failed"; + return false; + } + } else { + FinishEdge(edge); } - FinishEdge(edge); } else { if (!command_runner_->WaitForCommands()) { *err = "stuck [this is a bug]"; diff --git a/src/build.h b/src/build.h index feb83d5..96ae186 100644 --- a/src/build.h +++ b/src/build.h @@ -80,7 +80,8 @@ struct CommandRunner { /// Options (e.g. verbosity, parallelism) passed to a build. struct BuildConfig { - BuildConfig() : verbosity(NORMAL), dry_run(false), parallelism(1) {} + BuildConfig() : verbosity(NORMAL), dry_run(false), parallelism(1), + swallow_failures(0) {} enum Verbosity { NORMAL, @@ -90,6 +91,7 @@ struct BuildConfig { Verbosity verbosity; bool dry_run; int parallelism; + int swallow_failures; }; /// Builder wraps the build process: starting commands, updating status. @@ -104,6 +106,7 @@ struct Builder { void FinishEdge(Edge* edge); State* state_; + const BuildConfig& config_; Plan plan_; DiskInterface* disk_interface_; CommandRunner* command_runner_; diff --git a/src/build_test.cc b/src/build_test.cc index d55cae3..c067001 100644 --- a/src/build_test.cc +++ b/src/build_test.cc @@ -253,13 +253,15 @@ bool BuildTest::StartCommand(Edge* edge) { (*out)->file_->mtime_ = now_; (*out)->dirty_ = false; } - last_command_ = edge; - return true; + } else if (edge->rule_->name_ == "fail") { + // Don't do anything. } else { - printf("unkown command\n"); + printf("unknown command\n"); + return false; } - return false; + last_command_ = edge; + return true; } bool BuildTest::WaitForCommands() { @@ -269,7 +271,10 @@ bool BuildTest::WaitForCommands() { Edge* BuildTest::NextFinishedCommand(bool* success) { if (Edge* edge = last_command_) { - *success = true; + if (edge->rule_->name_ == "fail") + *success = false; + else + *success = true; last_command_ = NULL; return edge; } @@ -517,3 +522,38 @@ TEST_F(BuildTest, Phony) { ASSERT_NE("", err); } +TEST_F(BuildTest, Fail) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"rule fail\n" +" command = fail\n" +"build out1: fail\n")); + + string err; + EXPECT_TRUE(builder_.AddTarget("out1", &err)); + ASSERT_EQ("", err); + + EXPECT_FALSE(builder_.Build(&err)); + ASSERT_EQ(1u, commands_ran_.size()); + ASSERT_EQ("subcommand failed", err); +} + +TEST_F(BuildTest, SwallowFailures) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"rule fail\n" +" command = fail\n" +"build out1: fail\n" +"build out2: fail\n" +"build out3: fail\n" +"build all: phony out1 out2 out3\n")); + + // Swallow two failures, die on the third. + config_.swallow_failures = 2; + + string err; + EXPECT_TRUE(builder_.AddTarget("all", &err)); + ASSERT_EQ("", err); + + EXPECT_FALSE(builder_.Build(&err)); + ASSERT_EQ(3u, commands_ran_.size()); + ASSERT_EQ("subcommand failed", err); +} -- cgit v0.12