Imported Upstream version 1.7.1
[platform/upstream/ninja.git] / src / clean.cc
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "clean.h"
16
17 #include <assert.h>
18 #include <stdio.h>
19
20 #include "disk_interface.h"
21 #include "graph.h"
22 #include "state.h"
23 #include "util.h"
24
25 Cleaner::Cleaner(State* state, const BuildConfig& config)
26   : state_(state),
27     config_(config),
28     removed_(),
29     cleaned_(),
30     cleaned_files_count_(0),
31     disk_interface_(new RealDiskInterface),
32     status_(0) {
33 }
34
35 Cleaner::Cleaner(State* state,
36                  const BuildConfig& config,
37                  DiskInterface* disk_interface)
38   : state_(state),
39     config_(config),
40     removed_(),
41     cleaned_(),
42     cleaned_files_count_(0),
43     disk_interface_(disk_interface),
44     status_(0) {
45 }
46
47 int Cleaner::RemoveFile(const string& path) {
48   return disk_interface_->RemoveFile(path);
49 }
50
51 bool Cleaner::FileExists(const string& path) {
52   string err;
53   TimeStamp mtime = disk_interface_->Stat(path, &err);
54   if (mtime == -1)
55     Error("%s", err.c_str());
56   return mtime > 0;  // Treat Stat() errors as "file does not exist".
57 }
58
59 void Cleaner::Report(const string& path) {
60   ++cleaned_files_count_;
61   if (IsVerbose())
62     printf("Remove %s\n", path.c_str());
63 }
64
65 void Cleaner::Remove(const string& path) {
66   if (!IsAlreadyRemoved(path)) {
67     removed_.insert(path);
68     if (config_.dry_run) {
69       if (FileExists(path))
70         Report(path);
71     } else {
72       int ret = RemoveFile(path);
73       if (ret == 0)
74         Report(path);
75       else if (ret == -1)
76         status_ = 1;
77     }
78   }
79 }
80
81 bool Cleaner::IsAlreadyRemoved(const string& path) {
82   set<string>::iterator i = removed_.find(path);
83   return (i != removed_.end());
84 }
85
86 void Cleaner::RemoveEdgeFiles(Edge* edge) {
87   string depfile = edge->GetUnescapedDepfile();
88   if (!depfile.empty())
89     Remove(depfile);
90
91   string rspfile = edge->GetUnescapedRspfile();
92   if (!rspfile.empty())
93     Remove(rspfile);
94 }
95
96 void Cleaner::PrintHeader() {
97   if (config_.verbosity == BuildConfig::QUIET)
98     return;
99   printf("Cleaning...");
100   if (IsVerbose())
101     printf("\n");
102   else
103     printf(" ");
104 }
105
106 void Cleaner::PrintFooter() {
107   if (config_.verbosity == BuildConfig::QUIET)
108     return;
109   printf("%d files.\n", cleaned_files_count_);
110 }
111
112 int Cleaner::CleanAll(bool generator) {
113   Reset();
114   PrintHeader();
115   for (vector<Edge*>::iterator e = state_->edges_.begin();
116        e != state_->edges_.end(); ++e) {
117     // Do not try to remove phony targets
118     if ((*e)->is_phony())
119       continue;
120     // Do not remove generator's files unless generator specified.
121     if (!generator && (*e)->GetBindingBool("generator"))
122       continue;
123     for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
124          out_node != (*e)->outputs_.end(); ++out_node) {
125       Remove((*out_node)->path());
126     }
127
128     RemoveEdgeFiles(*e);
129   }
130   PrintFooter();
131   return status_;
132 }
133
134 void Cleaner::DoCleanTarget(Node* target) {
135   if (Edge* e = target->in_edge()) {
136     // Do not try to remove phony targets
137     if (!e->is_phony()) {
138       Remove(target->path());
139       RemoveEdgeFiles(e);
140     }
141     for (vector<Node*>::iterator n = e->inputs_.begin(); n != e->inputs_.end();
142          ++n) {
143       Node* next = *n;
144       // call DoCleanTarget recursively if this node has not been visited
145       if (cleaned_.count(next) == 0) {
146         DoCleanTarget(next);
147       }
148     }
149   }
150
151   // mark this target to be cleaned already
152   cleaned_.insert(target);
153 }
154
155 int Cleaner::CleanTarget(Node* target) {
156   assert(target);
157
158   Reset();
159   PrintHeader();
160   DoCleanTarget(target);
161   PrintFooter();
162   return status_;
163 }
164
165 int Cleaner::CleanTarget(const char* target) {
166   assert(target);
167
168   Reset();
169   Node* node = state_->LookupNode(target);
170   if (node) {
171     CleanTarget(node);
172   } else {
173     Error("unknown target '%s'", target);
174     status_ = 1;
175   }
176   return status_;
177 }
178
179 int Cleaner::CleanTargets(int target_count, char* targets[]) {
180   Reset();
181   PrintHeader();
182   for (int i = 0; i < target_count; ++i) {
183     const char* target_name = targets[i];
184     Node* target = state_->LookupNode(target_name);
185     if (target) {
186       if (IsVerbose())
187         printf("Target %s\n", target_name);
188       DoCleanTarget(target);
189     } else {
190       Error("unknown target '%s'", target_name);
191       status_ = 1;
192     }
193   }
194   PrintFooter();
195   return status_;
196 }
197
198 void Cleaner::DoCleanRule(const Rule* rule) {
199   assert(rule);
200
201   for (vector<Edge*>::iterator e = state_->edges_.begin();
202        e != state_->edges_.end(); ++e) {
203     if ((*e)->rule().name() == rule->name()) {
204       for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
205            out_node != (*e)->outputs_.end(); ++out_node) {
206         Remove((*out_node)->path());
207         RemoveEdgeFiles(*e);
208       }
209     }
210   }
211 }
212
213 int Cleaner::CleanRule(const Rule* rule) {
214   assert(rule);
215
216   Reset();
217   PrintHeader();
218   DoCleanRule(rule);
219   PrintFooter();
220   return status_;
221 }
222
223 int Cleaner::CleanRule(const char* rule) {
224   assert(rule);
225
226   Reset();
227   const Rule* r = state_->bindings_.LookupRule(rule);
228   if (r) {
229     CleanRule(r);
230   } else {
231     Error("unknown rule '%s'", rule);
232     status_ = 1;
233   }
234   return status_;
235 }
236
237 int Cleaner::CleanRules(int rule_count, char* rules[]) {
238   assert(rules);
239
240   Reset();
241   PrintHeader();
242   for (int i = 0; i < rule_count; ++i) {
243     const char* rule_name = rules[i];
244     const Rule* rule = state_->bindings_.LookupRule(rule_name);
245     if (rule) {
246       if (IsVerbose())
247         printf("Rule %s\n", rule_name);
248       DoCleanRule(rule);
249     } else {
250       Error("unknown rule '%s'", rule_name);
251       status_ = 1;
252     }
253   }
254   PrintFooter();
255   return status_;
256 }
257
258 void Cleaner::Reset() {
259   status_ = 0;
260   cleaned_files_count_ = 0;
261   removed_.clear();
262   cleaned_.clear();
263 }