make Node::in_edge_ private
[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 <errno.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/stat.h>
22
23 #include "disk_interface.h"
24 #include "graph.h"
25 #include "state.h"
26 #include "util.h"
27
28 Cleaner::Cleaner(State* state, const BuildConfig& config)
29   : state_(state),
30     config_(config),
31     removed_(),
32     cleaned_files_count_(0),
33     disk_interface_(new RealDiskInterface),
34     status_(0) {
35 }
36
37 Cleaner::Cleaner(State* state,
38                  const BuildConfig& config,
39                  DiskInterface* disk_interface)
40   : state_(state),
41     config_(config),
42     removed_(),
43     cleaned_files_count_(0),
44     disk_interface_(disk_interface),
45     status_(0) {
46 }
47
48 int Cleaner::RemoveFile(const string& path) {
49   return disk_interface_->RemoveFile(path);
50 }
51
52 bool Cleaner::FileExists(const string& path) {
53   return disk_interface_->Stat(path) > 0;
54 }
55
56 void Cleaner::Report(const string& path) {
57   ++cleaned_files_count_;
58   if (IsVerbose())
59     printf("Remove %s\n", path.c_str());
60 }
61
62 void Cleaner::Remove(const string& path) {
63   if (!IsAlreadyRemoved(path)) {
64     removed_.insert(path);
65     if (config_.dry_run) {
66       if (FileExists(path))
67         Report(path);
68     } else {
69       int ret = RemoveFile(path);
70       if (ret == 0)
71         Report(path);
72       else if (ret == -1)
73         status_ = 1;
74     }
75   }
76 }
77
78 bool Cleaner::IsAlreadyRemoved(const string& path) {
79   set<string>::iterator i = removed_.find(path);
80   return (i != removed_.end());
81 }
82
83 void Cleaner::PrintHeader() {
84   if (config_.verbosity == BuildConfig::QUIET)
85     return;
86   printf("Cleaning...");
87   if (IsVerbose())
88     printf("\n");
89   else
90     printf(" ");
91 }
92
93 void Cleaner::PrintFooter() {
94   if (config_.verbosity == BuildConfig::QUIET)
95     return;
96   printf("%d files.\n", cleaned_files_count_);
97 }
98
99 int Cleaner::CleanAll(bool generator) {
100   Reset();
101   PrintHeader();
102   for (vector<Edge*>::iterator e = state_->edges_.begin();
103        e != state_->edges_.end(); ++e) {
104     // Do not try to remove phony targets
105     if ((*e)->rule_ == &State::kPhonyRule)
106       continue;
107     // Do not remove generator's files unless generator specified.
108     if (!generator && (*e)->rule().generator_)
109       continue;
110     for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
111          out_node != (*e)->outputs_.end(); ++out_node) {
112       Remove((*out_node)->path());
113     }
114     if (!(*e)->rule().depfile_.empty())
115       Remove((*e)->EvaluateDepFile());
116   }
117   PrintFooter();
118   return status_;
119 }
120
121 void Cleaner::DoCleanTarget(Node* target) {
122   if (target->in_edge()) {
123     Remove(target->path());
124     for (vector<Node*>::iterator n = target->in_edge()->inputs_.begin();
125          n != target->in_edge()->inputs_.end();
126          ++n) {
127       DoCleanTarget(*n);
128     }
129   }
130 }
131
132 int Cleaner::CleanTarget(Node* target) {
133   assert(target);
134
135   Reset();
136   PrintHeader();
137   DoCleanTarget(target);
138   PrintFooter();
139   return status_;
140 }
141
142 int Cleaner::CleanTarget(const char* target) {
143   assert(target);
144
145   Reset();
146   Node* node = state_->LookupNode(target);
147   if (node) {
148     CleanTarget(node);
149   } else {
150     Error("unknown target '%s'", target);
151     status_ = 1;
152   }
153   return status_;
154 }
155
156 int Cleaner::CleanTargets(int target_count, char* targets[]) {
157   Reset();
158   PrintHeader();
159   for (int i = 0; i < target_count; ++i) {
160     const char* target_name = targets[i];
161     Node* target = state_->LookupNode(target_name);
162     if (target) {
163       if (IsVerbose())
164         printf("Target %s\n", target_name);
165       DoCleanTarget(target);
166     } else {
167       Error("unknown target '%s'", target_name);
168       status_ = 1;
169     }
170   }
171   PrintFooter();
172   return status_;
173 }
174
175 void Cleaner::DoCleanRule(const Rule* rule) {
176   assert(rule);
177
178   for (vector<Edge*>::iterator e = state_->edges_.begin();
179        e != state_->edges_.end();
180        ++e)
181     if ((*e)->rule().name_ == rule->name_)
182       for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
183            out_node != (*e)->outputs_.end();
184            ++out_node)
185         Remove((*out_node)->path());
186 }
187
188 int Cleaner::CleanRule(const Rule* rule) {
189   assert(rule);
190
191   Reset();
192   PrintHeader();
193   DoCleanRule(rule);
194   PrintFooter();
195   return status_;
196 }
197
198 int Cleaner::CleanRule(const char* rule) {
199   assert(rule);
200
201   Reset();
202   const Rule* r = state_->LookupRule(rule);
203   if (r) {
204     CleanRule(r);
205   } else {
206     Error("unknown rule '%s'", rule);
207     status_ = 1;
208   }
209   return status_;
210 }
211
212 int Cleaner::CleanRules(int rule_count, char* rules[]) {
213   assert(rules);
214
215   Reset();
216   PrintHeader();
217   for (int i = 0; i < rule_count; ++i) {
218     const char* rule_name = rules[i];
219     const Rule* rule = state_->LookupRule(rule_name);
220     if (rule) {
221       if (IsVerbose())
222         printf("Rule %s\n", rule_name);
223       DoCleanRule(rule);
224     } else {
225       Error("unknown rule '%s'", rule_name);
226       status_ = 1;
227     }
228   }
229   PrintFooter();
230   return status_;
231 }
232
233 void Cleaner::Reset() {
234   status_ = 0;
235   cleaned_files_count_ = 0;
236   removed_.clear();
237 }