From 2669a278a9349f88fdab7927232c093f114b4d30 Mon Sep 17 00:00:00 2001 From: "mateusz.krzaczek" Date: Wed, 28 Aug 2024 20:02:21 +0200 Subject: [PATCH] Single exe windows installer progress --- .../.gitignore | 1 + .../MainWindow.xaml | 9 +- .../MainWindow.xaml.cs | 145 +++++++++++++++--- .../build_and_pack.sh | 9 ++ 4 files changed, 145 insertions(+), 19 deletions(-) create mode 100644 windows-installer/AIPG-Omniworker-Windows-Installer/.gitignore create mode 100644 windows-installer/AIPG-Omniworker-Windows-Installer/build_and_pack.sh diff --git a/windows-installer/AIPG-Omniworker-Windows-Installer/.gitignore b/windows-installer/AIPG-Omniworker-Windows-Installer/.gitignore new file mode 100644 index 0000000..91da5ac --- /dev/null +++ b/windows-installer/AIPG-Omniworker-Windows-Installer/.gitignore @@ -0,0 +1 @@ +build/*.* \ No newline at end of file diff --git a/windows-installer/AIPG-Omniworker-Windows-Installer/MainWindow.xaml b/windows-installer/AIPG-Omniworker-Windows-Installer/MainWindow.xaml index 12479ec..2a3de2e 100644 --- a/windows-installer/AIPG-Omniworker-Windows-Installer/MainWindow.xaml +++ b/windows-installer/AIPG-Omniworker-Windows-Installer/MainWindow.xaml @@ -9,7 +9,14 @@ - + + + + + + diff --git a/windows-installer/AIPG-Omniworker-Windows-Installer/MainWindow.xaml.cs b/windows-installer/AIPG-Omniworker-Windows-Installer/MainWindow.xaml.cs index 17cc686..9c25623 100644 --- a/windows-installer/AIPG-Omniworker-Windows-Installer/MainWindow.xaml.cs +++ b/windows-installer/AIPG-Omniworker-Windows-Installer/MainWindow.xaml.cs @@ -1,10 +1,12 @@ using System.Collections.Concurrent; +using System.ComponentModel; using System.Diagnostics; using System.Net.Http; using System.Security.Principal; using System.Text; using System.Windows; using System.Windows.Controls; +using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; @@ -20,6 +22,8 @@ namespace AIPG_Omniworker_Windows_Installer; /// public partial class MainWindow : Window { + private bool _requiresRestart; + public MainWindow() { InitializeComponent(); @@ -70,31 +74,53 @@ await InstallButton.Dispatcher.InvokeAsync(() => await ValidateDocker(); await InstallCuda(); + if(_requiresRestart) + { + AppendLine("Installation requires restart. Please restart your computer and run the installer again."); + MessageBox.Show("Installation requires restart. Please restart your computer and run the installer again."); + return; + } + await InstallOmniworker(); await WaitForOmniworker(); await OpenBrowser(); + + string text = "Installation completed successfully! Open http://localhost:7870 in your browser to access Omniworker."; + AppendLine(text); + MessageBox.Show(text); } catch (Exception e) { AppendLine(e.StackTrace); AppendLine(""); AppendLine("Installation failed:"); - AppendLine(e.Message); + + if(e.GetType() != typeof(Exception)) + { + AppendLine(e.GetType().Name + ": " + e.Message); + } + else + { + AppendLine(e.Message); + } } finally { - await InstallButton.Dispatcher.InvokeAsync(() => + if (!_requiresRestart) { - InstallButton.IsEnabled = true; - InstallButton.Content = "Retry Installation"; - }); + await InstallButton.Dispatcher.InvokeAsync(() => + { + InstallButton.IsEnabled = true; + InstallButton.Content = "Retry Installation"; + }); + } } } private async Task InstallCuda() { - var output = await RunProcessAndGetOutput("nvidia-smi", ""); + var output = await RunProcessAndGetOutputSafe("nvidia-smi", ""); if(output.Any(x => x != null && ( x.Contains("CUDA Version: 12.6", StringComparison.InvariantCultureIgnoreCase) || x.Contains("CUDA Version: 12.5", StringComparison.InvariantCultureIgnoreCase) @@ -107,6 +133,7 @@ private async Task InstallCuda() } await InstallPackage("cuda --version 12.6.0.560"); + _requiresRestart = true; } private async Task WaitForOmniworker() @@ -173,15 +200,39 @@ private static bool IsAdministrator() private async Task OpenBrowser() { - await RunCommand("explorer", "http://localhost:7870"); + await RunProcessAndGetExitCode("explorer", "http://localhost:7870"); } private async Task ValidateDocker() { + if (_requiresRestart) + { + return; + } + if(!(await TryToRunProcess("docker", "--version"))) { throw new Exception("Docker installation failed or computer needs restart. Try to restart your computer and run the installer again."); } + + int code = await RunProcessAndGetExitCode("docker", "ps"); + + if (code != 0) + { + AppendLine("Docker is not running. Trying to start Docker Desktop..."); + + await RunProcessAndGetOutputSafe(@"C:\Program Files\Docker\Docker\Docker Desktop.exe", ""); + + AppendLine("Waiting for Docker engine to start..."); + await Task.Delay(10000); + + code = await RunProcessAndGetExitCode("docker", "ps"); + + if (code != 0) + { + throw new Exception("Docker is not running. Please start Docker Desktop and start the Docker Engine and retry the installation."); + } + } AppendLine("Docker installed successfully"); } @@ -196,53 +247,94 @@ await RunCommand("docker", private async Task InstallDocker() { - var output = await RunProcessAndGetOutput("docker", "--version"); - if(output.Any(x => x != null && x.Contains("Docker version"))) + IReadOnlyList output = null; + + try + { + output = await RunProcessAndGetOutput("docker", "--version"); + } + catch (Win32Exception) + { + AppendLine("Docker not found."); + } + + if(output != null && output.Any(x => x != null && x.Contains("Docker version"))) { AppendLine("Docker already installed"); return; } - await InstallPackage("docker-desktop"); + await InstallPackage("docker-desktop", true); + _requiresRestart = true; } private async Task InstallWsl() { - var processResults = await RunProcessAndGetOutput("wsl", "--version"); + var processResults = await RunProcessAndGetOutputSafe("wsl", "--version"); if (processResults.Any(x => x != null && x.Contains("WSL version: 2.", StringComparison.InvariantCultureIgnoreCase))) { AppendLine("WSL2 already installed"); return; } - if(await TryToRunProcess("wsl", "--install --no-launch --web-download --no-distribution")) + AppendLine("WSL2 Installation not found. Trying to install WSL2 with a build-in windows tool..."); + + try { - return; + if(await TryToRunProcess("wsl", "--install --no-launch --web-download --no-distribution")) + { + return; + } + } + catch (Win32Exception e) + { + AppendLine($"Failed to install WSL2 with build-in Windows feature: {e.Message}"); + AppendLine("Trying to install WSL2 with Chocolatey..."); } - - AppendLine("Failed to install WSL2 with build-in Windows feature. Trying to install with Chocolatey..."); await InstallPackage("wsl2"); + _requiresRestart = true; } - private async Task InstallPackage(string packageName) + private async Task InstallPackage(string packageName, bool force = false) { - await RunCommand("choco", $"install {packageName} -y"); + if (force) + { + await RunCommand("choco", $"install {packageName} -y -force"); + } + else + { + await RunCommand("choco", $"install {packageName} -y"); + } } private async Task InstallChocolatey() { - var output = await RunProcessAndGetOutput("choco", ""); + var output = await RunProcessAndGetOutputSafe("choco", ""); if (output.Any(x => x != null && x.Contains("Chocolatey v"))) { AppendLine("Chocolatey already installed"); return; } + AppendLine("Chocolatey not found."); AppendLine("Installing Chocolatey..."); await RunCommand("powershell.exe", "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iwr https://community.chocolatey.org/install.ps1 -UseBasicParsing | iex"); + + string path = Environment.GetEnvironmentVariable("PATH")!; + path += @";C:\ProgramData\chocolatey\bin"; + Environment.SetEnvironmentVariable("PATH", path); + + output = await RunProcessAndGetOutputSafe("choco", ""); + if (output.Any(x => x != null && x.Contains("Chocolatey v"))) + { + AppendLine("Chocolatey installed successfully"); + return; + } + + throw new Exception("Failed to install Chocolatey"); } private async Task RunCommand(string path, string arguments) @@ -304,6 +396,18 @@ private async Task RunProcessAndGetExitCode(string path, string arguments) return process.ExitCode; } + + private async Task> RunProcessAndGetOutputSafe(string path, string arguments) + { + try + { + return await RunProcessAndGetOutput(path, arguments); + } + catch (Win32Exception e) + { + return new[] {e.Message}; + } + } private async Task> RunProcessAndGetOutput(string path, string arguments) { @@ -366,6 +470,11 @@ private void AppendLine(string text) { text = text.Substring(0, text.Length - Environment.NewLine.Length); } + + if (string.IsNullOrWhiteSpace(text)) + { + return; + } Output.AppendText(text + "\n"); Output.ScrollToEnd(); diff --git a/windows-installer/AIPG-Omniworker-Windows-Installer/build_and_pack.sh b/windows-installer/AIPG-Omniworker-Windows-Installer/build_and_pack.sh new file mode 100644 index 0000000..4b10573 --- /dev/null +++ b/windows-installer/AIPG-Omniworker-Windows-Installer/build_and_pack.sh @@ -0,0 +1,9 @@ +mkdir build +rm bin/Release/net8.0-windows/win-x64/publish/AIPG-Omniworker-Windows-Installer.exe +dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained true +cp bin/Release/net8.0-windows/win-x64/publish/AIPG-Omniworker-Windows-Installer.exe build/AIPG-Omniworker-Windows-Installer.exe +echo "" +echo "" +echo "If build succeeded, the output is in build/AIPG-Omniworker-Windows-Installer.exe" +echo "Press any key to exit..." +read \ No newline at end of file