Skip to content

Commit 01ea2f4

Browse files
committed
refactor(installer): revert to lean installer logic from ee23346; fix macOS path via Application.platform; escape pgrep pattern
1 parent ce1104e commit 01ea2f4

File tree

1 file changed

+26
-245
lines changed

1 file changed

+26
-245
lines changed

UnityMcpBridge/Editor/Helpers/ServerInstaller.cs

Lines changed: 26 additions & 245 deletions
Original file line numberDiff line numberDiff line change
@@ -67,23 +67,6 @@ public static void EnsureServerInstalled()
6767
|| (!string.IsNullOrEmpty(embeddedVer) && CompareSemverSafe(legacyVer, embeddedVer) < 0);
6868
if (legacyOlder)
6969
{
70-
// If referenced, attempt to rewire known configs (EditorPrefs, Cursor) to canonical
71-
bool stillRef = IsPathPossiblyReferencedByPrefsOrKnownConfigs(legacySrc);
72-
if (stillRef)
73-
{
74-
bool rewired = TryRewriteKnownConfigsToCanonical(legacySrc, destSrc);
75-
if (rewired)
76-
{
77-
McpLog.Info($"Rewired configs from legacy '{legacySrc}' to canonical '{destSrc}'.", always: false);
78-
}
79-
stillRef = IsPathPossiblyReferencedByPrefsOrKnownConfigs(legacySrc);
80-
}
81-
// If still referenced after rewrite attempts, skip deletion
82-
if (stillRef)
83-
{
84-
McpLog.Info($"Skipping removal of legacy server at '{legacyRoot}' (still referenced).", always: false);
85-
continue;
86-
}
8770
TryKillUvForPath(legacySrc);
8871
try
8972
{
@@ -134,24 +117,20 @@ public static string GetServerPath()
134117
/// </summary>
135118
private static string GetSaveLocation()
136119
{
137-
// Prefer Unity's platform to avoid RuntimeInformation quirks under Mono/macOS
120+
// Prefer Unity's platform first (more reliable under Mono/macOS), then fallback
138121
try
139122
{
140123
if (Application.platform == RuntimePlatform.OSXEditor)
141124
{
142125
string home = Environment.GetFolderPath(Environment.SpecialFolder.Personal) ?? string.Empty;
143126
string appSupport = Path.Combine(home, "Library", "Application Support");
144-
string path = Path.Combine(appSupport, RootFolder);
145-
McpLog.Info($"Resolved canonical install root (macOS): {path}", always: false);
146-
return path;
127+
return Path.Combine(appSupport, RootFolder);
147128
}
148129
if (Application.platform == RuntimePlatform.WindowsEditor)
149130
{
150131
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
151132
?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty, "AppData", "Local");
152-
string path = Path.Combine(localAppData, RootFolder);
153-
McpLog.Info($"Resolved canonical install root (Windows): {path}", always: false);
154-
return path;
133+
return Path.Combine(localAppData, RootFolder);
155134
}
156135
if (Application.platform == RuntimePlatform.LinuxEditor)
157136
{
@@ -160,19 +139,12 @@ private static string GetSaveLocation()
160139
{
161140
xdg = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty, ".local", "share");
162141
}
163-
string path = Path.Combine(xdg, RootFolder);
164-
McpLog.Info($"Resolved canonical install root (Linux): {path}", always: false);
165-
return path;
142+
return Path.Combine(xdg, RootFolder);
166143
}
167144
}
168145
catch { }
169146

170-
// Fallback to RuntimeInformation if Application.platform is unavailable
171-
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
172-
{
173-
string home = Environment.GetFolderPath(Environment.SpecialFolder.Personal) ?? string.Empty;
174-
return Path.Combine(home, "Library", "Application Support", RootFolder);
175-
}
147+
// Fallback to RuntimeInformation
176148
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
177149
{
178150
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
@@ -182,9 +154,17 @@ private static string GetSaveLocation()
182154
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
183155
{
184156
var xdg = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
185-
if (string.IsNullOrEmpty(xdg)) xdg = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty, ".local", "share");
157+
if (string.IsNullOrEmpty(xdg))
158+
{
159+
xdg = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty, ".local", "share");
160+
}
186161
return Path.Combine(xdg, RootFolder);
187162
}
163+
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
164+
{
165+
string home = Environment.GetFolderPath(Environment.SpecialFolder.Personal) ?? string.Empty;
166+
return Path.Combine(home, "Library", "Application Support", RootFolder);
167+
}
188168
throw new Exception("Unsupported operating system.");
189169
}
190170

@@ -297,200 +277,6 @@ private static bool PathsEqualSafe(string a, string b)
297277
catch { return false; }
298278
}
299279

