Skip to content

Commit 6476597

Browse files
whatevertogoclaude
andcommitted
fix: 修复平台检测器的路径解析和 Python 版本检测问题
- 通用化 FindUvxExecutableInPath 方法,支持查找任意命令名(uv/uvx) - 修复 BuildAugmentedPath PATH 重复拼接问题 - 修复 Python 版本检测,同时检查 stdout 和 stderr - 统一三个平台检测器的实现逻辑 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 84cee8c commit 6476597

4 files changed

Lines changed: 101 additions & 54 deletions

File tree

MCPForUnity/Editor/Dependencies/PlatformDetectors/LinuxPlatformDetector.cs

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -141,22 +141,14 @@ private bool TryValidatePython(string pythonPath, out string version, out string
141141

142142
try
143143
{
144-
var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
145-
var pathAdditions = new[]
146-
{
147-
"/usr/local/bin",
148-
"/usr/bin",
149-
"/bin",
150-
"/snap/bin",
151-
Path.Combine(homeDir, ".local", "bin")
152-
};
153-
string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? "");
144+
string augmentedPath = BuildAugmentedPath();
154145

155146
if (!ExecPath.TryRun(pythonPath, "--version", null, out string stdout, out string stderr,
156147
5000, augmentedPath))
157148
return false;
158149

159-
string output = stdout.Trim();
150+
// Check stdout first, then stderr (some Python distributions output to stderr)
151+
string output = !string.IsNullOrWhiteSpace(stdout) ? stdout.Trim() : stderr.Trim();
160152
if (output.StartsWith("Python "))
161153
{
162154
version = output.Substring(7);
@@ -193,6 +185,7 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str
193185
if (output.StartsWith("uv ") || output.StartsWith("uvx "))
194186
{
195187
// Extract version: "uvx 0.9.18" -> "0.9.18"
188+
// Handle extra tokens: "uvx 0.9.18 extra" or "uvx 0.9.18 (build info)"
196189
int spaceIndex = output.IndexOf(' ');
197190
if (spaceIndex >= 0)
198191
{
@@ -219,8 +212,13 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str
219212

220213
private string BuildAugmentedPath()
221214
{
215+
var additions = GetPathAdditions();
216+
if (additions.Length == 0) return null;
217+
222218
string currentPath = Environment.GetEnvironmentVariable("PATH") ?? "";
223-
return string.Join(":", GetPathAdditions()) + ":" + currentPath;
219+
return string.IsNullOrEmpty(currentPath)
220+
? string.Join(Path.PathSeparator, additions)
221+
: string.Join(Path.PathSeparator, additions) + Path.PathSeparator + currentPath;
224222
}
225223

226224
private string[] GetPathAdditions()
@@ -242,16 +240,7 @@ private bool TryFindInPath(string executable, out string fullPath)
242240

243241
try
244242
{
245-
var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
246-
var pathAdditions = new[]
247-
{
248-
"/usr/local/bin",
249-
"/usr/bin",
250-
"/bin",
251-
"/snap/bin",
252-
Path.Combine(homeDir, ".local", "bin")
253-
};
254-
string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? "");
243+
string augmentedPath = BuildAugmentedPath();
255244

256245
if (!ExecPath.TryRun("/usr/bin/which", executable, null, out string stdout, out _, 3000, augmentedPath))
257246
return false;

MCPForUnity/Editor/Dependencies/PlatformDetectors/MacOSPlatformDetector.cs

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -139,21 +139,14 @@ private bool TryValidatePython(string pythonPath, out string version, out string
139139

140140
try
141141
{
142-
var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
143-
var pathAdditions = new[]
144-
{
145-
"/opt/homebrew/bin",
146-
"/usr/local/bin",
147-
"/usr/bin",
148-
Path.Combine(homeDir, ".local", "bin")
149-
};
150-
string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? "");
142+
string augmentedPath = BuildAugmentedPath();
151143

152144
if (!ExecPath.TryRun(pythonPath, "--version", null, out string stdout, out string stderr,
153145
5000, augmentedPath))
154146
return false;
155147

156-
string output = stdout.Trim();
148+
// Check stdout first, then stderr (some Python distributions output to stderr)
149+
string output = !string.IsNullOrWhiteSpace(stdout) ? stdout.Trim() : stderr.Trim();
157150
if (output.StartsWith("Python "))
158151
{
159152
version = output.Substring(7);
@@ -216,9 +209,13 @@ private bool TryValidateUvWithPath(string command, string augmentedPath, out str
216209

217210
private string BuildAugmentedPath()
218211
{
219-
var pathAdditions = GetPathAdditions();
212+
var additions = GetPathAdditions();
213+
if (additions.Length == 0) return null;
214+
220215
string currentPath = Environment.GetEnvironmentVariable("PATH") ?? "";
221-
return string.Join(":", pathAdditions) + ":" + currentPath;
216+
return string.IsNullOrEmpty(currentPath)
217+
? string.Join(Path.PathSeparator, additions)
218+
: string.Join(Path.PathSeparator, additions) + Path.PathSeparator + currentPath;
222219
}
223220

224221
private string[] GetPathAdditions()
@@ -240,16 +237,7 @@ private bool TryFindInPath(string executable, out string fullPath)
240237

241238
try
242239
{
243-
var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
244-
var pathAdditions = new[]
245-
{
246-
"/opt/homebrew/bin",
247-
"/usr/local/bin",
248-
"/usr/bin",
249-
"/bin",
250-
Path.Combine(homeDir, ".local", "bin")
251-
};
252-
string augmentedPath = string.Join(":", pathAdditions) + ":" + (Environment.GetEnvironmentVariable("PATH") ?? "");
240+
string augmentedPath = BuildAugmentedPath();
253241

254242
if (!ExecPath.TryRun("/usr/bin/which", executable, null, out string stdout, out _, 3000, augmentedPath))
255243
return false;

MCPForUnity/Editor/Dependencies/PlatformDetectors/WindowsPlatformDetector.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,8 @@ private bool TryValidatePython(string pythonPath, out string version, out string
151151
if (!ExecPath.TryRun(pythonPath, "--version", null, out string stdout, out string stderr, 5000, augmentedPath))
152152
return false;
153153

154-
string output = stdout.Trim();
154+
// Check stdout first, then stderr (some Python distributions output to stderr)
155+
string output = !string.IsNullOrWhiteSpace(stdout) ? stdout.Trim() : stderr.Trim();
155156
if (output.StartsWith("Python "))
156157
{
157158
version = output.Substring(7);
@@ -199,8 +200,13 @@ private bool TryFindInPath(string executable, out string fullPath)
199200

200201
private string BuildAugmentedPath()
201202
{
203+
var additions = GetPathAdditions();
204+
if (additions.Length == 0) return null;
205+
202206
string currentPath = Environment.GetEnvironmentVariable("PATH") ?? "";
203-
return string.Join(Path.PathSeparator, GetPathAdditions()) + Path.PathSeparator + currentPath;
207+
return string.IsNullOrEmpty(currentPath)
208+
? string.Join(Path.PathSeparator, additions)
209+
: string.Join(Path.PathSeparator, additions) + Path.PathSeparator + currentPath;
204210
}
205211

206212
private string[] GetPathAdditions()
@@ -239,7 +245,7 @@ private string[] GetPathAdditions()
239245
if (!string.IsNullOrEmpty(homeDir))
240246
additions.Add(Path.Combine(homeDir, ".local", "bin"));
241247

242-
return additions.Where(Directory.Exists).ToArray();
248+
return additions.ToArray();
243249
}
244250
}
245251
}

MCPForUnity/Editor/Services/PathResolverService.cs

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -309,20 +309,26 @@ private string FindUvxExecutableInPath(string commandName)
309309
? commandName + ".exe"
310310
: commandName;
311311

312-
// First try EnumerateUvxCandidates which checks File.Exists
313-
foreach (string candidate in EnumerateUvxCandidates())
312+
// Try command-specific candidates first (for uvx, use EnumerateUvxCandidates)
313+
if (commandName.Equals("uvx", StringComparison.OrdinalIgnoreCase))
314314
{
315-
if (!string.IsNullOrEmpty(candidate) && File.Exists(candidate))
315+
foreach (string candidate in EnumerateUvxCandidates())
316316
{
317-
// Check if this candidate matches our command name
318-
string candidateName = Path.GetFileName(candidate);
319-
if (candidateName.Equals(exeName, StringComparison.OrdinalIgnoreCase) ||
320-
candidateName.Equals(commandName, StringComparison.OrdinalIgnoreCase))
317+
if (!string.IsNullOrEmpty(candidate) && File.Exists(candidate))
321318
{
322319
return candidate;
323320
}
324321
}
325322
}
323+
324+
// Generic search for any command in PATH and common locations
325+
foreach (string candidate in EnumerateCommandCandidates(commandName))
326+
{
327+
if (!string.IsNullOrEmpty(candidate) && File.Exists(candidate))
328+
{
329+
return candidate;
330+
}
331+
}
326332
}
327333
catch
328334
{
@@ -331,5 +337,63 @@ private string FindUvxExecutableInPath(string commandName)
331337

332338
return null;
333339
}
340+
341+
/// <summary>
342+
/// Enumerates candidate paths for a generic command name.
343+
/// Searches PATH and common installation locations.
344+
/// </summary>
345+
private static IEnumerable<string> EnumerateCommandCandidates(string commandName)
346+
{
347+
string exeName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !commandName.EndsWith(".exe")
348+
? commandName + ".exe"
349+
: commandName;
350+
351+
// Search PATH first
352+
string pathEnv = Environment.GetEnvironmentVariable("PATH");
353+
if (!string.IsNullOrEmpty(pathEnv))
354+
{
355+
foreach (string rawDir in pathEnv.Split(Path.PathSeparator))
356+
{
357+
if (string.IsNullOrWhiteSpace(rawDir)) continue;
358+
string dir = rawDir.Trim();
359+
yield return Path.Combine(dir, exeName);
360+
}
361+
}
362+
363+
// User-local binary directories
364+
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
365+
if (!string.IsNullOrEmpty(home))
366+
{
367+
yield return Path.Combine(home, ".local", "bin", exeName);
368+
yield return Path.Combine(home, ".cargo", "bin", exeName);
369+
}
370+
371+
// System directories (platform-specific)
372+
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
373+
{
374+
yield return "/opt/homebrew/bin/" + exeName;
375+
yield return "/usr/local/bin/" + exeName;
376+
}
377+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
378+
{
379+
yield return "/usr/local/bin/" + exeName;
380+
yield return "/usr/bin/" + exeName;
381+
}
382+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
383+
{
384+
string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
385+
string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
386+
387+
if (!string.IsNullOrEmpty(localAppData))
388+
{
389+
yield return Path.Combine(localAppData, "Programs", "uv", exeName);
390+
}
391+
392+
if (!string.IsNullOrEmpty(programFiles))
393+
{
394+
yield return Path.Combine(programFiles, "uv", exeName);
395+
}
396+
}
397+
}
334398
}
335399
}

0 commit comments

Comments
 (0)