diff --git a/src/build_test.cc b/src/build_test.cc index bcc9f36454..d4885f869c 100644 --- a/src/build_test.cc +++ b/src/build_test.cc @@ -605,7 +605,7 @@ void BuildTest::RebuildTarget(const string& target, const char* manifest, pbuild_log = &build_log; } - DepsLog deps_log, *pdeps_log = NULL; + DepsLog deps_log(disk_interface), *pdeps_log = NULL; if (deps_path) { ASSERT_TRUE(deps_log.Load(deps_path, pstate, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_path, &err)); @@ -2330,7 +2330,8 @@ struct BuildWithQueryDepsLogTest : public BuildTest { ScopedTempDir temp_dir_; ScopedFilePath deps_log_file_; - DepsLog log_; + SystemDiskInterface disk_interface_; + DepsLog log_{ disk_interface_ }; }; /// Test a MSVC-style deps log with multiple outputs. @@ -2553,13 +2554,15 @@ TEST_F(BuildWithDepsLogTest, Straightforward) { " deps = gcc\n" " depfile = in1.d\n"; + SystemDiskInterface disk_interface; + { State state; ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); // Run the build once, everything should be ok. - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -2589,7 +2592,7 @@ TEST_F(BuildWithDepsLogTest, Straightforward) { fs_.Create("in2", ""); // Run the build again. - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); @@ -2620,6 +2623,9 @@ TEST_F(BuildWithDepsLogTest, ObsoleteDeps) { "build out: cat in1\n" " deps = gcc\n" " depfile = in1.d\n"; + + SystemDiskInterface disk_interface; + { // Run an ordinary build that gathers dependencies. fs_.Create("in1", ""); @@ -2630,7 +2636,7 @@ TEST_F(BuildWithDepsLogTest, ObsoleteDeps) { ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); // Run the build once, everything should be ok. - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -2659,7 +2665,7 @@ TEST_F(BuildWithDepsLogTest, ObsoleteDeps) { ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); @@ -2730,7 +2736,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceCondition) { ASSERT_TRUE(build_log.OpenForWrite(build_log_file_.path(), *this, &err)) << err; - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); @@ -2813,7 +2819,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceConditionWithDepFile) { ASSERT_TRUE(build_log.Load(build_log_file_.path(), &err)); ASSERT_TRUE(build_log.OpenForWrite(build_log_file_.path(), *this, &err)); - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); @@ -2954,13 +2960,16 @@ TEST_F(BuildWithDepsLogTest, RestatDepfileDependencyDepsLog) { "build out: cat in1\n" " deps = gcc\n" " depfile = in1.d\n"; + + SystemDiskInterface disk_interface; + { State state; ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); // Run the build once, everything should be ok. - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -2986,7 +2995,7 @@ TEST_F(BuildWithDepsLogTest, RestatDepfileDependencyDepsLog) { fs_.Create("header.in", ""); // Run the build again. - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); @@ -3014,12 +3023,14 @@ TEST_F(BuildWithDepsLogTest, DepFileOKDepsLog) { fs_.Create("foo.c", ""); + SystemDiskInterface disk_interface; + { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); // Run the build once, everything should be ok. - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -3039,7 +3050,7 @@ TEST_F(BuildWithDepsLogTest, DepFileOKDepsLog) { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -3091,7 +3102,7 @@ TEST_F(BuildWithDepsLogTest, DiscoveredDepDuringBuildChanged) { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -3114,7 +3125,7 @@ TEST_F(BuildWithDepsLogTest, DiscoveredDepDuringBuildChanged) { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -3137,7 +3148,7 @@ TEST_F(BuildWithDepsLogTest, DiscoveredDepDuringBuildChanged) { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -3161,12 +3172,14 @@ TEST_F(BuildWithDepsLogTest, DepFileDepsLogCanonicalize) { fs_.Create("x/y/z/foo.c", ""); + SystemDiskInterface disk_interface; + { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); // Run the build once, everything should be ok. - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -3188,7 +3201,7 @@ TEST_F(BuildWithDepsLogTest, DepFileDepsLogCanonicalize) { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -4258,6 +4271,8 @@ TEST_F(BuildWithDepsLogTest, ValidationThroughDepfile) { string err; + SystemDiskInterface disk_interface; + { fs_.Create("in", ""); fs_.Create("in2", ""); @@ -4268,7 +4283,7 @@ TEST_F(BuildWithDepsLogTest, ValidationThroughDepfile) { ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); @@ -4303,7 +4318,7 @@ TEST_F(BuildWithDepsLogTest, ValidationThroughDepfile) { ASSERT_NO_FATAL_FAILURE(AddCatRule(&state)); ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest)); - DepsLog deps_log; + DepsLog deps_log(disk_interface); ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err)); ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err)); ASSERT_EQ("", err); diff --git a/src/deps_log.cc b/src/deps_log.cc index b28736ad3d..6046cd3cfd 100644 --- a/src/deps_log.cc +++ b/src/deps_log.cc @@ -41,6 +41,9 @@ const int kCurrentVersion = 4; // internal buffers having to have this size. const unsigned kMaxRecordSize = (1 << 19) - 1; +DepsLog::DepsLog(DiskInterface& disk_interface) + : disk_interface_(&disk_interface) {} + DepsLog::~DepsLog() { Close(); } @@ -152,7 +155,7 @@ void DepsLog::Close() { LoadStatus DepsLog::Load(const string& path, State* state, string* err) { METRIC_RECORD(".ninja_deps load"); char buf[kMaxRecordSize + 1]; - FILE* f = fopen(path.c_str(), "rb"); + FILE* f = disk_interface_->OpenFile(path, "rb"); if (!f) { if (errno == ENOENT) return LOAD_NOT_FOUND; @@ -175,7 +178,7 @@ LoadStatus DepsLog::Load(const string& path, State* state, string* err) { else *err = "bad deps log signature or version; starting over"; fclose(f); - unlink(path.c_str()); + disk_interface_->RemoveFile(path); // Don't report this as a failure. An empty deps log will cause // us to rebuild the outputs anyway. return LOAD_SUCCESS; @@ -312,13 +315,13 @@ bool DepsLog::Recompact(const string& path, string* err) { METRIC_RECORD(".ninja_deps recompact"); Close(); - string temp_path = path + ".recompact"; + std::string temp_path = path + ".recompact"; // OpenForWrite() opens for append. Make sure it's not appending to a // left-over file from a previous recompaction attempt that crashed somehow. - unlink(temp_path.c_str()); + disk_interface_->RemoveFile(temp_path); - DepsLog new_log; + DepsLog new_log(*disk_interface_); if (!new_log.OpenForWrite(temp_path, err)) return false; @@ -348,12 +351,12 @@ bool DepsLog::Recompact(const string& path, string* err) { deps_.swap(new_log.deps_); nodes_.swap(new_log.nodes_); - if (unlink(path.c_str()) < 0) { + if (disk_interface_->RemoveFile(path) < 0) { *err = strerror(errno); return false; } - if (rename(temp_path.c_str(), path.c_str()) < 0) { + if (!disk_interface_->RenameFile(temp_path, path)) { *err = strerror(errno); return false; } @@ -420,7 +423,7 @@ bool DepsLog::OpenForWriteIfNeeded() { if (file_path_.empty()) { return true; } - file_ = fopen(file_path_.c_str(), "ab"); + file_ = disk_interface_->OpenFile(file_path_, "ab"); if (!file_) { return false; } diff --git a/src/deps_log.h b/src/deps_log.h index 2a1b188906..f4aa40638c 100644 --- a/src/deps_log.h +++ b/src/deps_log.h @@ -15,11 +15,13 @@ #ifndef NINJA_DEPS_LOG_H_ #define NINJA_DEPS_LOG_H_ +#include + +#include #include #include -#include - +#include "disk_interface.h" #include "load_status.h" #include "timestamp.h" @@ -66,7 +68,13 @@ struct State; /// wins, allowing updates to just be appended to the file. A separate /// repacking step can run occasionally to remove dead records. struct DepsLog { - DepsLog() : needs_recompaction_(false), file_(NULL) {} + /// No default constructor. + DepsLog() = delete; + + /// Constructor takes a DiskInterface reference. + DepsLog(DiskInterface& disk_interface); + + /// Destructor ~DepsLog(); // Writing (build-time) interface. @@ -114,8 +122,10 @@ struct DepsLog { /// be set. bool OpenForWriteIfNeeded(); - bool needs_recompaction_; - FILE* file_; + DiskInterface* disk_interface_ = nullptr; + + bool needs_recompaction_ = false; + FILE* file_ = nullptr; std::string file_path_; /// Maps id -> Node. diff --git a/src/deps_log_test.cc b/src/deps_log_test.cc index cb1c925532..5ae6fd084a 100644 --- a/src/deps_log_test.cc +++ b/src/deps_log_test.cc @@ -32,16 +32,16 @@ const char kTestFilename[] = "DepsLogTest-tempfile"; struct DepsLogTest : public testing::Test { virtual void SetUp() { // In case a crashing test left a stale file behind. - unlink(kTestFilename); - } - virtual void TearDown() { - unlink(kTestFilename); + disk_interface_.RemoveFile(kTestFilename); } + virtual void TearDown() { disk_interface_.RemoveFile(kTestFilename); } + + SystemDiskInterface disk_interface_; }; TEST_F(DepsLogTest, WriteRead) { State state1; - DepsLog log1; + DepsLog log1(disk_interface_); string err; EXPECT_TRUE(log1.OpenForWrite(kTestFilename, &err)); ASSERT_EQ("", err); @@ -68,7 +68,7 @@ TEST_F(DepsLogTest, WriteRead) { log1.Close(); State state2; - DepsLog log2; + DepsLog log2(disk_interface_); EXPECT_TRUE(log2.Load(kTestFilename, &state2, &err)); ASSERT_EQ("", err); @@ -93,7 +93,7 @@ TEST_F(DepsLogTest, LotsOfDeps) { const int kNumDeps = 100000; // More than 64k. State state1; - DepsLog log1; + DepsLog log1(disk_interface_); string err; EXPECT_TRUE(log1.OpenForWrite(kTestFilename, &err)); ASSERT_EQ("", err); @@ -114,7 +114,7 @@ TEST_F(DepsLogTest, LotsOfDeps) { log1.Close(); State state2; - DepsLog log2; + DepsLog log2(disk_interface_); EXPECT_TRUE(log2.Load(kTestFilename, &state2, &err)); ASSERT_EQ("", err); @@ -128,7 +128,7 @@ TEST_F(DepsLogTest, DoubleEntry) { int file_size; { State state; - DepsLog log; + DepsLog log(disk_interface_); string err; EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err)); ASSERT_EQ("", err); @@ -152,7 +152,7 @@ TEST_F(DepsLogTest, DoubleEntry) { // Now reload the file, and read the same deps. { State state; - DepsLog log; + DepsLog log(disk_interface_); string err; EXPECT_TRUE(log.Load(kTestFilename, &state, &err)); @@ -190,7 +190,7 @@ TEST_F(DepsLogTest, Recompact) { { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, kManifest)); - DepsLog log; + DepsLog log(disk_interface_); string err; ASSERT_TRUE(log.OpenForWrite(kTestFilename, &err)); ASSERT_EQ("", err); @@ -222,7 +222,7 @@ TEST_F(DepsLogTest, Recompact) { { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, kManifest)); - DepsLog log; + DepsLog log(disk_interface_); string err; ASSERT_TRUE(log.Load(kTestFilename, &state, &err)); @@ -252,7 +252,7 @@ TEST_F(DepsLogTest, Recompact) { { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, kManifest)); - DepsLog log; + DepsLog log(disk_interface_); string err; ASSERT_TRUE(log.Load(kTestFilename, &state, &err)); @@ -306,7 +306,7 @@ TEST_F(DepsLogTest, Recompact) { { State state; // Intentionally not parsing kManifest here. - DepsLog log; + DepsLog log(disk_interface_); string err; ASSERT_TRUE(log.Load(kTestFilename, &state, &err)); @@ -362,7 +362,7 @@ TEST_F(DepsLogTest, InvalidHeader) { }; for (size_t i = 0; i < sizeof(kInvalidHeaders) / sizeof(kInvalidHeaders[0]); ++i) { - FILE* deps_log = fopen(kTestFilename, "wb"); + FILE* deps_log = disk_interface_.OpenFile(kTestFilename, "wb"); ASSERT_TRUE(deps_log != NULL); ASSERT_EQ( strlen(kInvalidHeaders[i]), @@ -370,7 +370,7 @@ TEST_F(DepsLogTest, InvalidHeader) { ASSERT_EQ(0 ,fclose(deps_log)); string err; - DepsLog log; + DepsLog log(disk_interface_); State state; ASSERT_TRUE(log.Load(kTestFilename, &state, &err)); EXPECT_EQ("bad deps log signature or version; starting over", err); @@ -382,7 +382,7 @@ TEST_F(DepsLogTest, Truncated) { // Create a file with some entries. { State state; - DepsLog log; + DepsLog log(disk_interface_); string err; EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err)); ASSERT_EQ("", err); @@ -419,7 +419,7 @@ TEST_F(DepsLogTest, Truncated) { ASSERT_TRUE(Truncate(kTestFilename, size, &err)); State state; - DepsLog log; + DepsLog log(disk_interface_); EXPECT_TRUE(log.Load(kTestFilename, &state, &err)); if (!err.empty()) { // At some point the log will be so short as to be unparsable. @@ -446,7 +446,7 @@ TEST_F(DepsLogTest, TruncatedRecovery) { // Create a file with some entries. { State state; - DepsLog log; + DepsLog log(disk_interface_); string err; EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err)); ASSERT_EQ("", err); @@ -480,7 +480,7 @@ TEST_F(DepsLogTest, TruncatedRecovery) { // Load the file again, add an entry. { State state; - DepsLog log; + DepsLog log(disk_interface_); string err; EXPECT_TRUE(log.Load(kTestFilename, &state, &err)); ASSERT_EQ("premature end of file; recovering", err); @@ -505,7 +505,7 @@ TEST_F(DepsLogTest, TruncatedRecovery) { // entry doesn't break things. { State state; - DepsLog log; + DepsLog log(disk_interface_); string err; EXPECT_TRUE(log.Load(kTestFilename, &state, &err)); @@ -517,7 +517,7 @@ TEST_F(DepsLogTest, TruncatedRecovery) { TEST_F(DepsLogTest, ReverseDepsNodes) { State state; - DepsLog log; + DepsLog log(disk_interface_); string err; EXPECT_TRUE(log.OpenForWrite(kTestFilename, &err)); ASSERT_EQ("", err); diff --git a/src/missing_deps_test.cc b/src/missing_deps_test.cc index dae377b49d..bf487dc292 100644 --- a/src/missing_deps_test.cc +++ b/src/missing_deps_test.cc @@ -88,7 +88,8 @@ struct MissingDependencyScannerTest : public testing::Test { MissingDependencyTestDelegate delegate_; Rule generator_rule_; Rule compile_rule_; - DepsLog deps_log_; + SystemDiskInterface disk_interface_; + DepsLog deps_log_{ disk_interface_ }; State state_; VirtualFileSystem filesystem_; MissingDependencyScanner scanner_; diff --git a/src/ninja.cc b/src/ninja.cc index 53bc054aa8..a1a84be963 100644 --- a/src/ninja.cc +++ b/src/ninja.cc @@ -84,9 +84,10 @@ struct Options { /// The Ninja main() loads up a series of data structures; various tools need /// to poke into these, so store them as fields on an object. struct NinjaMain : public BuildLogUser { - NinjaMain(const char* ninja_command, const BuildConfig& config) : - ninja_command_(ninja_command), config_(config), - build_log_(disk_interface_), start_time_millis_(GetTimeMillis()) {} + NinjaMain(const char* ninja_command, const BuildConfig& config) + : ninja_command_(ninja_command), config_(config), + build_log_(disk_interface_), deps_log_(disk_interface_), + start_time_millis_(GetTimeMillis()) {} /// Command line used to run Ninja. const char* ninja_command_;