Browse Source

Merge pull request #33791 from neikeq/issue-33761

C#: Fix PathWhich on Windows when name already has extension
Ignacio Roldán Etcheverry 5 years ago
parent
commit
63b321dbbb

+ 1 - 0
modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj

@@ -30,6 +30,7 @@
     <ConsolePause>false</ConsolePause>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="Mono.Posix" />
     <Reference Include="System" />
     <Reference Include="GodotSharp">
       <HintPath>$(GodotSourceRootPath)/bin/GodotSharp/Api/$(GodotApiConfiguration)/GodotSharp.dll</HintPath>

+ 49 - 37
modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs

@@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.Linq;
 using System.Runtime.CompilerServices;
+using Mono.Unix.Native;
 
 namespace GodotTools.Utils
 {
@@ -55,21 +56,23 @@ namespace GodotTools.Utils
             return name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
         }
 
-        public static bool IsWindows => IsOS(Names.Windows);
-
-        public static bool IsOSX => IsOS(Names.OSX);
-
-        public static bool IsX11 => IsOS(Names.X11);
-
-        public static bool IsServer => IsOS(Names.Server);
-
-        public static bool IsUWP => IsOS(Names.UWP);
-
-        public static bool IsHaiku => IsOS(Names.Haiku);
-
-        public static bool IsAndroid => IsOS(Names.Android);
-
-        public static bool IsHTML5 => IsOS(Names.HTML5);
+        private static readonly Lazy<bool> _isWindows = new Lazy<bool>(() => IsOS(Names.Windows));
+        private static readonly Lazy<bool> _isOSX = new Lazy<bool>(() => IsOS(Names.OSX));
+        private static readonly Lazy<bool> _isX11 = new Lazy<bool>(() => IsOS(Names.X11));
+        private static readonly Lazy<bool> _isServer = new Lazy<bool>(() => IsOS(Names.Server));
+        private static readonly Lazy<bool> _isUWP = new Lazy<bool>(() => IsOS(Names.UWP));
+        private static readonly Lazy<bool> _isHaiku = new Lazy<bool>(() => IsOS(Names.Haiku));
+        private static readonly Lazy<bool> _isAndroid = new Lazy<bool>(() => IsOS(Names.Android));
+        private static readonly Lazy<bool> _isHTML5 = new Lazy<bool>(() => IsOS(Names.HTML5));
+
+        public static bool IsWindows => _isWindows.Value;
+        public static bool IsOSX => _isOSX.Value;
+        public static bool IsX11 => _isX11.Value;
+        public static bool IsServer => _isServer.Value;
+        public static bool IsUWP => _isUWP.Value;
+        public static bool IsHaiku => _isHaiku.Value;
+        public static bool IsAndroid => _isAndroid.Value;
+        public static bool IsHTML5 => _isHTML5.Value;
 
         private static bool? _isUnixCache;
         private static readonly string[] UnixLikePlatforms = {Names.OSX, Names.X11, Names.Server, Names.Haiku, Names.Android};
@@ -88,7 +91,12 @@ namespace GodotTools.Utils
 
         public static string PathWhich(string name)
         {
-            string[] windowsExts = IsWindows ? Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) : null;
+            return IsWindows ? PathWhichWindows(name) : PathWhichUnix(name);
+        }
+
+        private static string PathWhichWindows(string name)
+        {
+            string[] windowsExts = Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) ?? new string[] { };
             string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep);
 
             var searchDirs = new List<string>();
@@ -96,30 +104,34 @@ namespace GodotTools.Utils
             if (pathDirs != null)
                 searchDirs.AddRange(pathDirs);
 
+            string nameExt = Path.GetExtension(name);
+            bool hasPathExt = string.IsNullOrEmpty(nameExt) || windowsExts.Contains(nameExt, StringComparer.OrdinalIgnoreCase);
+
             searchDirs.Add(System.IO.Directory.GetCurrentDirectory()); // last in the list
 
-            foreach (var dir in searchDirs)
-            {
-                string path = Path.Combine(dir, name);
-
-                if (IsWindows && windowsExts != null)
-                {
-                    foreach (var extension in windowsExts)
-                    {
-                        string pathWithExtension = path + extension;
-
-                        if (File.Exists(pathWithExtension))
-                            return pathWithExtension;
-                    }
-                }
-                else
-                {
-                    if (File.Exists(path))
-                        return path;
-                }
-            }
+            if (hasPathExt)
+                return searchDirs.Select(dir => Path.Combine(dir, name)).FirstOrDefault(File.Exists);
+
+            return (from dir in searchDirs
+                select Path.Combine(dir, name)
+                into path
+                from ext in windowsExts
+                select path + ext).FirstOrDefault(File.Exists);
+        }
+
+        private static string PathWhichUnix(string name)
+        {
+            string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep);
+
+            var searchDirs = new List<string>();
+
+            if (pathDirs != null)
+                searchDirs.AddRange(pathDirs);
+
+            searchDirs.Add(System.IO.Directory.GetCurrentDirectory()); // last in the list
 
-            return null;
+            return searchDirs.Select(dir => Path.Combine(dir, name))
+                .FirstOrDefault(path => File.Exists(path) && Syscall.access(path, AccessModes.X_OK) == 0);
         }
 
         public static void RunProcess(string command, IEnumerable<string> arguments)