Initial commit to new repository
This commit is contained in:
80
src/AxCopilot/Services/RuntimeDetector.cs
Normal file
80
src/AxCopilot/Services/RuntimeDetector.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace AxCopilot.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 런타임 환경(Python, Node.js 등) 설치 여부를 감지하는 정적 헬퍼.
|
||||
/// 스킬 시스템에서 런타임 의존 스킬의 가용성을 판단하는 데 사용합니다.
|
||||
/// 결과는 5분간 캐시되어 반복 호출 시 프로세스 생성을 최소화합니다.
|
||||
/// </summary>
|
||||
public static class RuntimeDetector
|
||||
{
|
||||
private static Dictionary<string, bool>? _cache;
|
||||
private static DateTime _cacheTime;
|
||||
private static readonly TimeSpan CacheTtl = TimeSpan.FromMinutes(5);
|
||||
|
||||
/// <summary>지정된 런타임이 설치되어 PATH에서 접근 가능한지 확인합니다.</summary>
|
||||
/// <param name="runtime">런타임 이름 (python, node, dotnet 등)</param>
|
||||
public static bool IsAvailable(string runtime)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(runtime)) return true;
|
||||
runtime = runtime.Trim().ToLowerInvariant();
|
||||
|
||||
// 캐시 확인
|
||||
if (_cache != null && (DateTime.UtcNow - _cacheTime) < CacheTtl)
|
||||
{
|
||||
if (_cache.TryGetValue(runtime, out var cached))
|
||||
return cached;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cache = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
|
||||
_cacheTime = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
var available = DetectRuntime(runtime);
|
||||
_cache[runtime] = available;
|
||||
return available;
|
||||
}
|
||||
|
||||
/// <summary>캐시를 강제로 초기화합니다.</summary>
|
||||
public static void ClearCache() => _cache = null;
|
||||
|
||||
private static bool DetectRuntime(string runtime)
|
||||
{
|
||||
// 1단계: where.exe로 PATH 존재 확인
|
||||
var wherePath = RunQuick("where.exe", runtime);
|
||||
if (string.IsNullOrEmpty(wherePath)) return false;
|
||||
|
||||
// 2단계: --version으로 실행 가능 확인
|
||||
var versionArg = runtime switch
|
||||
{
|
||||
"java" => "-version",
|
||||
_ => "--version",
|
||||
};
|
||||
var version = RunQuick(runtime, versionArg);
|
||||
return !string.IsNullOrEmpty(version);
|
||||
}
|
||||
|
||||
private static string? RunQuick(string exe, string args)
|
||||
{
|
||||
try
|
||||
{
|
||||
var psi = new ProcessStartInfo(exe, args)
|
||||
{
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
using var proc = Process.Start(psi);
|
||||
if (proc == null) return null;
|
||||
var output = proc.StandardOutput.ReadToEnd();
|
||||
var error = proc.StandardError.ReadToEnd();
|
||||
proc.WaitForExit(5000);
|
||||
var result = string.IsNullOrWhiteSpace(output) ? error : output;
|
||||
return string.IsNullOrWhiteSpace(result) ? null : result.Trim();
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user