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

Unified Diff: tools/gn/label_pattern.cc

Issue 500423003: Enhance GN diagnostic tools (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: use patterns for gn check Created 6 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/gn/label_pattern.h ('k') | tools/gn/label_pattern_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/gn/label_pattern.cc
diff --git a/tools/gn/label_pattern.cc b/tools/gn/label_pattern.cc
new file mode 100644
index 0000000000000000000000000000000000000000..752898f1acace2f03bdddc25315da680728b6d00
--- /dev/null
+++ b/tools/gn/label_pattern.cc
@@ -0,0 +1,247 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tools/gn/label_pattern.h"
+
+#include "tools/gn/err.h"
+#include "tools/gn/filesystem_utils.h"
+#include "tools/gn/value.h"
+
+const char kLabelPattern_Help[] =
+ "Label patterns\n"
+ "\n"
+ " A label pattern is a way of expressing one or more labels in a portion\n"
+ " of the source tree. They are not general regular expressions.\n"
+ "\n"
+ " They can take the following forms only:\n"
+ "\n"
+ " - Explicit (no wildcard):\n"
+ " \"//foo/bar:baz\"\n"
+ " \":baz\"\n"
+ "\n"
+ " - Wildcard target names:\n"
+ " \"//foo/bar:*\" (all targets in the //foo/bar/BUILD.gn file)\n"
+ " \":*\" (all targets in the current build file)\n"
+ "\n"
+ " - Wildcard directory names (\"*\" is only supported at the end)\n"
+ " \"*\" (all targets)\n"
+ " \"//foo/bar/*\" (all targets in any subdir of //foo/bar)\n"
+ " \"./*\" (all targets in the current build file or sub dirs)\n"
+ "\n"
+ " Any of the above forms can additionally take an explicit toolchain.\n"
+ " In this case, the toolchain must be fully qualified (no wildcards\n"
+ " are supported in the toolchain name).\n"
+ "\n"
+ " \"//foo:bar(//build/toochain:mac)\"\n"
+ " An explicit target in an explicit toolchain.\n"
+ "\n"
+ " \":*(//build/toolchain/linux:32bit)\"\n"
+ " All targets in the current build file using the 32-bit Linux\n"
+ " toolchain.\n"
+ "\n"
+ " \"//foo/*(//build/toolchain:win)\"\n"
+ " All targets in //foo and any subdirectory using the Windows\n"
+ " toolchain.\n";
+
+LabelPattern::LabelPattern() : type_(MATCH) {
+}
+
+LabelPattern::LabelPattern(Type type,
+ const SourceDir& dir,
+ const base::StringPiece& name,
+ const Label& toolchain_label)
+ : toolchain_(toolchain_label),
+ type_(type),
+ dir_(dir) {
+ name.CopyToString(&name_);
+}
+
+LabelPattern::~LabelPattern() {
+}
+
+// static
+LabelPattern LabelPattern::GetPattern(const SourceDir& current_dir,
+ const Value& value,
+ Err* err) {
+ if (!value.VerifyTypeIs(Value::STRING, err))
+ return LabelPattern();
+
+ base::StringPiece str(value.string_value());
+ if (str.empty()) {
+ *err = Err(value, "Label pattern must not be empty.");
+ return LabelPattern();
+ }
+
+ // If there's no wildcard, this is specifying an exact label, use the
+ // label resolution code to get all the implicit name stuff.
+ size_t star = str.find('*');
+ if (star == std::string::npos) {
+ Label label = Label::Resolve(current_dir, Label(), value, err);
+ if (err->has_error())
+ return LabelPattern();
+
+ // Toolchain.
+ Label toolchain_label;
+ if (!label.toolchain_dir().is_null() || !label.toolchain_name().empty())
+ toolchain_label = label.GetToolchainLabel();
+
+ return LabelPattern(MATCH, label.dir(), label.name(), toolchain_label);
+ }
+
+ // Wildcard case, need to split apart the label to see what it specifies.
+ Label toolchain_label;
+ size_t open_paren = str.find('(');
+ if (open_paren != std::string::npos) {
+ // Has a toolchain definition, extract inside the parens.
+ size_t close_paren = str.find(')', open_paren);
+ if (close_paren == std::string::npos) {
+ *err = Err(value, "No close paren when looking for toolchain name.");
+ return LabelPattern();
+ }
+
+ std::string toolchain_string =
+ str.substr(open_paren + 1, close_paren - open_paren - 1).as_string();
+ if (toolchain_string.find('*') != std::string::npos) {
+ *err = Err(value, "Can't have a wildcard in the toolchain.");
+ return LabelPattern();
+ }
+
+ // Parse the inside of the parens as a label for a toolchain.
+ Value value_for_toolchain(value.origin(), toolchain_string);
+ toolchain_label =
+ Label::Resolve(current_dir, Label(), value_for_toolchain, err);
+ if (err->has_error())
+ return LabelPattern();
+
+ // Trim off the toolchain for the processing below.
+ str = str.substr(0, open_paren);
+ }
+
+ // Extract path and name.
+ base::StringPiece path;
+ base::StringPiece name;
+ size_t colon = str.find(':');
+ if (colon == std::string::npos) {
+ path = base::StringPiece(str);
+ } else {
+ path = str.substr(0, colon);
+ name = str.substr(colon + 1);
+ }
+
+ // The path can have these forms:
+ // 1. <empty> (use current dir)
+ // 2. <non wildcard stuff> (send through directory resolution)
+ // 3. <non wildcard stuff>* (send stuff through dir resolution, note star)
+ // 4. * (matches anything)
+ SourceDir dir;
+ bool has_path_star = false;
+ if (path.empty()) {
+ // Looks like ":foo".
+ dir = current_dir;
+ } else if (path[path.size() - 1] == '*') {
+ // Case 3 or 4 above.
+ has_path_star = true;
+
+ // Adjust path to contain everything but the star.
+ path = path.substr(0, path.size() - 1);
+
+ if (!path.empty() && path[path.size() - 1] != '/') {
+ // The input was "foo*" which is invalid.
+ *err = Err(value, "'*' must match full directories in a label pattern.",
+ "You did \"foo*\" but this thing doesn't do general pattern\n"
+ "matching. Instead, you have to add a slash: \"foo/*\" to match\n"
+ "all targets in a directory hierarchy.");
+ return LabelPattern();
+ }
+ }
+
+ // Resolve the part of the path that's not the wildcard.
+ if (!path.empty()) {
+ // The non-wildcard stuff better not have a wildcard.
+ if (path.find('*') != base::StringPiece::npos) {
+ *err = Err(value, "Label patterns only support wildcard suffixes.",
+ "The pattern contained a '*' that wasn't at tne end.");
+ return LabelPattern();
+ }
+
+ // Resolve the non-wildcard stuff.
+ dir = current_dir.ResolveRelativeDir(path);
+ if (dir.is_null()) {
+ *err = Err(value, "Label pattern didn't resolve to a dir.",
+ "The directory name \"" + path.as_string() + "\" didn't\n"
+ "resolve to a directory.");
+ return LabelPattern();
+ }
+ }
+
+ // Resolve the name. At this point, we're doing wildcard matches so the
+ // name should either be empty ("foo/*") or a wildcard ("foo:*");
+ if (colon != std::string::npos && name != "*") {
+ *err = Err(value, "Invalid label pattern.",
+ "You seem to be using the wildcard more generally that is supported.\n"
+ "Did you mean \"foo:*\" to match everything in the file, or\n"
+ "\"./*\" to recursively match everything in the currend subtree.");
+ return LabelPattern();
+ }
+
+ Type type;
+ if (has_path_star) {
+ // We know there's a wildcard, so if the name is empty it looks like
+ // "foo/*".
+ type = RECURSIVE_DIRECTORY;
+ } else {
+ // Everything else should be of the form "foo:*".
+ type = DIRECTORY;
+ }
+
+ // When we're doing wildcard matching, the name is always empty.
+ return LabelPattern(type, dir, base::StringPiece(), toolchain_label);
+}
+
+bool LabelPattern::Matches(const Label& label) const {
+ if (!toolchain_.is_null()) {
+ // Toolchain must match exactly.
+ if (toolchain_.dir() != label.toolchain_dir() ||
+ toolchain_.name() != label.toolchain_name())
+ return false;
+ }
+
+ switch (type_) {
+ case MATCH:
+ return label.name() == name_ && label.dir() == dir_;
+ case DIRECTORY:
+ // The directories must match exactly.
+ return label.dir() == dir_;
+ case RECURSIVE_DIRECTORY:
+ // Our directory must be a prefix of the input label for recursive.
+ return label.dir().value().compare(0, dir_.value().size(), dir_.value())
+ == 0;
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+std::string LabelPattern::Describe() const {
+ std::string result;
+
+ switch (type()) {
+ case MATCH:
+ result = DirectoryWithNoLastSlash(dir()) + ":" + name();
+ break;
+ case DIRECTORY:
+ result = DirectoryWithNoLastSlash(dir()) + ":*";
+ break;
+ case RECURSIVE_DIRECTORY:
+ result = dir().value() + "*";
+ break;
+ }
+
+ if (!toolchain_.is_null()) {
+ result.push_back('(');
+ result.append(toolchain_.GetUserVisibleName(false));
+ result.push_back(')');
+ }
+ return result;
+}
« no previous file with comments | « tools/gn/label_pattern.h ('k') | tools/gn/label_pattern_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698