OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "tools/gn/visibility.h" | |
6 | |
7 #include "base/strings/string_piece.h" | |
8 #include "base/strings/string_util.h" | |
9 #include "tools/gn/err.h" | |
10 #include "tools/gn/filesystem_utils.h" | |
11 #include "tools/gn/item.h" | |
12 #include "tools/gn/label.h" | |
13 #include "tools/gn/scope.h" | |
14 #include "tools/gn/value.h" | |
15 #include "tools/gn/variables.h" | |
16 | |
17 Visibility::VisPattern::VisPattern() : type_(MATCH) { | |
18 } | |
19 | |
20 Visibility::VisPattern::VisPattern(Type type, | |
21 const SourceDir& dir, | |
22 const base::StringPiece& name) | |
23 : type_(type), | |
24 dir_(dir) { | |
25 name.CopyToString(&name_); | |
26 } | |
27 | |
28 Visibility::VisPattern::~VisPattern() { | |
29 } | |
30 | |
31 bool Visibility::VisPattern::Matches(const Label& label) const { | |
32 switch (type_) { | |
33 case MATCH: | |
34 return label.name() == name_ && label.dir() == dir_; | |
35 case DIRECTORY: | |
36 // The directories must match exactly for private visibility. | |
37 return label.dir() == dir_; | |
38 case RECURSIVE_DIRECTORY: | |
39 // Our directory must be a prefix of the input label for recursive | |
40 // private visibility. | |
41 return label.dir().value().compare(0, dir_.value().size(), dir_.value()) | |
42 == 0; | |
43 default: | |
44 NOTREACHED(); | |
45 return false; | |
46 } | |
47 } | |
48 | |
49 Visibility::Visibility() { | |
50 } | |
51 | |
52 Visibility::~Visibility() { | |
53 } | |
54 | |
55 bool Visibility::Set(const SourceDir& current_dir, | |
56 const Value& value, | |
57 Err* err) { | |
58 patterns_.clear(); | |
59 | |
60 // Allow a single string to be passed in to make the common case (just one | |
61 // pattern) easier to specify. | |
62 if (value.type() == Value::STRING) { | |
63 patterns_.push_back(GetPattern(current_dir, value, err)); | |
64 return !err->has_error(); | |
65 } | |
66 | |
67 // If it's not a string, it should be a list of strings. | |
68 if (!value.VerifyTypeIs(Value::LIST, err)) | |
69 return false; | |
70 | |
71 const std::vector<Value>& list = value.list_value(); | |
72 for (size_t i = 0; i < list.size(); i++) { | |
73 patterns_.push_back(GetPattern(current_dir, list[i], err)); | |
74 if (err->has_error()) | |
75 return false; | |
76 } | |
77 return true; | |
78 } | |
79 | |
80 void Visibility::SetPublic() { | |
81 patterns_.push_back( | |
82 VisPattern(VisPattern::RECURSIVE_DIRECTORY, SourceDir(), std::string())); | |
83 } | |
84 | |
85 void Visibility::SetPrivate(const SourceDir& current_dir) { | |
86 patterns_.push_back( | |
87 VisPattern(VisPattern::DIRECTORY, current_dir, std::string())); | |
88 } | |
89 | |
90 bool Visibility::CanSeeMe(const Label& label) const { | |
91 for (size_t i = 0; i < patterns_.size(); i++) { | |
92 if (patterns_[i].Matches(label)) | |
93 return true; | |
94 } | |
95 return false; | |
96 } | |
97 | |
98 std::string Visibility::Describe() const { | |
99 if (patterns_.empty()) | |
100 return std::string("[] (no visibility)"); | |
101 std::string result = "[\n"; | |
102 | |
103 for (size_t i = 0; i < patterns_.size(); i++) { | |
104 switch (patterns_[i].type()) { | |
105 case VisPattern::MATCH: | |
106 result += " " + patterns_[i].dir().value() + ":" + | |
107 patterns_[i].name() + "\n"; | |
108 break; | |
109 case VisPattern::DIRECTORY: | |
110 result += " " + DirectoryWithNoLastSlash(patterns_[i].dir()) + | |
111 ":*\n"; | |
112 break; | |
113 case VisPattern::RECURSIVE_DIRECTORY: | |
114 result += " " + patterns_[i].dir().value() + "*\n"; | |
115 break; | |
116 } | |
117 } | |
118 | |
119 result += "]"; | |
120 return result; | |
121 } | |
122 | |
123 // static | |
124 Visibility::VisPattern Visibility::GetPattern(const SourceDir& current_dir, | |
125 const Value& value, | |
126 Err* err) { | |
127 if (!value.VerifyTypeIs(Value::STRING, err)) | |
128 return VisPattern(); | |
129 | |
130 const std::string& str = value.string_value(); | |
131 if (str.empty()) { | |
132 *err = Err(value, "Visibility pattern must not be empty."); | |
133 return VisPattern(); | |
134 } | |
135 | |
136 // If there's no wildcard, this is specifying an exact label, use the | |
137 // label resolution code to get all the implicit name stuff. | |
138 size_t star = str.find('*'); | |
139 if (star == std::string::npos) { | |
140 Label label = Label::Resolve(current_dir, Label(), value, err); | |
141 if (err->has_error()) | |
142 return VisPattern(); | |
143 | |
144 // There should be no toolchain specified. | |
145 if (!label.toolchain_dir().is_null() || !label.toolchain_name().empty()) { | |
146 *err = Err(value, "Visibility label specified a toolchain.", | |
147 "Visibility names and patterns don't use toolchains, erase the\n" | |
148 "stuff in the ()."); | |
149 return VisPattern(); | |
150 } | |
151 | |
152 return VisPattern(VisPattern::MATCH, label.dir(), label.name()); | |
153 } | |
154 | |
155 // Wildcard case, need to split apart the label to see what it specifies. | |
156 base::StringPiece path; | |
157 base::StringPiece name; | |
158 size_t colon = str.find(':'); | |
159 if (colon == std::string::npos) { | |
160 path = base::StringPiece(str); | |
161 } else { | |
162 path = base::StringPiece(&str[0], colon); | |
163 name = base::StringPiece(&str[colon + 1], str.size() - colon - 1); | |
164 } | |
165 | |
166 // The path can have these forms: | |
167 // 1. <empty> (use current dir) | |
168 // 2. <non wildcard stuff> (send through directory resolution) | |
169 // 3. <non wildcard stuff>* (send stuff throgh dir resolution, note star) | |
scottmg
2014/04/01 06:18:35
"through"
| |
170 // 4. * (matches anything) | |
171 SourceDir dir; | |
172 bool has_path_star = false; | |
173 if (path.empty()) { | |
174 // Looks like ":foo". | |
175 dir = current_dir; | |
176 } else if (path[path.size() - 1] == '*') { | |
177 // Case 3 or 4 above. | |
178 has_path_star = true; | |
179 | |
180 // Adjust path to contain everything but the star. | |
181 path = path.substr(0, path.size() - 1); | |
182 | |
183 if (!path.empty() && path[path.size() - 1] != '/') { | |
184 // The input was "foo*" which is invalid. | |
185 *err = Err(value, "'*' must match full directories in visibility.", | |
186 "You did \"foo*\" but visibility doesn't do general pattern\n" | |
187 "matching. Instead, you have to add a slash: \"foo/*\"."); | |
188 return VisPattern(); | |
189 } | |
190 } | |
191 | |
192 // Resolve the part of the path that's not the wildcard. | |
193 if (!path.empty()) { | |
194 // The non-wildcard stuff better not have a wildcard. | |
195 if (path.find('*') != base::StringPiece::npos) { | |
196 *err = Err(value, "Visibility patterns only support wildcard suffixes.", | |
197 "The visibility pattern contained a '*' that wasn't at tne end."); | |
198 return VisPattern(); | |
199 } | |
200 | |
201 // Resolve the non-wildcard stuff. | |
202 dir = current_dir.ResolveRelativeDir(path); | |
203 if (dir.is_null()) { | |
204 *err = Err(value, "Visibility pattern didn't resolve to a dir.", | |
205 "The directory name \"" + path.as_string() + "\" didn't\n" | |
206 "resolve to a directory."); | |
207 return VisPattern(); | |
208 } | |
209 } | |
210 | |
211 // Resolve the name. At this point, we're doing wildcard matches so the | |
212 // name should either be empty ("foo/*") or a wildcard ("foo:*"); | |
213 if (colon != std::string::npos && name != "*") { | |
214 *err = Err(value, "Invalid visibility pattern.", | |
215 "You seem to be using the wildcard more generally that is supported.\n" | |
216 "Did you mean \"foo:*\" to match everything in the current file, or\n" | |
217 "\"./*\" to recursively match everything in the currend subtree."); | |
218 return VisPattern(); | |
219 } | |
220 | |
221 VisPattern::Type type; | |
222 if (has_path_star) { | |
223 // We know there's a wildcard, so if the name is empty it looks like | |
224 // "foo/*". | |
225 type = VisPattern::RECURSIVE_DIRECTORY; | |
226 } else { | |
227 // Everything else should be of the form "foo:*". | |
228 type = VisPattern::DIRECTORY; | |
229 } | |
230 | |
231 // When we're doing wildcard matching, the name is always empty. | |
232 return VisPattern(type, dir, base::StringPiece()); | |
233 } | |
234 | |
235 // static | |
236 bool Visibility::CheckItemVisibility(const Item* from, | |
237 const Item* to, | |
238 Err* err) { | |
239 if (!to->visibility().CanSeeMe(from->label())) { | |
240 std::string to_label = to->label().GetUserVisibleName(false); | |
241 *err = Err(from->defined_from(), "Dependency not allowed.", | |
242 "The item " + from->label().GetUserVisibleName(false) + "\n" | |
243 "can not depend on " + to_label + "\n" | |
244 "because it is not in " + to_label + "'s visibility list: " + | |
245 to->visibility().Describe()); | |
246 return false; | |
247 } | |
248 return true; | |
249 } | |
250 | |
251 // static | |
252 bool Visibility::FillItemVisibility(Item* item, Scope* scope, Err* err) { | |
253 const Value* vis_value = scope->GetValue(variables::kVisibility, true); | |
254 if (vis_value) | |
255 item->visibility().Set(scope->GetSourceDir(), *vis_value, err); | |
256 else // Default to public. | |
257 item->visibility().SetPublic(); | |
258 return !err->has_error(); | |
259 } | |
OLD | NEW |