|
2 | 2 | using System.IO; |
3 | 3 | using System.Runtime.InteropServices; |
4 | 4 | using System.Text; |
5 | | -using System.Reflection; |
6 | 5 | using UnityEditor; |
7 | 6 | using UnityEngine; |
8 | 7 |
|
@@ -70,21 +69,19 @@ private static string GetSaveLocation() |
70 | 69 | { |
71 | 70 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
72 | 71 | { |
73 | | - return Path.Combine( |
74 | | - Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), |
75 | | - "AppData", |
76 | | - "Local", |
77 | | - "Programs", |
78 | | - RootFolder |
79 | | - ); |
| 72 | + var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) |
| 73 | + ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty, "AppData", "Local"); |
| 74 | + return Path.Combine(localAppData, "Programs", RootFolder); |
80 | 75 | } |
81 | 76 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) |
82 | 77 | { |
83 | | - return Path.Combine( |
84 | | - Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), |
85 | | - "bin", |
86 | | - RootFolder |
87 | | - ); |
| 78 | + var xdg = Environment.GetEnvironmentVariable("XDG_DATA_HOME"); |
| 79 | + if (string.IsNullOrEmpty(xdg)) |
| 80 | + { |
| 81 | + xdg = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty, |
| 82 | + ".local", "share"); |
| 83 | + } |
| 84 | + return Path.Combine(xdg, RootFolder); |
88 | 85 | } |
89 | 86 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) |
90 | 87 | { |
@@ -270,19 +267,58 @@ internal static string FindUvPath() |
270 | 267 | string[] candidates; |
271 | 268 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
272 | 269 | { |
| 270 | + string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty; |
| 271 | + string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) ?? string.Empty; |
| 272 | + string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty; |
| 273 | + string programData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) ?? string.Empty; // optional fallback |
| 274 | + |
| 275 | + // Fast path: resolve from PATH first |
| 276 | + try |
| 277 | + { |
| 278 | + var wherePsi = new System.Diagnostics.ProcessStartInfo |
| 279 | + { |
| 280 | + FileName = "where", |
| 281 | + Arguments = "uv.exe", |
| 282 | + UseShellExecute = false, |
| 283 | + RedirectStandardOutput = true, |
| 284 | + RedirectStandardError = true, |
| 285 | + CreateNoWindow = true |
| 286 | + }; |
| 287 | + using var wp = System.Diagnostics.Process.Start(wherePsi); |
| 288 | + string output = wp.StandardOutput.ReadToEnd().Trim(); |
| 289 | + wp.WaitForExit(1500); |
| 290 | + if (wp.ExitCode == 0 && !string.IsNullOrEmpty(output)) |
| 291 | + { |
| 292 | + foreach (var line in output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)) |
| 293 | + { |
| 294 | + string path = line.Trim(); |
| 295 | + if (File.Exists(path) && ValidateUvBinary(path)) return path; |
| 296 | + } |
| 297 | + } |
| 298 | + } |
| 299 | + catch { } |
| 300 | + |
273 | 301 | candidates = new[] |
274 | 302 | { |
| 303 | + // Preferred: WinGet Links shims (stable entrypoints) |
| 304 | + Path.Combine(localAppData, "Microsoft", "WinGet", "Links", "uv.exe"), |
| 305 | + Path.Combine(programFiles, "WinGet", "Links", "uv.exe"), |
| 306 | + // Optional low-priority fallback for atypical images |
| 307 | + Path.Combine(programData, "Microsoft", "WinGet", "Links", "uv.exe"), |
| 308 | + |
275 | 309 | // Common per-user installs |
276 | | - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python313\Scripts\uv.exe"), |
277 | | - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python312\Scripts\uv.exe"), |
278 | | - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python311\Scripts\uv.exe"), |
279 | | - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty, @"Programs\Python\Python310\Scripts\uv.exe"), |
280 | | - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python313\Scripts\uv.exe"), |
281 | | - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python312\Scripts\uv.exe"), |
282 | | - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python311\Scripts\uv.exe"), |
283 | | - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty, @"Python\Python310\Scripts\uv.exe"), |
| 310 | + Path.Combine(localAppData, @"Programs\Python\Python313\Scripts\uv.exe"), |
| 311 | + Path.Combine(localAppData, @"Programs\Python\Python312\Scripts\uv.exe"), |
| 312 | + Path.Combine(localAppData, @"Programs\Python\Python311\Scripts\uv.exe"), |
| 313 | + Path.Combine(localAppData, @"Programs\Python\Python310\Scripts\uv.exe"), |
| 314 | + Path.Combine(appData, @"Python\Python313\Scripts\uv.exe"), |
| 315 | + Path.Combine(appData, @"Python\Python312\Scripts\uv.exe"), |
| 316 | + Path.Combine(appData, @"Python\Python311\Scripts\uv.exe"), |
| 317 | + Path.Combine(appData, @"Python\Python310\Scripts\uv.exe"), |
| 318 | + |
284 | 319 | // Program Files style installs (if a native installer was used) |
285 | | - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) ?? string.Empty, @"uv\uv.exe"), |
| 320 | + Path.Combine(programFiles, @"uv\uv.exe"), |
| 321 | + |
286 | 322 | // Try simple name resolution later via PATH |
287 | 323 | "uv.exe", |
288 | 324 | "uv" |
@@ -315,33 +351,10 @@ internal static string FindUvPath() |
315 | 351 | catch { /* ignore */ } |
316 | 352 | } |
317 | 353 |
|
318 | | - // Use platform-appropriate which/where to resolve from PATH |
| 354 | + // Use platform-appropriate which/where to resolve from PATH (non-Windows handled here; Windows tried earlier) |
319 | 355 | try |
320 | 356 | { |
321 | | - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
322 | | - { |
323 | | - var wherePsi = new System.Diagnostics.ProcessStartInfo |
324 | | - { |
325 | | - FileName = "where", |
326 | | - Arguments = "uv.exe", |
327 | | - UseShellExecute = false, |
328 | | - RedirectStandardOutput = true, |
329 | | - RedirectStandardError = true, |
330 | | - CreateNoWindow = true |
331 | | - }; |
332 | | - using var wp = System.Diagnostics.Process.Start(wherePsi); |
333 | | - string output = wp.StandardOutput.ReadToEnd().Trim(); |
334 | | - wp.WaitForExit(3000); |
335 | | - if (wp.ExitCode == 0 && !string.IsNullOrEmpty(output)) |
336 | | - { |
337 | | - foreach (var line in output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)) |
338 | | - { |
339 | | - string path = line.Trim(); |
340 | | - if (File.Exists(path) && ValidateUvBinary(path)) return path; |
341 | | - } |
342 | | - } |
343 | | - } |
344 | | - else |
| 357 | + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
345 | 358 | { |
346 | 359 | var whichPsi = new System.Diagnostics.ProcessStartInfo |
347 | 360 | { |
|
0 commit comments