summaryrefslogtreecommitdiffstats
path: root/src/build_log.cc
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2010-12-16 19:52:24 (GMT)
committerEvan Martin <martine@danga.com>2010-12-23 19:20:33 (GMT)
commit9a6fd1a97b64ea1245a7343aee1e584c401a391b (patch)
tree73e83a65f9c157ffdce98d45969cfa7c4f18757e /src/build_log.cc
parent12e36285ae52feca764e8fb2a417a87b913fe3e6 (diff)
downloadNinja-9a6fd1a97b64ea1245a7343aee1e584c401a391b.zip
Ninja-9a6fd1a97b64ea1245a7343aee1e584c401a391b.tar.gz
Ninja-9a6fd1a97b64ea1245a7343aee1e584c401a391b.tar.bz2
add a class for logging builds (commands + timing)
Diffstat (limited to 'src/build_log.cc')
-rw-r--r--src/build_log.cc89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/build_log.cc b/src/build_log.cc
new file mode 100644
index 0000000..06db0e6
--- /dev/null
+++ b/src/build_log.cc
@@ -0,0 +1,89 @@
+#include "build_log.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ninja.h"
+
+// Implementation details:
+// Each run's log appends to the log file.
+// To load, we run through all log entries in series, throwing away
+// older runs.
+// XXX figure out recompaction strategy
+
+bool BuildLog::OpenForWrite(const string& path, string* err) {
+ log_file_ = fopen(path.c_str(), "ab");
+ if (!log_file_) {
+ *err = strerror(errno);
+ return false;
+ }
+ setlinebuf(log_file_);
+ return true;
+}
+
+void BuildLog::RecordCommand(Edge* edge, int time_ms) {
+ const string command = edge->EvaluateCommand();
+ for (vector<Node*>::iterator out = edge->outputs_.begin();
+ out != edge->outputs_.end(); ++out) {
+ const string& path = (*out)->file_->path_;
+ Log::iterator i = log_.find(path);
+ LogEntry* log_entry;
+ if (i != log_.end()) {
+ log_entry = i->second;
+ } else {
+ log_entry = new LogEntry;
+ log_.insert(make_pair(path, log_entry));
+ }
+ log_entry->output = path;
+ log_entry->command = command;
+ log_entry->time_ms = time_ms;
+
+ fprintf(log_file_, "%d %s %s\n", time_ms, path.c_str(), command.c_str());
+ }
+}
+
+void BuildLog::Close() {
+ fclose(log_file_);
+ log_file_ = NULL;
+}
+
+// Load the on-disk log.
+bool BuildLog::Load(const string& path, string* err) {
+ FILE* file = fopen(path.c_str(), "r");
+ if (!file) {
+ *err = strerror(errno);
+ return false;
+ }
+
+ char buf[4 << 10];
+ while (fgets(buf, sizeof(buf), file)) {
+ char* start = buf;
+ char* end = strchr(start, ' ');
+ if (!end)
+ continue;
+
+ LogEntry* entry = new LogEntry;
+ *end = 0;
+ entry->time_ms = atoi(start);
+
+ start = end + 1;
+ end = strchr(start, ' ');
+ entry->output = string(start, end - start);
+
+ start = end + 1;
+ end = strchr(start, '\n');
+ entry->command = string(start, end - start);
+ log_.insert(make_pair(entry->output, entry));
+ }
+
+ return true;
+}
+
+// Lookup a previously-run command by its output path.
+BuildLog::LogEntry* BuildLog::LookupByOutput(const string& path) {
+ Log::iterator i = log_.find(path);
+ if (i != log_.end())
+ return i->second;
+ return NULL;
+}