summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2011-05-09 04:47:03 (GMT)
committerEvan Martin <martine@danga.com>2011-05-09 15:50:32 (GMT)
commit4e9f273d9c4a2d19ad15169ff1f244c4b1e7bbd1 (patch)
treedbe8c79573c6b7b458c4f6427bb4f01c93d7aafe
parent3a48d1027e594e39ee5dc526e9254387715a945e (diff)
downloadNinja-4e9f273d9c4a2d19ad15169ff1f244c4b1e7bbd1.zip
Ninja-4e9f273d9c4a2d19ad15169ff1f244c4b1e7bbd1.tar.gz
Ninja-4e9f273d9c4a2d19ad15169ff1f244c4b1e7bbd1.tar.bz2
add support for ignoring failures of some subtasks
-rw-r--r--src/build.cc12
-rw-r--r--src/build.h5
-rw-r--r--src/build_test.cc50
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);
+}