Cleaner::Cleaner(State* state, const BuildConfig& config)
: state_(state)
- , verbose_(config.verbosity == BuildConfig::VERBOSE || config.dry_run)
- , dry_run_(config.dry_run)
+ , config_(config)
, removed_()
+ , cleaned_files_count_(0)
+ , disk_interface_(new RealDiskInterface)
+{
+}
+
+Cleaner::Cleaner(State* state,
+ const BuildConfig& config,
+ DiskInterface* disk_interface)
+ : state_(state)
+ , config_(config)
+ , removed_()
+ , cleaned_files_count_(0)
+ , disk_interface_(disk_interface)
{
}
bool Cleaner::RemoveFile(const string& path) {
- if (remove(path.c_str()) < 0) {
- switch (errno) {
- case ENOENT:
- return false;
- default:
- Error("remove(%s): %s", path.c_str(), strerror(errno));
- return false;
- }
- } else {
- return true;
- }
+ return disk_interface_->RemoveFile(path);
}
bool Cleaner::FileExists(const string& path) {
- struct stat st;
- if (stat(path.c_str(), &st) < 0) {
- switch (errno) {
- case ENOENT:
- return false;
- default:
- Error("stat(%s): %s", path.c_str(), strerror(errno));
- return false;
- }
- } else {
- return true;
- }
+ return disk_interface_->Stat(path) > 0;
}
void Cleaner::Report(const string& path) {
- if (verbose_)
+ ++cleaned_files_count_;
+ if (IsVerbose())
printf("Remove %s\n", path.c_str());
}
void Cleaner::Remove(const string& path) {
if (!IsAlreadyRemoved(path)) {
removed_.insert(path);
- if (dry_run_) {
+ if (config_.dry_run) {
if (FileExists(path))
Report(path);
} else {
}
void Cleaner::PrintHeader() {
+ if (config_.verbosity == BuildConfig::QUIET)
+ return;
printf("Cleaning...");
- if (verbose_)
+ if (IsVerbose())
printf("\n");
else
printf(" ");
}
void Cleaner::PrintFooter() {
- printf("%d files.\n", (int)removed_.size());
+ if (config_.verbosity == BuildConfig::QUIET)
+ return;
+ printf("%d files.\n", cleaned_files_count_);
}
void Cleaner::CleanAll() {
PrintFooter();
}
+int Cleaner::CleanTarget(const char* target) {
+ assert(target);
+ Node* node = state_->LookupNode(target);
+ if (node) {
+ CleanTarget(node);
+ return 0;
+ } else {
+ Error("unknown target '%s'", target);
+ return 1;
+ }
+}
+
int Cleaner::CleanTargets(int target_count, char* targets[]) {
int status = 0;
PrintHeader();
const char* target_name = targets[i];
Node* target = state_->LookupNode(target_name);
if (target) {
- if (verbose_)
+ if (IsVerbose())
printf("Target %s\n", target_name);
DoCleanTarget(target);
} else {
PrintFooter();
}
+int Cleaner::CleanRule(const char* rule) {
+ assert(rule);
+
+ const Rule* r = state_->LookupRule(rule);
+ if (r) {
+ CleanRule(r);
+ return 0;
+ } else {
+ Error("unknown rule '%s'", rule);
+ return 1;
+ }
+}
+
int Cleaner::CleanRules(int rule_count, char* rules[]) {
assert(rules);
const char* rule_name = rules[i];
const Rule* rule = state_->LookupRule(rule_name);
if (rule) {
- if (verbose_)
+ if (IsVerbose())
printf("Rule %s\n", rule_name);
DoCleanRule(rule);
} else {
--- /dev/null
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "clean.h"
+#include "build.h"
+
+#include "test.h"
+
+struct CleanTest : public StateTestWithBuiltinRules {
+ VirtualFileSystem fs_;
+ BuildConfig config_;
+ virtual void SetUp() {
+ config_.verbosity = BuildConfig::QUIET;
+ }
+};
+
+TEST_F(CleanTest, CleanAll) {
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build in1: cat src1\n"
+"build out1: cat in1\n"
+"build in2: cat src2\n"
+"build out2: cat in2\n"));
+ fs_.Create("in1", 1, "");
+ fs_.Create("out1", 1, "");
+ fs_.Create("in2", 1, "");
+ fs_.Create("out2", 1, "");
+
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ cleaner.CleanAll();
+ EXPECT_EQ(4, cleaner.cleaned_files_count());
+ EXPECT_EQ(4, fs_.files_removed_.size());
+ }
+
+ // Check they are removed.
+ EXPECT_EQ(0, fs_.Stat("in1"));
+ EXPECT_EQ(0, fs_.Stat("out1"));
+ EXPECT_EQ(0, fs_.Stat("in2"));
+ EXPECT_EQ(0, fs_.Stat("out2"));
+ fs_.files_removed_.clear();
+
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ cleaner.CleanAll();
+ EXPECT_EQ(0, cleaner.cleaned_files_count());
+ EXPECT_EQ(0, fs_.files_removed_.size());
+ }
+}
+
+TEST_F(CleanTest, CleanAllDryRun) {
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build in1: cat src1\n"
+"build out1: cat in1\n"
+"build in2: cat src2\n"
+"build out2: cat in2\n"));
+ fs_.Create("in1", 1, "");
+ fs_.Create("out1", 1, "");
+ fs_.Create("in2", 1, "");
+ fs_.Create("out2", 1, "");
+
+ config_.dry_run = true;
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ cleaner.CleanAll();
+ EXPECT_EQ(4, cleaner.cleaned_files_count());
+ EXPECT_EQ(0, fs_.files_removed_.size());
+ }
+
+ // Check they are not removed.
+ EXPECT_NE(0, fs_.Stat("in1"));
+ EXPECT_NE(0, fs_.Stat("out1"));
+ EXPECT_NE(0, fs_.Stat("in2"));
+ EXPECT_NE(0, fs_.Stat("out2"));
+ fs_.files_removed_.clear();
+
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ cleaner.CleanAll();
+ EXPECT_EQ(4, cleaner.cleaned_files_count());
+ EXPECT_EQ(0, fs_.files_removed_.size());
+ }
+}
+
+TEST_F(CleanTest, CleanTarget) {
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build in1: cat src1\n"
+"build out1: cat in1\n"
+"build in2: cat src2\n"
+"build out2: cat in2\n"));
+ fs_.Create("in1", 1, "");
+ fs_.Create("out1", 1, "");
+ fs_.Create("in2", 1, "");
+ fs_.Create("out2", 1, "");
+
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ ASSERT_EQ(0, cleaner.CleanTarget("out1"));
+ EXPECT_EQ(2, cleaner.cleaned_files_count());
+ EXPECT_EQ(2, fs_.files_removed_.size());
+ }
+
+ // Check they are removed.
+ EXPECT_EQ(0, fs_.Stat("in1"));
+ EXPECT_EQ(0, fs_.Stat("out1"));
+ EXPECT_NE(0, fs_.Stat("in2"));
+ EXPECT_NE(0, fs_.Stat("out2"));
+ fs_.files_removed_.clear();
+
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ ASSERT_EQ(0, cleaner.CleanTarget("out1"));
+ EXPECT_EQ(0, cleaner.cleaned_files_count());
+ EXPECT_EQ(0, fs_.files_removed_.size());
+ }
+}
+
+TEST_F(CleanTest, CleanTargetDryRun) {
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build in1: cat src1\n"
+"build out1: cat in1\n"
+"build in2: cat src2\n"
+"build out2: cat in2\n"));
+ fs_.Create("in1", 1, "");
+ fs_.Create("out1", 1, "");
+ fs_.Create("in2", 1, "");
+ fs_.Create("out2", 1, "");
+
+ config_.dry_run = true;
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ ASSERT_EQ(0, cleaner.CleanTarget("out1"));
+ EXPECT_EQ(2, cleaner.cleaned_files_count());
+ EXPECT_EQ(0, fs_.files_removed_.size());
+ }
+
+ // Check they are removed.
+ EXPECT_NE(0, fs_.Stat("in1"));
+ EXPECT_NE(0, fs_.Stat("out1"));
+ EXPECT_NE(0, fs_.Stat("in2"));
+ EXPECT_NE(0, fs_.Stat("out2"));
+ fs_.files_removed_.clear();
+
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ ASSERT_EQ(0, cleaner.CleanTarget("out1"));
+ EXPECT_EQ(2, cleaner.cleaned_files_count());
+ EXPECT_EQ(0, fs_.files_removed_.size());
+ }
+}
+
+TEST_F(CleanTest, CleanRule) {
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cat_e\n"
+" command = cat -e $in > $out\n"
+"build in1: cat_e src1\n"
+"build out1: cat in1\n"
+"build in2: cat_e src2\n"
+"build out2: cat in2\n"));
+ fs_.Create("in1", 1, "");
+ fs_.Create("out1", 1, "");
+ fs_.Create("in2", 1, "");
+ fs_.Create("out2", 1, "");
+
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
+ EXPECT_EQ(2, cleaner.cleaned_files_count());
+ EXPECT_EQ(2, fs_.files_removed_.size());
+ }
+
+ // Check they are removed.
+ EXPECT_EQ(0, fs_.Stat("in1"));
+ EXPECT_NE(0, fs_.Stat("out1"));
+ EXPECT_EQ(0, fs_.Stat("in2"));
+ EXPECT_NE(0, fs_.Stat("out2"));
+ fs_.files_removed_.clear();
+
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
+ EXPECT_EQ(0, cleaner.cleaned_files_count());
+ EXPECT_EQ(0, fs_.files_removed_.size());
+ }
+}
+
+TEST_F(CleanTest, CleanRuleDryRun) {
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cat_e\n"
+" command = cat -e $in > $out\n"
+"build in1: cat_e src1\n"
+"build out1: cat in1\n"
+"build in2: cat_e src2\n"
+"build out2: cat in2\n"));
+ fs_.Create("in1", 1, "");
+ fs_.Create("out1", 1, "");
+ fs_.Create("in2", 1, "");
+ fs_.Create("out2", 1, "");
+
+ config_.dry_run = true;
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
+ EXPECT_EQ(2, cleaner.cleaned_files_count());
+ EXPECT_EQ(0, fs_.files_removed_.size());
+ }
+
+ // Check they are removed.
+ EXPECT_NE(0, fs_.Stat("in1"));
+ EXPECT_NE(0, fs_.Stat("out1"));
+ EXPECT_NE(0, fs_.Stat("in2"));
+ EXPECT_NE(0, fs_.Stat("out2"));
+ fs_.files_removed_.clear();
+
+ {
+ Cleaner cleaner(&state_, config_, &fs_);
+
+ ASSERT_EQ(0, cleaner.cleaned_files_count());
+ ASSERT_EQ(0, cleaner.CleanRule("cat_e"));
+ EXPECT_EQ(2, cleaner.cleaned_files_count());
+ EXPECT_EQ(0, fs_.files_removed_.size());
+ }
+}