Ninja
|
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 <stdio.h> 00019 00020 #include "disk_interface.h" 00021 #include "graph.h" 00022 #include "state.h" 00023 #include "util.h" 00024 00025 Cleaner::Cleaner(State* state, const BuildConfig& config) 00026 : state_(state), 00027 config_(config), 00028 removed_(), 00029 cleaned_(), 00030 cleaned_files_count_(0), 00031 disk_interface_(new RealDiskInterface), 00032 status_(0) { 00033 } 00034 00035 Cleaner::Cleaner(State* state, 00036 const BuildConfig& config, 00037 DiskInterface* disk_interface) 00038 : state_(state), 00039 config_(config), 00040 removed_(), 00041 cleaned_(), 00042 cleaned_files_count_(0), 00043 disk_interface_(disk_interface), 00044 status_(0) { 00045 } 00046 00047 int Cleaner::RemoveFile(const string& path) { 00048 return disk_interface_->RemoveFile(path); 00049 } 00050 00051 bool Cleaner::FileExists(const string& path) { 00052 return disk_interface_->Stat(path) > 0; 00053 } 00054 00055 void Cleaner::Report(const string& path) { 00056 ++cleaned_files_count_; 00057 if (IsVerbose()) 00058 printf("Remove %s\n", path.c_str()); 00059 } 00060 00061 void Cleaner::Remove(const string& path) { 00062 if (!IsAlreadyRemoved(path)) { 00063 removed_.insert(path); 00064 if (config_.dry_run) { 00065 if (FileExists(path)) 00066 Report(path); 00067 } else { 00068 int ret = RemoveFile(path); 00069 if (ret == 0) 00070 Report(path); 00071 else if (ret == -1) 00072 status_ = 1; 00073 } 00074 } 00075 } 00076 00077 bool Cleaner::IsAlreadyRemoved(const string& path) { 00078 set<string>::iterator i = removed_.find(path); 00079 return (i != removed_.end()); 00080 } 00081 00082 void Cleaner::RemoveEdgeFiles(Edge* edge) { 00083 string depfile = edge->GetBinding("depfile"); 00084 if (!depfile.empty()) 00085 Remove(depfile); 00086 00087 string rspfile = edge->GetBinding("rspfile"); 00088 if (!rspfile.empty()) 00089 Remove(rspfile); 00090 } 00091 00092 void Cleaner::PrintHeader() { 00093 if (config_.verbosity == BuildConfig::QUIET) 00094 return; 00095 printf("Cleaning..."); 00096 if (IsVerbose()) 00097 printf("\n"); 00098 else 00099 printf(" "); 00100 } 00101 00102 void Cleaner::PrintFooter() { 00103 if (config_.verbosity == BuildConfig::QUIET) 00104 return; 00105 printf("%d files.\n", cleaned_files_count_); 00106 } 00107 00108 int Cleaner::CleanAll(bool generator) { 00109 Reset(); 00110 PrintHeader(); 00111 for (vector<Edge*>::iterator e = state_->edges_.begin(); 00112 e != state_->edges_.end(); ++e) { 00113 // Do not try to remove phony targets 00114 if ((*e)->is_phony()) 00115 continue; 00116 // Do not remove generator's files unless generator specified. 00117 if (!generator && (*e)->GetBindingBool("generator")) 00118 continue; 00119 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin(); 00120 out_node != (*e)->outputs_.end(); ++out_node) { 00121 Remove((*out_node)->path()); 00122 } 00123 00124 RemoveEdgeFiles(*e); 00125 } 00126 PrintFooter(); 00127 return status_; 00128 } 00129 00130 void Cleaner::DoCleanTarget(Node* target) { 00131 if (Edge* e = target->in_edge()) { 00132 // Do not try to remove phony targets 00133 if (!e->is_phony()) { 00134 Remove(target->path()); 00135 RemoveEdgeFiles(e); 00136 } 00137 for (vector<Node*>::iterator n = e->inputs_.begin(); n != e->inputs_.end(); 00138 ++n) { 00139 Node* next = *n; 00140 // call DoCleanTarget recursively if this node has not been visited 00141 if (cleaned_.count(next) == 0) { 00142 DoCleanTarget(next); 00143 } 00144 } 00145 } 00146 00147 // mark this target to be cleaned already 00148 cleaned_.insert(target); 00149 } 00150 00151 int Cleaner::CleanTarget(Node* target) { 00152 assert(target); 00153 00154 Reset(); 00155 PrintHeader(); 00156 DoCleanTarget(target); 00157 PrintFooter(); 00158 return status_; 00159 } 00160 00161 int Cleaner::CleanTarget(const char* target) { 00162 assert(target); 00163 00164 Reset(); 00165 Node* node = state_->LookupNode(target); 00166 if (node) { 00167 CleanTarget(node); 00168 } else { 00169 Error("unknown target '%s'", target); 00170 status_ = 1; 00171 } 00172 return status_; 00173 } 00174 00175 int Cleaner::CleanTargets(int target_count, char* targets[]) { 00176 Reset(); 00177 PrintHeader(); 00178 for (int i = 0; i < target_count; ++i) { 00179 const char* target_name = targets[i]; 00180 Node* target = state_->LookupNode(target_name); 00181 if (target) { 00182 if (IsVerbose()) 00183 printf("Target %s\n", target_name); 00184 DoCleanTarget(target); 00185 } else { 00186 Error("unknown target '%s'", target_name); 00187 status_ = 1; 00188 } 00189 } 00190 PrintFooter(); 00191 return status_; 00192 } 00193 00194 void Cleaner::DoCleanRule(const Rule* rule) { 00195 assert(rule); 00196 00197 for (vector<Edge*>::iterator e = state_->edges_.begin(); 00198 e != state_->edges_.end(); ++e) { 00199 if ((*e)->rule().name() == rule->name()) { 00200 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin(); 00201 out_node != (*e)->outputs_.end(); ++out_node) { 00202 Remove((*out_node)->path()); 00203 RemoveEdgeFiles(*e); 00204 } 00205 } 00206 } 00207 } 00208 00209 int Cleaner::CleanRule(const Rule* rule) { 00210 assert(rule); 00211 00212 Reset(); 00213 PrintHeader(); 00214 DoCleanRule(rule); 00215 PrintFooter(); 00216 return status_; 00217 } 00218 00219 int Cleaner::CleanRule(const char* rule) { 00220 assert(rule); 00221 00222 Reset(); 00223 const Rule* r = state_->LookupRule(rule); 00224 if (r) { 00225 CleanRule(r); 00226 } else { 00227 Error("unknown rule '%s'", rule); 00228 status_ = 1; 00229 } 00230 return status_; 00231 } 00232 00233 int Cleaner::CleanRules(int rule_count, char* rules[]) { 00234 assert(rules); 00235 00236 Reset(); 00237 PrintHeader(); 00238 for (int i = 0; i < rule_count; ++i) { 00239 const char* rule_name = rules[i]; 00240 const Rule* rule = state_->LookupRule(rule_name); 00241 if (rule) { 00242 if (IsVerbose()) 00243 printf("Rule %s\n", rule_name); 00244 DoCleanRule(rule); 00245 } else { 00246 Error("unknown rule '%s'", rule_name); 00247 status_ = 1; 00248 } 00249 } 00250 PrintFooter(); 00251 return status_; 00252 } 00253 00254 void Cleaner::Reset() { 00255 status_ = 0; 00256 cleaned_files_count_ = 0; 00257 removed_.clear(); 00258 cleaned_.clear(); 00259 }