From 858386d8415d2ee932fe3c01ebfbe5e0737f94a3 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 3 Feb 2016 13:20:00 -0500 Subject: Expose more details in FileReader::ReadFile signature Return a status so callers can distinguish a missing file from an empty file. This allows our VirtualFileSystem test infrastructure to report as missing any file for which it has no entry. --- src/build.cc | 12 ++++++++++-- src/disk_interface.cc | 14 +++++++------- src/disk_interface.h | 15 ++++++++++++--- src/disk_interface_test.cc | 16 +++++++++++----- src/graph.cc | 11 +++++++++-- src/test.cc | 13 +++++++++---- src/test.h | 2 +- 7 files changed, 59 insertions(+), 24 deletions(-) diff --git a/src/build.cc b/src/build.cc index ab2460a..45d3f32 100644 --- a/src/build.cc +++ b/src/build.cc @@ -871,9 +871,17 @@ bool Builder::ExtractDeps(CommandRunner::Result* result, return false; } - string content = disk_interface_->ReadFile(depfile, err); - if (!err->empty()) + // Read depfile content. Treat a missing depfile as empty. + string content; + switch (disk_interface_->ReadFile(depfile, &content, err)) { + case DiskInterface::Okay: + break; + case DiskInterface::NotFound: + err->clear(); + break; + case DiskInterface::OtherError: return false; + } if (content.empty()) return true; diff --git a/src/disk_interface.cc b/src/disk_interface.cc index 70282c0..451a9b4 100644 --- a/src/disk_interface.cc +++ b/src/disk_interface.cc @@ -229,14 +229,14 @@ bool RealDiskInterface::MakeDir(const string& path) { return true; } -string RealDiskInterface::ReadFile(const string& path, string* err) { - string contents; - int ret = ::ReadFile(path, &contents, err); - if (ret == -ENOENT) { - // Swallow ENOENT. - err->clear(); +FileReader::Status RealDiskInterface::ReadFile(const string& path, + string* contents, + string* err) { + switch (::ReadFile(path, contents, err)) { + case 0: return Okay; + case -ENOENT: return NotFound; + default: return OtherError; } - return contents; } int RealDiskInterface::RemoveFile(const string& path) { diff --git a/src/disk_interface.h b/src/disk_interface.h index 94f25dc..145e089 100644 --- a/src/disk_interface.h +++ b/src/disk_interface.h @@ -26,8 +26,17 @@ using namespace std; struct FileReader { virtual ~FileReader() {} - /// Read a file to a string. Fill in |err| on error. - virtual string ReadFile(const string& path, string* err) = 0; + /// Result of ReadFile. + enum Status { + Okay, + NotFound, + OtherError + }; + + /// Read and store in given string. On success, return Okay. + /// On error, return another Status and fill |err|. + virtual Status ReadFile(const string& path, string* contents, + string* err) = 0; }; /// Interface for accessing the disk. @@ -69,7 +78,7 @@ struct RealDiskInterface : public DiskInterface { virtual TimeStamp Stat(const string& path, string* err) const; virtual bool MakeDir(const string& path); virtual bool WriteFile(const string& path, const string& contents); - virtual string ReadFile(const string& path, string* err); + virtual Status ReadFile(const string& path, string* contents, string* err); virtual int RemoveFile(const string& path); /// Whether stat information can be cached. Only has an effect on Windows. diff --git a/src/disk_interface_test.cc b/src/disk_interface_test.cc index 9d210b4..7187bdf 100644 --- a/src/disk_interface_test.cc +++ b/src/disk_interface_test.cc @@ -157,8 +157,12 @@ TEST_F(DiskInterfaceTest, StatCache) { TEST_F(DiskInterfaceTest, ReadFile) { string err; - EXPECT_EQ("", disk_.ReadFile("foobar", &err)); - EXPECT_EQ("", err); + std::string content; + ASSERT_EQ(DiskInterface::NotFound, + disk_.ReadFile("foobar", &content, &err)); + EXPECT_EQ("", content); + EXPECT_NE("", err); // actual value is platform-specific + err.clear(); const char* kTestFile = "testfile"; FILE* f = fopen(kTestFile, "wb"); @@ -167,7 +171,9 @@ TEST_F(DiskInterfaceTest, ReadFile) { fprintf(f, "%s", kTestContent); ASSERT_EQ(0, fclose(f)); - EXPECT_EQ(kTestContent, disk_.ReadFile(kTestFile, &err)); + ASSERT_EQ(DiskInterface::Okay, + disk_.ReadFile(kTestFile, &content, &err)); + EXPECT_EQ(kTestContent, content); EXPECT_EQ("", err); } @@ -208,9 +214,9 @@ struct StatTest : public StateTestWithBuiltinRules, assert(false); return false; } - virtual string ReadFile(const string& path, string* err) { + virtual Status ReadFile(const string& path, string* contents, string* err) { assert(false); - return ""; + return NotFound; } virtual int RemoveFile(const string& path) { assert(false); diff --git a/src/graph.cc b/src/graph.cc index 9e65675..98f1461 100644 --- a/src/graph.cc +++ b/src/graph.cc @@ -395,8 +395,15 @@ bool ImplicitDepLoader::LoadDeps(Edge* edge, string* err) { bool ImplicitDepLoader::LoadDepFile(Edge* edge, const string& path, string* err) { METRIC_RECORD("depfile load"); - string content = disk_interface_->ReadFile(path, err); - if (!err->empty()) { + // Read depfile content. Treat a missing depfile as empty. + string content; + switch (disk_interface_->ReadFile(path, &content, err)) { + case DiskInterface::Okay: + break; + case DiskInterface::NotFound: + err->clear(); + break; + case DiskInterface::OtherError: *err = "loading '" + path + "': " + *err; return false; } diff --git a/src/test.cc b/src/test.cc index 841ce04..53bfc48 100644 --- a/src/test.cc +++ b/src/test.cc @@ -164,12 +164,17 @@ bool VirtualFileSystem::MakeDir(const string& path) { return true; // success } -string VirtualFileSystem::ReadFile(const string& path, string* err) { +FileReader::Status VirtualFileSystem::ReadFile(const string& path, + string* contents, + string* err) { files_read_.push_back(path); FileMap::iterator i = files_.find(path); - if (i != files_.end()) - return i->second.contents; - return ""; + if (i != files_.end()) { + *contents = i->second.contents; + return Okay; + } + *err = strerror(ENOENT); + return NotFound; } int VirtualFileSystem::RemoveFile(const string& path) { diff --git a/src/test.h b/src/test.h index 156e68a..488c243 100644 --- a/src/test.h +++ b/src/test.h @@ -145,7 +145,7 @@ struct VirtualFileSystem : public DiskInterface { virtual TimeStamp Stat(const string& path, string* err) const; virtual bool WriteFile(const string& path, const string& contents); virtual bool MakeDir(const string& path); - virtual string ReadFile(const string& path, string* err); + virtual Status ReadFile(const string& path, string* contents, string* err); virtual int RemoveFile(const string& path); /// An entry for a single in-memory file. -- cgit v0.12