summaryrefslogtreecommitdiffstats
path: root/src/build.cc
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2011-11-13 05:49:16 (GMT)
committerPeter Collingbourne <peter@pcc.me.uk>2012-02-04 21:46:12 (GMT)
commit85ff781fa30fff63c01ccd30faaad39d766e1505 (patch)
treedc5791da4769c61951735e84febcccfa8acf98d2 /src/build.cc
parentb07e183e0eb6225e34a3d592e3dff63bcf00df81 (diff)
downloadNinja-85ff781fa30fff63c01ccd30faaad39d766e1505.zip
Ninja-85ff781fa30fff63c01ccd30faaad39d766e1505.tar.gz
Ninja-85ff781fa30fff63c01ccd30faaad39d766e1505.tar.bz2
Implement cleanup-on-interrupt
This causes us to clean up by deleting any output files belonging to currently-running commands before we quit if we are interrupted (either by Ctrl-C or by a command failing). Fixes issue #110.
Diffstat (limited to 'src/build.cc')
-rw-r--r--src/build.cc76
1 files changed, 59 insertions, 17 deletions
diff --git a/src/build.cc b/src/build.cc
index 8c9981c..4c15de9 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -396,35 +396,52 @@ struct RealCommandRunner : public CommandRunner {
virtual ~RealCommandRunner() {}
virtual bool CanRunMore();
virtual bool StartCommand(Edge* edge);
- virtual Edge* WaitForCommand(bool* success, string* output);
+ virtual Edge* WaitForCommand(ExitStatus* status, string* output);
+ virtual vector<Edge*> GetActiveEdges();
+ virtual void Abort();
const BuildConfig& config_;
SubprocessSet subprocs_;
map<Subprocess*, Edge*> subproc_to_edge_;
};
+vector<Edge*> RealCommandRunner::GetActiveEdges() {
+ vector<Edge*> edges;
+ for (map<Subprocess*, Edge*>::iterator i = subproc_to_edge_.begin();
+ i != subproc_to_edge_.end(); ++i)
+ edges.push_back(i->second);
+ return edges;
+}
+
+void RealCommandRunner::Abort() {
+ subprocs_.Clear();
+}
+
bool RealCommandRunner::CanRunMore() {
return ((int)subprocs_.running_.size()) < config_.parallelism;
}
bool RealCommandRunner::StartCommand(Edge* edge) {
string command = edge->EvaluateCommand();
- Subprocess* subproc = new Subprocess;
- subproc_to_edge_.insert(make_pair(subproc, edge));
- if (!subproc->Start(&subprocs_, command))
+ Subprocess* subproc = subprocs_.Add(command);
+ if (!subproc)
return false;
-
- subprocs_.Add(subproc);
+ subproc_to_edge_.insert(make_pair(subproc, edge));
+
return true;
}
-Edge* RealCommandRunner::WaitForCommand(bool* success, string* output) {
+Edge* RealCommandRunner::WaitForCommand(ExitStatus* status, string* output) {
Subprocess* subproc;
while ((subproc = subprocs_.NextFinished()) == NULL) {
- subprocs_.DoWork();
+ bool interrupted = subprocs_.DoWork();
+ if (interrupted) {
+ *status = ExitInterrupted;
+ return 0;
+ }
}
- *success = subproc->Finish();
+ *status = subproc->Finish();
*output = subproc->GetOutput();
map<Subprocess*, Edge*>::iterator i = subproc_to_edge_.find(subproc);
@@ -445,10 +462,12 @@ struct DryRunCommandRunner : public CommandRunner {
finished_.push(edge);
return true;
}
- virtual Edge* WaitForCommand(bool* success, string* output) {
- if (finished_.empty())
+ virtual Edge* WaitForCommand(ExitStatus* status, string* /* output */) {
+ if (finished_.empty()) {
+ *status = ExitFailure;
return NULL;
- *success = true;
+ }
+ *status = ExitSuccess;
Edge* edge = finished_.front();
finished_.pop();
return edge;
@@ -461,13 +480,29 @@ Builder::Builder(State* state, const BuildConfig& config)
: state_(state), config_(config) {
disk_interface_ = new RealDiskInterface;
if (config.dry_run)
- command_runner_ = new DryRunCommandRunner;
+ command_runner_.reset(new DryRunCommandRunner);
else
- command_runner_ = new RealCommandRunner(config);
+ command_runner_.reset(new RealCommandRunner(config));
status_ = new BuildStatus(config);
log_ = state->build_log_;
}
+Builder::~Builder() {
+ if (command_runner_.get()) {
+ vector<Edge*> active_edges = command_runner_->GetActiveEdges();
+ command_runner_->Abort();
+
+ for (vector<Edge*>::iterator i = active_edges.begin();
+ i != active_edges.end(); ++i) {
+ for (vector<Node*>::iterator ni = (*i)->outputs_.begin();
+ ni != (*i)->outputs_.end(); ++ni)
+ disk_interface_->RemoveFile((*ni)->path());
+ if (!(*i)->rule_->depfile_.empty())
+ disk_interface_->RemoveFile((*i)->EvaluateDepFile());
+ }
+ }
+}
+
Node* Builder::AddTarget(const string& name, string* err) {
Node* node = state_->LookupNode(name);
if (!node) {
@@ -533,10 +568,11 @@ bool Builder::Build(string* err) {
// See if we can reap any finished commands.
if (pending_commands) {
- bool success;
+ ExitStatus status;
string output;
- Edge* edge;
- if ((edge = command_runner_->WaitForCommand(&success, &output))) {
+ Edge* edge = command_runner_->WaitForCommand(&status, &output);
+ if (edge && status != ExitInterrupted) {
+ bool success = (status == ExitSuccess);
--pending_commands;
FinishEdge(edge, success, output);
if (!success) {
@@ -552,6 +588,12 @@ bool Builder::Build(string* err) {
// We made some progress; start the main loop over.
continue;
}
+
+ if (status == ExitInterrupted) {
+ status_->BuildFinished();
+ *err = "interrupted by user";
+ return false;
+ }
}
// If we get here, we can neither enqueue new commands nor are any running.