Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: tools/gn/visibility.cc

Issue 46313003: Implement target visibility in GN (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698