GN: Use source root as base for gn gen filters

When running gn gen with filters for the IDE output from ninja,
the gn gen command used the working directory (//out/foo) as the
base for resolving the filters, rather than "//" as is done when
running gn gen directly.

This CL fixes that by always using "//" as the root_dir. It also
fixes filter labels that have had the leading "/" in "//" removed
by Git Bash.

R=dpranke@chromium.org

Change-Id: I6c6e6f5e720d50b325d8b368f94ee1b3b5931627
Reviewed-on: https://chromium-review.googlesource.com/941209
Reviewed-by: Dirk Pranke <dpranke@chromium.org>
Commit-Queue: Yngve Pettersen <yngve@vivaldi.com>
Cr-Original-Commit-Position: refs/heads/master@{#548215}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: f7ccdc763eb515b93850db40cc6ea44c02e2015a
diff --git a/tools/gn/commands.cc b/tools/gn/commands.cc
index c47f1b1..59d2391 100644
--- a/tools/gn/commands.cc
+++ b/tools/gn/commands.cc
@@ -338,6 +338,35 @@
   }
 }
 
+#if defined(OS_WIN)
+// Git bash will remove the first "/" in "//" paths
+// This also happens for labels assigned to command line parameters, e.g.
+// --filters
+// Fix "//" paths, but not absolute and relative paths
+inline std::string FixGitBashLabelEdit(const std::string& label) {
+  static std::unique_ptr<base::Environment> git_bash_env;
+  if (!git_bash_env)
+    git_bash_env = base::Environment::Create();
+
+  std::string temp_label(label);
+
+  if (git_bash_env->HasVar(
+          "MSYSTEM") &&        // Only for MinGW based shells like Git Bash
+      temp_label[0] == '/' &&  // Only fix for //foo paths, not /f:oo paths
+      (temp_label.length() < 2 ||
+       (temp_label[1] != '/' &&
+        (temp_label.length() < 3 || temp_label[1] != ':'))))
+    temp_label.insert(0, "/");
+  return temp_label;
+}
+#else
+// Only repair on Windows
+inline std::string FixGitBashLabelEdit(const std::string& label) {
+  return label;
+}
+#endif
+
+
 }  // namespace
 
 CommandInfo::CommandInfo()
@@ -383,22 +412,8 @@
     Setup* setup,
     const std::string& label_string) {
   // Need to resolve the label after we know the default toolchain.
-  std::string temp_label = label_string;
-#if defined(OS_WIN)
-  // Git bash will remove the first "/" in "//" paths
-  // Fix "//" paths, but not absolute and relative paths
-  std::unique_ptr<base::Environment> env(base::Environment::Create());
-
-  if (env->HasVar("MSYSTEM") && // Only for MinGW based shells like Git Bash
-      temp_label[0] == '/' && // Only fix for //foo paths, not /f:oo paths
-      (temp_label.length() < 2 ||
-        (temp_label[1] != '/' && (temp_label.length() < 3 ||
-                                  temp_label[1] != ':' ))))
-    temp_label.insert(0, "/");
-#endif
-
   Label default_toolchain = setup->loader()->default_toolchain_label();
-  Value arg_value(nullptr, temp_label);
+  Value arg_value(nullptr, FixGitBashLabelEdit(label_string));
   Err err;
   Label label = Label::Resolve(SourceDirForCurrentDirectory(
                                    setup->build_settings().root_path()),
@@ -485,13 +500,12 @@
                               Err* err) {
   std::vector<std::string> tokens = base::SplitString(
       label_list_string, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-  SourceDir root_dir =
-      SourceDirForCurrentDirectory(build_settings->root_path());
+  SourceDir root_dir("//");
 
   filters->reserve(tokens.size());
   for (const std::string& token : tokens) {
-    LabelPattern pattern =
-        LabelPattern::GetPattern(root_dir, Value(nullptr, token), err);
+    LabelPattern pattern = LabelPattern::GetPattern(
+        root_dir, Value(nullptr, FixGitBashLabelEdit(token)), err);
     if (err->has_error())
       return false;
     filters->push_back(pattern);