300-
private static bool IsPathPossiblyReferencedByPrefsOrKnownConfigs(string serverSrcPath)
301-
{
302-
try
303-
{
304-
if (string.IsNullOrEmpty(serverSrcPath)) return false;
305-
306-
// EditorPrefs overrides
307-
try
308-
{
309-
string prefServerSrc = EditorPrefs.GetString("MCPForUnity.ServerSrc", string.Empty) ?? string.Empty;
310-
if (!string.IsNullOrEmpty(prefServerSrc) && PathsEqualSafe(prefServerSrc, serverSrcPath)) return true;
311-
312-
string prefOverride = EditorPrefs.GetString("MCPForUnity.PythonDirOverride", string.Empty) ?? string.Empty;
313-
if (!string.IsNullOrEmpty(prefOverride) && PathsEqualSafe(prefOverride, serverSrcPath)) return true;
314-
}
315-
catch { }
316-
317-
// Cursor config (~/.cursor/mcp.json)
318-
string user = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty;
319-
string cursorCfg = Path.Combine(user, ".cursor", "mcp.json");
320-
if (File.Exists(cursorCfg))
321-
{
322-
try
323-
{
324-
string json = File.ReadAllText(cursorCfg);
325-
string dir = ExtractDirectoryArgFromJson(json);
326-
if (!string.IsNullOrEmpty(dir) && PathsEqualSafe(dir, serverSrcPath)) return true;
327-
}
328-
catch { }
329-
}
330-
}
331-
catch { }
332-
return false;
333-
}
334-
335-
private static bool TryRewriteKnownConfigsToCanonical(string legacySrc, string canonicalSrc)
336-
{
337-
bool changed = false;
338-
try
339-
{
340-
// Normalize for comparison
341-
string normLegacy = NormalizePathSafe(legacySrc);
342-
string normCanon = NormalizePathSafe(canonicalSrc);
343-
344-
// EditorPrefs
345-
try
346-
{
347-
string prefServerSrc = EditorPrefs.GetString("MCPForUnity.ServerSrc", string.Empty) ?? string.Empty;
348-
if (!string.IsNullOrEmpty(prefServerSrc) && PathsEqualSafe(prefServerSrc, normLegacy))
349-
{
350-
EditorPrefs.SetString("MCPForUnity.ServerSrc", normCanon);
351-
changed = true;
352-
}
353-
string prefOverride = EditorPrefs.GetString("MCPForUnity.PythonDirOverride", string.Empty) ?? string.Empty;
354-
if (!string.IsNullOrEmpty(prefOverride) && PathsEqualSafe(prefOverride, normLegacy))
355-
{
356-
EditorPrefs.SetString("MCPForUnity.PythonDirOverride", normCanon);
357-
changed = true;
358-
}
359-
}
360-
catch { }
361-
362-
// Cursor config (~/.cursor/mcp.json)
363-
try
364-
{
365-
string user = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty;
366-
string cursorCfg = Path.Combine(user, ".cursor", "mcp.json");
367-
if (File.Exists(cursorCfg))
368-
{
369-
string json = File.ReadAllText(cursorCfg);
370-
string currentDir = ExtractDirectoryArgFromJson(json);
371-
if (!string.IsNullOrEmpty(currentDir) && PathsEqualSafe(currentDir, normLegacy))
372-
{
373-
string updated = ReplaceDirectoryArgInJson(json, normCanon);
374-
if (!string.IsNullOrEmpty(updated) && !string.Equals(updated, json, StringComparison.Ordinal))
375-
{
376-
try
377-
{
378-
string backup = cursorCfg + ".bak";
379-
File.Copy(cursorCfg, backup, overwrite: true);
380-
}
381-
catch { }
382-
File.WriteAllText(cursorCfg, updated);
383-
changed = true;
384-
}
385-
}
386-
}
387-
}
388-
catch { }
389-
}
390-
catch { }
391-
return changed;
392-
}
393-
394-
// Best-effort: rewrite the value following --directory in the first args array found
395-
private static string ReplaceDirectoryArgInJson(string json, string newDirectory)
396-
{
397-
try
398-
{
399-
if (string.IsNullOrEmpty(json)) return json;
400-
int argsIdx = json.IndexOf("\"args\"", StringComparison.OrdinalIgnoreCase);
401-
if (argsIdx < 0) return json;
402-
int arrStart = json.IndexOf('[', argsIdx);
403-
if (arrStart < 0) return json;
404-
int depth = 0;
405-
int arrEnd = -1;
406-
for (int i = arrStart; i < json.Length; i++)
407-
{
408-
char c = json[i];
409-
if (c == '[') depth++;
410-
else if (c == ']') { depth--; if (depth == 0) { arrEnd = i; break; } }
411-
}
412-
if (arrEnd <= arrStart) return json;
413-
414-
string arrBody = json.Substring(arrStart + 1, arrEnd - arrStart - 1);
415-
// Split simple string array by commas at top level
416-
string[] raw = arrBody.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
417-
var parts = new List<string>(raw.Length);
418-
foreach (var r in raw)
419-
{
420-
string s = r.Trim();
421-
if (s.Length >= 2 && s[0] == '"' && s[s.Length - 1] == '"')
422-
{
423-
s = s.Substring(1, s.Length - 2);
424-
}
425-
parts.Add(s);
426-
}
427-
428-
for (int i = 0; i < parts.Count - 1; i++)
429-
{
430-
if (string.Equals(parts[i], "--directory", StringComparison.OrdinalIgnoreCase))
431-
{
432-
parts[i + 1] = newDirectory;
433-
// Rebuild array JSON
434-
var sb = new StringBuilder();
435-
for (int j = 0; j < parts.Count; j++)
436-
{
437-
if (j > 0) sb.Append(", ");
438-
sb.Append('"').Append(parts[j].Replace("\\", "\\\\").Replace("\"", "\\\"")).Append('"');
439-
}
440-
string newArr = sb.ToString();
441-
string rebuilt = json.Substring(0, arrStart + 1) + newArr + json.Substring(arrEnd);
442-
return rebuilt;
443-
}
444-
}
445-
}
446-
catch { }
447-
return json;
448-
}
449-
450-
// Minimal helper to extract the value following a --directory token in a plausible JSON args array
451-
private static string ExtractDirectoryArgFromJson(string json)
452-
{
453-
try
454-
{
455-
if (string.IsNullOrEmpty(json)) return null;
456-
int argsIdx = json.IndexOf("\"args\"", StringComparison.OrdinalIgnoreCase);
457-
if (argsIdx < 0) return null;
458-
int arrStart = json.IndexOf('[', argsIdx);
459-
if (arrStart < 0) return null;
460-
int depth = 0;
461-
int arrEnd = -1;
462-
for (int i = arrStart; i < json.Length; i++)
463-
{
464-
char c = json[i];
465-
if (c == '[') depth++;
466-
else if (c == ']') { depth--; if (depth == 0) { arrEnd = i; break; } }
467-
}
468-
if (arrEnd <= arrStart) return null;
469-
string arrBody = json.Substring(arrStart + 1, arrEnd - arrStart - 1);
470-
// Split on commas at top-level (best effort for simple arrays of strings)
471-
string[] raw = arrBody.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
472-
var parts = new List<string>(raw.Length);
473-
foreach (var r in raw)
474-
{
475-
string s = r.Trim();
476-
if (s.Length >= 2 && s[0] == '"' && s[s.Length - 1] == '"')
477-
{
478-
s = s.Substring(1, s.Length - 2);
479-
}
480-
parts.Add(s);
481-
}
482-
for (int i = 0; i < parts.Count - 1; i++)
483-
{
484-
if (string.Equals(parts[i], "--directory", StringComparison.OrdinalIgnoreCase))
485-
{
486-
return parts[i + 1];
487-
}
488-
}
489-
}
490-
catch { }
491-
return null;
492-
}
493-
494280
private static IEnumerable<string> GetLegacyRootsForDetection()
495281
{
496282
var roots = new System.Collections.Generic.List<string>();
@@ -544,37 +330,32 @@ private static void TryKillUvForPath(string serverSrcPath)
544330
catch { }
545331
}
546332

