virtual int Stat(const string& path);
// Create a directory, returning false on failure.
virtual bool MakeDir(const string& path);
+ // Read a file to a string. Fill in |err| on error.
+ virtual string ReadFile(const string& path, string* err);
// Create all the parent directories for path; like mkdir -p `basename path`.
bool MakeDirs(const string& path);
#include <stdio.h>
#include <string.h>
+string ReadFile(const string& path, string* err) {
+ FILE* f = fopen(path.c_str(), "r");
+ if (!f) {
+ err->assign(strerror(errno));
+ return false;
+ }
+
+ string text;
+ char buf[64 << 10];
+ size_t len;
+ while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
+ text.append(buf, len);
+ }
+ if (ferror(f)) {
+ err->assign(strerror(errno));
+ text = "";
+ }
+ fclose(f);
+ return text;
+}
+
int DiskInterface::Stat(const string& path) {
struct stat st;
if (stat(path.c_str(), &st) < 0) {
return MakeDir(dir);
}
+string DiskInterface::ReadFile(const string& path, string* err) {
+ return ::ReadFile(path, err);
+}
+
bool DiskInterface::MakeDir(const string& path) {
if (mkdir(path.c_str(), 0777) < 0) {
fprintf(stderr, "mkdir(%s): %s\n", path.c_str(), strerror(errno));
Edge() : rule_(NULL), env_(NULL) {}
void MarkDirty(Node* node);
- void RecomputeDirty(DiskInterface* disk_interface);
+ void RecomputeDirty(State* state, DiskInterface* disk_interface);
string EvaluateCommand(); // XXX move to env, take env ptr
bool LoadDepFile(State* state, string* err);
(*i)->MarkDirty(this);
}
-void Edge::RecomputeDirty(DiskInterface* disk_interface) {
+void Edge::RecomputeDirty(State* state, DiskInterface* disk_interface) {
bool dirty = false;
time_t most_recent_input = 1;
for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) {
if ((*i)->file_->StatIfNecessary(disk_interface)) {
if (Edge* edge = (*i)->in_edge_)
- edge->RecomputeDirty(disk_interface);
+ edge->RecomputeDirty(state, disk_interface);
else
(*i)->dirty_ = !(*i)->file_->exists();
}
struct Builder {
Builder(State* state)
- : plan_(state), disk_interface_(&default_disk_interface_) {}
+ : state_(state), plan_(state), disk_interface_(&default_disk_interface_) {}
virtual ~Builder() {}
Node* AddTarget(const string& name, string* err) {
}
node->file_->StatIfNecessary(disk_interface_);
if (node->in_edge_)
- node->in_edge_->RecomputeDirty(disk_interface_);
+ node->in_edge_->RecomputeDirty(state_, disk_interface_);
if (!node->dirty_) {
*err = "target is clean; nothing to do";
return NULL;
}
bool Build(Shell* shell, string* err);
+ State* state_;
Plan plan_;
DiskInterface default_disk_interface_;
DiskInterface* disk_interface_;
out->file_->Stat(this);
ASSERT_EQ(1, stats_.size());
Edge* edge = out->in_edge_;
- edge->RecomputeDirty(this);
+ edge->RecomputeDirty(NULL, this);
ASSERT_EQ(2, stats_.size());
ASSERT_EQ("out", stats_[0]);
ASSERT_EQ("in", stats_[1]);
out->file_->Stat(this);
ASSERT_EQ(1, stats_.size());
Edge* edge = out->in_edge_;
- edge->RecomputeDirty(this);
+ edge->RecomputeDirty(NULL, this);
ASSERT_EQ(3, stats_.size());
ASSERT_EQ("out", stats_[0]);
ASSERT_TRUE(GetNode("out")->dirty_);
out->file_->Stat(this);
ASSERT_EQ(1, stats_.size());
Edge* edge = out->in_edge_;
- edge->RecomputeDirty(this);
+ edge->RecomputeDirty(NULL, this);
ASSERT_EQ(1 + 6, stats_.size());
ASSERT_EQ("mid1", stats_[1]);
ASSERT_TRUE(GetNode("mid1")->dirty_);
out->file_->Stat(this);
ASSERT_EQ(1, stats_.size());
Edge* edge = out->in_edge_;
- edge->RecomputeDirty(this);
+ edge->RecomputeDirty(NULL, this);
ASSERT_FALSE(GetNode("in")->dirty_);
ASSERT_TRUE(GetNode("mid")->dirty_);
ASSERT_TRUE(GetNode("out")->dirty_);