Find python/python3 from dotfile entries

This is the third (and final?) step in getting gn to properly find
Python3 on Windows. The first attempt got it to translate python3.bat.
The second attempt added the ability to handle python3. This change adds
support for the directive being in the dotfile.

This is all in aid of moving Chromium (and any other projects using
gn) to Python 3.

This has been tested with the recently reverted dotfile change in
Chromium (crrev.com/c/2591588) and it successfully did an otherwise-
failing "gn gen" and a chrome build is succeeding. It was also tested
with "gn gen out\arg --script-executable=python3" and this worked.

Change-Id: I7449a989d488dd107929e997a5e7d21daadd9757
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/10900
Reviewed-by: Brett Wilson <brettw@chromium.org>
Commit-Queue: Brett Wilson <brettw@chromium.org>
diff --git a/src/gn/setup.cc b/src/gn/setup.cc
index 0e3e4a2..0454fd8 100644
--- a/src/gn/setup.cc
+++ b/src/gn/setup.cc
@@ -721,6 +721,28 @@
   return true;
 }
 
+// On Chromium repositories on Windows the Python executable can be specified as
+// python, python.bat, or python.exe (ditto for python3, and with or without a
+// full path specification). This handles all of these cases and returns a fully
+// specified path to a .exe file.
+// This is currently a NOP on other platforms.
+base::FilePath ProcessFileExtensions(base::FilePath script_executable) {
+#if defined(OS_WIN)
+  // If we have a relative path with no extension such as "python" or
+  // "python3" then do a path search on the name with .exe and .bat appended.
+  if (!script_executable.IsAbsolute() &&
+      script_executable.FinalExtension() == u"") {
+    script_executable =
+        FindWindowsPython(script_executable.ReplaceExtension(u".exe"),
+                          script_executable.ReplaceExtension(u".bat"));
+  } else {
+    if (script_executable.FinalExtension() == u".bat")
+      script_executable = PythonBatToExe(script_executable);
+  }
+#endif
+  return script_executable;
+}
+
 bool Setup::FillPythonPath(const base::CommandLine& cmdline, Err* err) {
   // Trace this since it tends to be a bit slow on Windows.
   ScopedTrace setup_trace(TraceItem::TRACE_SETUP, "Fill Python Path");
@@ -728,26 +750,14 @@
   if (cmdline.HasSwitch(switches::kScriptExecutable)) {
     auto script_executable =
         cmdline.GetSwitchValuePath(switches::kScriptExecutable);
-#if defined(OS_WIN)
-    // If we have a relative path with no extension such as "python" or
-    // "python3" then do a path search on the name with .exe and .bat appended.
-    if (!script_executable.IsAbsolute() &&
-        script_executable.FinalExtension() == u"") {
-      script_executable =
-          FindWindowsPython(script_executable.ReplaceExtension(u".exe"),
-                            script_executable.ReplaceExtension(u".bat"));
-    } else {
-      if (script_executable.FinalExtension() == u".bat")
-        script_executable = PythonBatToExe(script_executable);
-    }
-#endif
+    script_executable = ProcessFileExtensions(script_executable);
     build_settings_.set_python_path(script_executable);
   } else if (value) {
     if (!value->VerifyTypeIs(Value::STRING, err)) {
       return false;
     }
     build_settings_.set_python_path(
-        base::FilePath(UTF8ToFilePath(value->string_value())));
+        ProcessFileExtensions(UTF8ToFilePath(value->string_value())));
   } else {
 #if defined(OS_WIN)
     const base::FilePath python_exe_name(u"python.exe");