SOLID refactoring: Abstract prerequisite checks into IPrerequisiteVerifier to bypass physical OS checks and fix Gitea CI/CD test run
Build and Test / build (push) Successful in 1m14s
Build and Test / build (push) Successful in 1m14s
This commit is contained in:
@@ -4,6 +4,10 @@
|
||||
<ProjectReference Include="..\NixWslWrapper.Core\NixWslWrapper.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Spectre.Console" Version="0.57.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NixWslWrapper.Core.Interfaces;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace NixWslWrapper.Infrastructure.Services
|
||||
{
|
||||
public class WslPrerequisiteVerifier : IPrerequisiteVerifier
|
||||
{
|
||||
public void EnsurePrerequisites(string distro, string user, string profilePath)
|
||||
{
|
||||
EnsurePathRegistered();
|
||||
EnsureWslAndDistro(distro);
|
||||
EnsureNix(distro, user, profilePath);
|
||||
}
|
||||
|
||||
private void EnsurePathRegistered()
|
||||
{
|
||||
try
|
||||
{
|
||||
string currentExeDir = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule?.FileName) ?? AppContext.BaseDirectory;
|
||||
currentExeDir = Path.GetFullPath(currentExeDir).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
|
||||
string? userPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User);
|
||||
var paths = (userPath ?? "")
|
||||
.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(p => Path.GetFullPath(p.Trim()).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar))
|
||||
.ToList();
|
||||
|
||||
if (!paths.Any(p => string.Equals(p, currentExeDir, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
string newPath = string.IsNullOrWhiteSpace(userPath)
|
||||
? currentExeDir
|
||||
: userPath.TrimEnd(';') + ";" + currentExeDir;
|
||||
|
||||
Environment.SetEnvironmentVariable("PATH", newPath, EnvironmentVariableTarget.User);
|
||||
|
||||
var pathPanel = new Panel(new Markup(
|
||||
$"[bold yellow]PATH Updated:[/] Added [green]\"{currentExeDir}\"[/] to your Windows User PATH.\n" +
|
||||
"Please [bold]restart your terminal, MCP servers, or IDE[/] for changes to take effect."
|
||||
))
|
||||
{
|
||||
Border = BoxBorder.Rounded,
|
||||
Padding = new Padding(1, 1, 1, 1),
|
||||
Header = new PanelHeader("PATH Auto-Registration")
|
||||
};
|
||||
AnsiConsole.Write(pathPanel.BorderColor(Color.Yellow));
|
||||
AnsiConsole.WriteLine();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[yellow]Warning: Could not automatically register directory to PATH: {ex.Message}[/]");
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureWslAndDistro(string distro)
|
||||
{
|
||||
// 1. Check if wsl.exe exists
|
||||
bool wslExists = false;
|
||||
try
|
||||
{
|
||||
var checkWsl = new ProcessStartInfo("wsl.exe", "--status")
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
using var p = Process.Start(checkWsl);
|
||||
p?.WaitForExit(3000);
|
||||
wslExists = p != null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
wslExists = false;
|
||||
}
|
||||
|
||||
if (!wslExists)
|
||||
{
|
||||
var wslPanel = new Panel(new Markup(
|
||||
$"[bold red]WSL Not Found:[/] WSL (Windows Subsystem for Linux) is not installed.\n" +
|
||||
$"Triggering automatic installation of WSL and the [green]{distro}[/] distribution.\n\n" +
|
||||
"[bold yellow]Please approve the administrator UAC prompt that appears.[/]"
|
||||
))
|
||||
{
|
||||
Border = BoxBorder.Double,
|
||||
Header = new PanelHeader("WSL Auto-Installation")
|
||||
};
|
||||
AnsiConsole.Write(wslPanel.BorderColor(Color.Red));
|
||||
|
||||
try
|
||||
{
|
||||
var installPsi = new ProcessStartInfo("wsl.exe", $"--install -d {distro}")
|
||||
{
|
||||
UseShellExecute = true,
|
||||
Verb = "runas" // Elevates to Administrator
|
||||
};
|
||||
using var p = Process.Start(installPsi);
|
||||
p?.WaitForExit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[bold red]Failed to start WSL installation:[/] {ex.Message}");
|
||||
throw new InvalidOperationException("WSL is required to run this wrapper.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Check if the specific distro is installed
|
||||
bool distroInstalled = false;
|
||||
try
|
||||
{
|
||||
var checkDistro = new ProcessStartInfo("wsl.exe", $"-d {distro} -u root -- echo check")
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
using var p = Process.Start(checkDistro);
|
||||
p?.WaitForExit(4000);
|
||||
distroInstalled = p?.ExitCode == 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
distroInstalled = false;
|
||||
}
|
||||
|
||||
if (!distroInstalled)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[yellow]WSL Distro [green]'{distro}'[/] is not registered. Installing it now...[/]");
|
||||
try
|
||||
{
|
||||
var distroPsi = new ProcessStartInfo("wsl.exe", $"--install -d {distro}")
|
||||
{
|
||||
UseShellExecute = true,
|
||||
Verb = "runas"
|
||||
};
|
||||
using var p = Process.Start(distroPsi);
|
||||
p?.WaitForExit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to automatically install WSL distribution '{distro}': {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureNix(string distro, string user, string profilePath)
|
||||
{
|
||||
bool nixInstalled = false;
|
||||
try
|
||||
{
|
||||
var checkNix = new ProcessStartInfo("wsl.exe", $"-d {distro} -u {user} -- sh -c \"command -v nix\"")
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
using var p = Process.Start(checkNix);
|
||||
p?.WaitForExit(4000);
|
||||
nixInstalled = p?.ExitCode == 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
nixInstalled = false;
|
||||
}
|
||||
|
||||
if (!nixInstalled)
|
||||
{
|
||||
var nixPanel = new Panel(new Markup(
|
||||
$"[bold yellow]Nix Engine Not Found:[/] Nix is not installed inside the [green]'{distro}'[/] distribution.\n" +
|
||||
"Triggering automatic installation using the official Determinate Nix installer.\n\n" +
|
||||
"[grey]This may take a few minutes. Please wait...[/]"
|
||||
))
|
||||
{
|
||||
Border = BoxBorder.Rounded,
|
||||
Header = new PanelHeader("Nix Auto-Installation")
|
||||
};
|
||||
AnsiConsole.Write(nixPanel.BorderColor(Color.Yellow));
|
||||
|
||||
try
|
||||
{
|
||||
string installCmd = "curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --no-confirm";
|
||||
var nixPsi = new ProcessStartInfo("wsl.exe", $"-d {distro} -u root -- sh -c \"{installCmd}\"")
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = false,
|
||||
RedirectStandardError = false,
|
||||
CreateNoWindow = false
|
||||
};
|
||||
using var p = Process.Start(nixPsi);
|
||||
p?.WaitForExit();
|
||||
|
||||
if (p?.ExitCode != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Nix installer exited with non-zero code: {p?.ExitCode}");
|
||||
}
|
||||
|
||||
AnsiConsole.MarkupLine("[green]✔ Nix installed successfully inside WSL![/]");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to automatically install Nix inside WSL distro: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user