547-
private static string ReadVersionFile(string path)
548-
{
549-
try
550-
{
551-
if (string.IsNullOrEmpty(path) || !File.Exists(path)) return null;
552-
string v = File.ReadAllText(path).Trim();
553-
return string.IsNullOrEmpty(v) ? null : v;
554-
}
555-
catch { return null; }
556-
}
557-
558333
// Escape regex metacharacters so the path is treated literally by pgrep -f
559334
private static string EscapeForPgrep(string path)
560335
{
561336
if (string.IsNullOrEmpty(path)) return path;
562-
// Escape backslash first, then regex metacharacters
563337
string s = path.Replace("\\", "\\\\");
564338
char[] meta = new[] {'.','+','*','?','^','$','(',')','[',']','{','}','|'};
565339
var sb = new StringBuilder(s.Length * 2);
566340
foreach (char c in s)
567341
{
568-
if (Array.IndexOf(meta, c) >= 0)
569-
{
570-
sb.Append('\\');
571-
}
342+
if (Array.IndexOf(meta, c) >= 0) sb.Append('\\');
572343
sb.Append(c);
573344
}
574-
// Also escape double quotes which we wrap the pattern with
575345
return sb.ToString().Replace("\"", "\\\"");
576346
}
577347

348+
private static string ReadVersionFile(string path)
349+
{
350+
try
351+
{
352+
if (string.IsNullOrEmpty(path) || !File.Exists(path)) return null;
353+
string v = File.ReadAllText(path).Trim();
354+
return string.IsNullOrEmpty(v) ? null : v;
355+
}
356+
catch { return null; }
357+
}
358+
578359
private static int CompareSemverSafe(string a, string b)
579360
{
580361
try

0 commit comments

Comments
 (0)