Chromium Code Reviews| 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 |