309 lines
10 KiB
C#
309 lines
10 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
using System.Runtime.InteropServices;
|
||
|
|
using MCPForUnity.Editor.Dependencies.Models;
|
||
|
|
using MCPForUnity.Editor.Dependencies.PlatformDetectors;
|
||
|
|
using MCPForUnity.Editor.Helpers;
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
namespace MCPForUnity.Editor.Dependencies
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Main orchestrator for dependency validation and management
|
||
|
|
/// </summary>
|
||
|
|
public static class DependencyManager
|
||
|
|
{
|
||
|
|
private static readonly List<IPlatformDetector> _detectors = new List<IPlatformDetector>
|
||
|
|
{
|
||
|
|
new WindowsPlatformDetector(),
|
||
|
|
new MacOSPlatformDetector(),
|
||
|
|
new LinuxPlatformDetector()
|
||
|
|
};
|
||
|
|
|
||
|
|
private static IPlatformDetector _currentDetector;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Get the platform detector for the current operating system
|
||
|
|
/// </summary>
|
||
|
|
public static IPlatformDetector GetCurrentPlatformDetector()
|
||
|
|
{
|
||
|
|
if (_currentDetector == null)
|
||
|
|
{
|
||
|
|
_currentDetector = _detectors.FirstOrDefault(d => d.CanDetect);
|
||
|
|
if (_currentDetector == null)
|
||
|
|
{
|
||
|
|
throw new PlatformNotSupportedException($"No detector available for current platform: {RuntimeInformation.OSDescription}");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return _currentDetector;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Perform a comprehensive dependency check
|
||
|
|
/// </summary>
|
||
|
|
public static DependencyCheckResult CheckAllDependencies()
|
||
|
|
{
|
||
|
|
var result = new DependencyCheckResult();
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var detector = GetCurrentPlatformDetector();
|
||
|
|
McpLog.Info($"Checking dependencies on {detector.PlatformName}...", always: false);
|
||
|
|
|
||
|
|
// Check Python
|
||
|
|
var pythonStatus = detector.DetectPython();
|
||
|
|
result.Dependencies.Add(pythonStatus);
|
||
|
|
|
||
|
|
// Check UV
|
||
|
|
var uvStatus = detector.DetectUV();
|
||
|
|
result.Dependencies.Add(uvStatus);
|
||
|
|
|
||
|
|
// Check MCP Server
|
||
|
|
var serverStatus = detector.DetectMCPServer();
|
||
|
|
result.Dependencies.Add(serverStatus);
|
||
|
|
|
||
|
|
// Generate summary and recommendations
|
||
|
|
result.GenerateSummary();
|
||
|
|
GenerateRecommendations(result, detector);
|
||
|
|
|
||
|
|
McpLog.Info($"Dependency check completed. System ready: {result.IsSystemReady}", always: false);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
McpLog.Error($"Error during dependency check: {ex.Message}");
|
||
|
|
result.Summary = $"Dependency check failed: {ex.Message}";
|
||
|
|
result.IsSystemReady = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Quick check if system is ready for MCP operations
|
||
|
|
/// </summary>
|
||
|
|
public static bool IsSystemReady()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var result = CheckAllDependencies();
|
||
|
|
return result.IsSystemReady;
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Get a summary of missing dependencies
|
||
|
|
/// </summary>
|
||
|
|
public static string GetMissingDependenciesSummary()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var result = CheckAllDependencies();
|
||
|
|
var missing = result.GetMissingRequired();
|
||
|
|
|
||
|
|
if (missing.Count == 0)
|
||
|
|
{
|
||
|
|
return "All required dependencies are available.";
|
||
|
|
}
|
||
|
|
|
||
|
|
var names = missing.Select(d => d.Name).ToArray();
|
||
|
|
return $"Missing required dependencies: {string.Join(", ", names)}";
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
return $"Error checking dependencies: {ex.Message}";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Check if a specific dependency is available
|
||
|
|
/// </summary>
|
||
|
|
public static bool IsDependencyAvailable(string dependencyName)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var detector = GetCurrentPlatformDetector();
|
||
|
|
|
||
|
|
return dependencyName.ToLowerInvariant() switch
|
||
|
|
{
|
||
|
|
"python" => detector.DetectPython().IsAvailable,
|
||
|
|
"uv" => detector.DetectUV().IsAvailable,
|
||
|
|
"mcpserver" or "mcp-server" => detector.DetectMCPServer().IsAvailable,
|
||
|
|
_ => false
|
||
|
|
};
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Get installation recommendations for the current platform
|
||
|
|
/// </summary>
|
||
|
|
public static string GetInstallationRecommendations()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var detector = GetCurrentPlatformDetector();
|
||
|
|
return detector.GetInstallationRecommendations();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
return $"Error getting installation recommendations: {ex.Message}";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Get platform-specific installation URLs
|
||
|
|
/// </summary>
|
||
|
|
public static (string pythonUrl, string uvUrl) GetInstallationUrls()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var detector = GetCurrentPlatformDetector();
|
||
|
|
return (detector.GetPythonInstallUrl(), detector.GetUVInstallUrl());
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
return ("https://python.org/downloads/", "https://docs.astral.sh/uv/getting-started/installation/");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Validate that the MCP server can be started
|
||
|
|
/// </summary>
|
||
|
|
public static bool ValidateMCPServerStartup()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
// Check if Python and UV are available
|
||
|
|
if (!IsDependencyAvailable("python") || !IsDependencyAvailable("uv"))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Try to ensure server is installed
|
||
|
|
ServerInstaller.EnsureServerInstalled();
|
||
|
|
|
||
|
|
// Check if server files exist
|
||
|
|
var serverStatus = GetCurrentPlatformDetector().DetectMCPServer();
|
||
|
|
return serverStatus.IsAvailable;
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
McpLog.Error($"Error validating MCP server startup: {ex.Message}");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Attempt to repair the Python environment
|
||
|
|
/// </summary>
|
||
|
|
public static bool RepairPythonEnvironment()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
McpLog.Info("Attempting to repair Python environment...");
|
||
|
|
return ServerInstaller.RepairPythonEnvironment();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
McpLog.Error($"Error repairing Python environment: {ex.Message}");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Get detailed dependency information for diagnostics
|
||
|
|
/// </summary>
|
||
|
|
public static string GetDependencyDiagnostics()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var result = CheckAllDependencies();
|
||
|
|
var detector = GetCurrentPlatformDetector();
|
||
|
|
|
||
|
|
var diagnostics = new System.Text.StringBuilder();
|
||
|
|
diagnostics.AppendLine($"Platform: {detector.PlatformName}");
|
||
|
|
diagnostics.AppendLine($"Check Time: {result.CheckedAt:yyyy-MM-dd HH:mm:ss} UTC");
|
||
|
|
diagnostics.AppendLine($"System Ready: {result.IsSystemReady}");
|
||
|
|
diagnostics.AppendLine();
|
||
|
|
|
||
|
|
foreach (var dep in result.Dependencies)
|
||
|
|
{
|
||
|
|
diagnostics.AppendLine($"=== {dep.Name} ===");
|
||
|
|
diagnostics.AppendLine($"Available: {dep.IsAvailable}");
|
||
|
|
diagnostics.AppendLine($"Required: {dep.IsRequired}");
|
||
|
|
|
||
|
|
if (!string.IsNullOrEmpty(dep.Version))
|
||
|
|
diagnostics.AppendLine($"Version: {dep.Version}");
|
||
|
|
|
||
|
|
if (!string.IsNullOrEmpty(dep.Path))
|
||
|
|
diagnostics.AppendLine($"Path: {dep.Path}");
|
||
|
|
|
||
|
|
if (!string.IsNullOrEmpty(dep.Details))
|
||
|
|
diagnostics.AppendLine($"Details: {dep.Details}");
|
||
|
|
|
||
|
|
if (!string.IsNullOrEmpty(dep.ErrorMessage))
|
||
|
|
diagnostics.AppendLine($"Error: {dep.ErrorMessage}");
|
||
|
|
|
||
|
|
diagnostics.AppendLine();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (result.RecommendedActions.Count > 0)
|
||
|
|
{
|
||
|
|
diagnostics.AppendLine("=== Recommended Actions ===");
|
||
|
|
foreach (var action in result.RecommendedActions)
|
||
|
|
{
|
||
|
|
diagnostics.AppendLine($"- {action}");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return diagnostics.ToString();
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
return $"Error generating diagnostics: {ex.Message}";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void GenerateRecommendations(DependencyCheckResult result, IPlatformDetector detector)
|
||
|
|
{
|
||
|
|
var missing = result.GetMissingDependencies();
|
||
|
|
|
||
|
|
if (missing.Count == 0)
|
||
|
|
{
|
||
|
|
result.RecommendedActions.Add("All dependencies are available. You can start using MCP for Unity.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach (var dep in missing)
|
||
|
|
{
|
||
|
|
if (dep.Name == "Python")
|
||
|
|
{
|
||
|
|
result.RecommendedActions.Add($"Install Python 3.10+ from: {detector.GetPythonInstallUrl()}");
|
||
|
|
}
|
||
|
|
else if (dep.Name == "UV Package Manager")
|
||
|
|
{
|
||
|
|
result.RecommendedActions.Add($"Install UV package manager from: {detector.GetUVInstallUrl()}");
|
||
|
|
}
|
||
|
|
else if (dep.Name == "MCP Server")
|
||
|
|
{
|
||
|
|
result.RecommendedActions.Add("MCP Server will be installed automatically when needed.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (result.GetMissingRequired().Count > 0)
|
||
|
|
{
|
||
|
|
result.RecommendedActions.Add("Use the Setup Wizard (Window > MCP for Unity > Setup Wizard) for guided installation.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|