Ninja
clean.cc
Go to the documentation of this file.
00001 // Copyright 2011 Google Inc. All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //     http://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "clean.h"
00016 
00017 #include <assert.h>
00018 #include <errno.h>
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <sys/stat.h>
00022 
00023 #include "disk_interface.h"
00024 #include "graph.h"
00025 #include "state.h"
00026 #include "util.h"
00027 
00028 Cleaner::Cleaner(State* state, const BuildConfig& config)
00029   : state_(state),
00030     config_(config),
00031     removed_(),
00032     cleaned_files_count_(0),
00033     disk_interface_(new RealDiskInterface),
00034     status_(0) {
00035 }
00036 
00037 Cleaner::Cleaner(State* state,
00038                  const BuildConfig& config,
00039                  DiskInterface* disk_interface)
00040   : state_(state),
00041     config_(config),
00042     removed_(),
00043     cleaned_files_count_(0),
00044     disk_interface_(disk_interface),
00045     status_(0) {
00046 }
00047 
00048 int Cleaner::RemoveFile(const string& path) {
00049   return disk_interface_->RemoveFile(path);
00050 }
00051 
00052 bool Cleaner::FileExists(const string& path) {
00053   return disk_interface_->Stat(path) > 0;
00054 }
00055 
00056 void Cleaner::Report(const string& path) {
00057   ++cleaned_files_count_;
00058   if (IsVerbose())
00059     printf("Remove %s\n", path.c_str());
00060 }
00061 
00062 void Cleaner::Remove(const string& path) {
00063   if (!IsAlreadyRemoved(path)) {
00064     removed_.insert(path);
00065     if (config_.dry_run) {
00066       if (FileExists(path))
00067         Report(path);
00068     } else {
00069       int ret = RemoveFile(path);
00070       if (ret == 0)
00071         Report(path);
00072       else if (ret == -1)
00073         status_ = 1;
00074     }
00075   }
00076 }
00077 
00078 bool Cleaner::IsAlreadyRemoved(const string& path) {
00079   set<string>::iterator i = removed_.find(path);
00080   return (i != removed_.end());
00081 }
00082 
00083 void Cleaner::PrintHeader() {
00084   if (config_.verbosity == BuildConfig::QUIET)
00085     return;
00086   printf("Cleaning...");
00087   if (IsVerbose())
00088     printf("\n");
00089   else
00090     printf(" ");
00091 }
00092 
00093 void Cleaner::PrintFooter() {
00094   if (config_.verbosity == BuildConfig::QUIET)
00095     return;
00096   printf("%d files.\n", cleaned_files_count_);
00097 }
00098 
00099 int Cleaner::CleanAll(bool generator) {
00100   Reset();
00101   PrintHeader();
00102   for (vector<Edge*>::iterator e = state_->edges_.begin();
00103        e != state_->edges_.end(); ++e) {
00104     // Do not try to remove phony targets
00105     if ((*e)->rule_ == &State::kPhonyRule)
00106       continue;
00107     // Do not remove generator's files unless generator specified.
00108     if (!generator && (*e)->rule_->generator_)
00109       continue;
00110     for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
00111          out_node != (*e)->outputs_.end(); ++out_node) {
00112       Remove((*out_node)->file_->path_);
00113     }
00114   }
00115   PrintFooter();
00116   return status_;
00117 }
00118 
00119 void Cleaner::DoCleanTarget(Node* target) {
00120   if (target->in_edge_) {
00121     Remove(target->file_->path_);
00122     for (vector<Node*>::iterator n = target->in_edge_->inputs_.begin();
00123          n != target->in_edge_->inputs_.end();
00124          ++n) {
00125       DoCleanTarget(*n);
00126     }
00127   }
00128 }
00129 
00130 int Cleaner::CleanTarget(Node* target) {
00131   assert(target);
00132 
00133   Reset();
00134   PrintHeader();
00135   DoCleanTarget(target);
00136   PrintFooter();
00137   return status_;
00138 }
00139 
00140 int Cleaner::CleanTarget(const char* target) {
00141   assert(target);
00142 
00143   Reset();
00144   Node* node = state_->LookupNode(target);
00145   if (node) {
00146     CleanTarget(node);
00147   } else {
00148     Error("unknown target '%s'", target);
00149     status_ = 1;
00150   }
00151   return status_;
00152 }
00153 
00154 int Cleaner::CleanTargets(int target_count, char* targets[]) {
00155   Reset();
00156   PrintHeader();
00157   for (int i = 0; i < target_count; ++i) {
00158     const char* target_name = targets[i];
00159     Node* target = state_->LookupNode(target_name);
00160     if (target) {
00161       if (IsVerbose())
00162         printf("Target %s\n", target_name);
00163       DoCleanTarget(target);
00164     } else {
00165       Error("unknown target '%s'", target_name);
00166       status_ = 1;
00167     }
00168   }
00169   PrintFooter();
00170   return status_;
00171 }
00172 
00173 void Cleaner::DoCleanRule(const Rule* rule) {
00174   assert(rule);
00175 
00176   for (vector<Edge*>::iterator e = state_->edges_.begin();
00177        e != state_->edges_.end();
00178        ++e)
00179     if ((*e)->rule_->name_ == rule->name_)
00180       for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
00181            out_node != (*e)->outputs_.end();
00182            ++out_node)
00183         Remove((*out_node)->file_->path_);
00184 }
00185 
00186 int Cleaner::CleanRule(const Rule* rule) {
00187   assert(rule);
00188 
00189   Reset();
00190   PrintHeader();
00191   DoCleanRule(rule);
00192   PrintFooter();
00193   return status_;
00194 }
00195 
00196 int Cleaner::CleanRule(const char* rule) {
00197   assert(rule);
00198 
00199   Reset();
00200   const Rule* r = state_->LookupRule(rule);
00201   if (r) {
00202     CleanRule(r);
00203   } else {
00204     Error("unknown rule '%s'", rule);
00205     status_ = 1;
00206   }
00207   return status_;
00208 }
00209 
00210 int Cleaner::CleanRules(int rule_count, char* rules[]) {
00211   assert(rules);
00212 
00213   Reset();
00214   PrintHeader();
00215   for (int i = 0; i < rule_count; ++i) {
00216     const char* rule_name = rules[i];
00217     const Rule* rule = state_->LookupRule(rule_name);
00218     if (rule) {
00219       if (IsVerbose())
00220         printf("Rule %s\n", rule_name);
00221       DoCleanRule(rule);
00222     } else {
00223       Error("unknown rule '%s'", rule_name);
00224       status_ = 1;
00225     }
00226   }
00227   PrintFooter();
00228   return status_;
00229 }
00230 
00231 void Cleaner::Reset() {
00232   status_ = 0;
00233   cleaned_files_count_ = 0;
00234   removed_.clear();
00235 }