1 // Copyright 2011 Google Inc. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <direct.h> // Has to be before util.h is included.
31 #include "build_log.h"
33 #include "manifest_parser.h"
40 /// mingw has no mktemp. Implement one with the same type as the one
41 /// found in the Windows API.
42 int _mktemp_s(char* templ) {
43 char* ofs = strchr(templ, 'X');
44 sprintf(ofs, "%d", rand() % 1000000);
49 /// Windows has no mkdtemp. Implement it in terms of _mktemp_s.
50 char* mkdtemp(char* name_template) {
51 int err = _mktemp_s(name_template);
57 err = _mkdir(name_template);
67 string GetSystemTempDir() {
70 if (!GetTempPath(sizeof(buf), buf))
74 const char* tempdir = getenv("TMPDIR");
81 } // anonymous namespace
83 StateTestWithBuiltinRules::StateTestWithBuiltinRules() {
87 void StateTestWithBuiltinRules::AddCatRule(State* state) {
90 " command = cat $in > $out\n");
93 Node* StateTestWithBuiltinRules::GetNode(const string& path) {
94 EXPECT_FALSE(strpbrk(path.c_str(), "/\\"));
95 return state_.GetNode(path, 0);
98 void AssertParse(State* state, const char* input) {
99 ManifestParser parser(state, NULL, kDupeEdgeActionWarn);
101 EXPECT_TRUE(parser.ParseTest(input, &err));
106 void AssertHash(const char* expected, uint64_t actual) {
107 ASSERT_EQ(BuildLog::LogEntry::HashCommand(expected), actual);
110 void VerifyGraph(const State& state) {
111 for (vector<Edge*>::const_iterator e = state.edges_.begin();
112 e != state.edges_.end(); ++e) {
113 // All edges need at least one output.
114 EXPECT_FALSE((*e)->outputs_.empty());
115 // Check that the edge's inputs have the edge as out-edge.
116 for (vector<Node*>::const_iterator in_node = (*e)->inputs_.begin();
117 in_node != (*e)->inputs_.end(); ++in_node) {
118 const vector<Edge*>& out_edges = (*in_node)->out_edges();
119 EXPECT_NE(find(out_edges.begin(), out_edges.end(), *e),
122 // Check that the edge's outputs have the edge as in-edge.
123 for (vector<Node*>::const_iterator out_node = (*e)->outputs_.begin();
124 out_node != (*e)->outputs_.end(); ++out_node) {
125 EXPECT_EQ((*out_node)->in_edge(), *e);
129 // The union of all in- and out-edges of each nodes should be exactly edges_.
130 set<const Edge*> node_edge_set;
131 for (State::Paths::const_iterator p = state.paths_.begin();
132 p != state.paths_.end(); ++p) {
133 const Node* n = p->second;
135 node_edge_set.insert(n->in_edge());
136 node_edge_set.insert(n->out_edges().begin(), n->out_edges().end());
138 set<const Edge*> edge_set(state.edges_.begin(), state.edges_.end());
139 EXPECT_EQ(node_edge_set, edge_set);
142 void VirtualFileSystem::Create(const string& path,
143 const string& contents) {
144 files_[path].mtime = now_;
145 files_[path].contents = contents;
146 files_created_.insert(path);
149 TimeStamp VirtualFileSystem::Stat(const string& path, string* err) const {
150 FileMap::const_iterator i = files_.find(path);
151 if (i != files_.end()) {
152 *err = i->second.stat_error;
153 return i->second.mtime;
158 bool VirtualFileSystem::WriteFile(const string& path, const string& contents) {
159 Create(path, contents);
163 bool VirtualFileSystem::MakeDir(const string& path) {
164 directories_made_.push_back(path);
165 return true; // success
168 FileReader::Status VirtualFileSystem::ReadFile(const string& path,
171 files_read_.push_back(path);
172 FileMap::iterator i = files_.find(path);
173 if (i != files_.end()) {
174 *contents = i->second.contents;
177 *err = strerror(ENOENT);
181 int VirtualFileSystem::RemoveFile(const string& path) {
182 if (find(directories_made_.begin(), directories_made_.end(), path)
183 != directories_made_.end())
185 FileMap::iterator i = files_.find(path);
186 if (i != files_.end()) {
188 files_removed_.insert(path);
195 void ScopedTempDir::CreateAndEnter(const string& name) {
196 // First change into the system temp dir and save it for cleanup.
197 start_dir_ = GetSystemTempDir();
198 if (start_dir_.empty())
199 Fatal("couldn't get system temp dir");
200 if (chdir(start_dir_.c_str()) < 0)
201 Fatal("chdir: %s", strerror(errno));
203 // Create a temporary subdirectory of that.
204 char name_template[1024];
205 strcpy(name_template, name.c_str());
206 strcat(name_template, "-XXXXXX");
207 char* tempname = mkdtemp(name_template);
209 Fatal("mkdtemp: %s", strerror(errno));
210 temp_dir_name_ = tempname;
212 // chdir into the new temporary directory.
213 if (chdir(temp_dir_name_.c_str()) < 0)
214 Fatal("chdir: %s", strerror(errno));
217 void ScopedTempDir::Cleanup() {
218 if (temp_dir_name_.empty())
219 return; // Something went wrong earlier.
221 // Move out of the directory we're about to clobber.
222 if (chdir(start_dir_.c_str()) < 0)
223 Fatal("chdir: %s", strerror(errno));
226 string command = "rmdir /s /q " + temp_dir_name_;
228 string command = "rm -rf " + temp_dir_name_;
230 if (system(command.c_str()) < 0)
231 Fatal("system: %s", strerror(errno));
233 temp_dir_name_.clear();