diff --git a/StabilityMatrix/Helper/ISettingsManager.cs b/StabilityMatrix/Helper/ISettingsManager.cs index 040e4716..5663023d 100644 --- a/StabilityMatrix/Helper/ISettingsManager.cs +++ b/StabilityMatrix/Helper/ISettingsManager.cs @@ -8,4 +8,6 @@ public interface ISettingsManager void SetTheme(string theme); void AddInstalledPackage(InstalledPackage p); void SetActiveInstalledPackage(InstalledPackage? p); -} \ No newline at end of file + void SetHasInstalledPip(bool hasInstalledPip); + void SetHasInstalledVenv(bool hasInstalledVenv); +} diff --git a/StabilityMatrix/Helper/SettingsManager.cs b/StabilityMatrix/Helper/SettingsManager.cs index dbe3a4b5..55d957ae 100644 --- a/StabilityMatrix/Helper/SettingsManager.cs +++ b/StabilityMatrix/Helper/SettingsManager.cs @@ -55,6 +55,18 @@ public class SettingsManager : ISettingsManager } SaveSettings(); } + + public void SetHasInstalledPip(bool hasInstalledPip) + { + Settings.HasInstalledPip = hasInstalledPip; + SaveSettings(); + } + + public void SetHasInstalledVenv(bool hasInstalledVenv) + { + Settings.HasInstalledVenv = hasInstalledVenv; + SaveSettings(); + } private void LoadSettings() { diff --git a/StabilityMatrix/InstallPage.xaml b/StabilityMatrix/InstallPage.xaml index 1885a09f..c90029ed 100644 --- a/StabilityMatrix/InstallPage.xaml +++ b/StabilityMatrix/InstallPage.xaml @@ -2,12 +2,10 @@ x:Class="StabilityMatrix.InstallPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:local="using:StabilityMatrix" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" xmlns:models="clr-namespace:StabilityMatrix.Models" - xmlns:viewModels="clr-namespace:StabilityMatrix.ViewModels" d:DesignHeight="700" d:DesignWidth="1100" Loaded="InstallPage_OnLoaded" @@ -15,10 +13,6 @@ Foreground="{DynamicResource TextFillColorPrimaryBrush}" mc:Ignorable="d"> - - - - diff --git a/StabilityMatrix/LaunchPage.xaml b/StabilityMatrix/LaunchPage.xaml index e648119b..5457c828 100644 --- a/StabilityMatrix/LaunchPage.xaml +++ b/StabilityMatrix/LaunchPage.xaml @@ -56,6 +56,7 @@ Margin="10,10,10,10" Text="{Binding ConsoleOutput, Mode=OneWay}" FontFamily="Consolas" + TextWrapping="Wrap" Background="{DynamicResource ControlFillColorDisabledBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/> diff --git a/StabilityMatrix/Models/BasePackage.cs b/StabilityMatrix/Models/BasePackage.cs index ac598f81..2c8912bf 100644 --- a/StabilityMatrix/Models/BasePackage.cs +++ b/StabilityMatrix/Models/BasePackage.cs @@ -12,6 +12,7 @@ public abstract class BasePackage public abstract Task DownloadPackage(); internal virtual string DownloadLocation => $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\StabilityMatrix\\Packages\\{Name}.zip"; + internal virtual string InstallLocation => $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\StabilityMatrix\\Packages\\{Name}"; public event EventHandler DownloadProgressChanged; public event EventHandler DownloadComplete; diff --git a/StabilityMatrix/Models/Settings.cs b/StabilityMatrix/Models/Settings.cs index be162818..ddb71aaa 100644 --- a/StabilityMatrix/Models/Settings.cs +++ b/StabilityMatrix/Models/Settings.cs @@ -8,4 +8,6 @@ public class Settings public string Theme { get; set; } public List InstalledPackages { get; set; } = new(); public Guid? ActiveInstalledPackage { get; set; } + public bool HasInstalledPip { get; set; } + public bool HasInstalledVenv { get; set; } } diff --git a/StabilityMatrix/ViewModels/InstallerViewModel.cs b/StabilityMatrix/ViewModels/InstallerViewModel.cs index bf55c23a..3045998d 100644 --- a/StabilityMatrix/ViewModels/InstallerViewModel.cs +++ b/StabilityMatrix/ViewModels/InstallerViewModel.cs @@ -1,26 +1,35 @@ -using System.Collections.ObjectModel; +using System; +using System.Collections.ObjectModel; using System.Threading.Tasks; using StabilityMatrix.Helper; using StabilityMatrix.Models; using System.ComponentModel; using System.Diagnostics; +using System.Dynamic; +using System.IO; +using System.IO.Compression; using System.Runtime.CompilerServices; using StabilityMatrix.Models.Packages; using System.Linq; using System.Windows; using CommunityToolkit.Mvvm.Input; +using Microsoft.Extensions.Logging; namespace StabilityMatrix.ViewModels; public class InstallerViewModel : INotifyPropertyChanged { + private readonly ILogger logger; + private readonly ISettingsManager settingsManager; private string installedText; private int progressValue; private bool isIndeterminate; private BasePackage selectedPackage; - public InstallerViewModel() + public InstallerViewModel(ILogger logger, ISettingsManager settingsManager) { + this.logger = logger; + this.settingsManager = settingsManager; InstalledText = "shrug"; ProgressValue = 0; Packages = new ObservableCollection @@ -85,13 +94,61 @@ public class InstallerViewModel : INotifyPropertyChanged public Visibility ProgressBarVisibility => ProgressValue > 0 || IsIndeterminate ? Visibility.Visible : Visibility.Collapsed; public AsyncRelayCommand InstallCommand => new(async () => + { + var installSuccess = await InstallGitIfNecessary(); + if (!installSuccess) + { + logger.LogError("Git installation failed"); + return; + } + + await DownloadPackage(); + + UnzipPackage(); + + InstalledText = "Installing dependencies..."; + await PyRunner.Initialize(); + if (!settingsManager.Settings.HasInstalledPip) + { + await PyRunner.SetupPip(); + settingsManager.SetHasInstalledPip(true); + } + + if (!settingsManager.Settings.HasInstalledVenv) + { + await PyRunner.InstallPackage("virtualenv"); + settingsManager.SetHasInstalledVenv(true); + } + + InstalledText = "Done"; + + IsIndeterminate = false; + ProgressValue = 100; + + if (settingsManager.Settings.InstalledPackages.FirstOrDefault(x => x.PackageName == SelectedPackage.Name) == + null) + { + var package = new InstalledPackage + { + Name = SelectedPackage.Name, + Path = SelectedPackage.InstallLocation, + Id = Guid.NewGuid(), + PackageName = SelectedPackage.Name, + PackageVersion = "idklol" + }; + settingsManager.AddInstalledPackage(package); + settingsManager.SetActiveInstalledPackage(package); + } + }); + + + private async Task DownloadPackage() { SelectedPackage.DownloadProgressChanged += (_, progress) => { if (progress == -1) { IsIndeterminate = true; - ProgressValue = 1; } else { @@ -100,8 +157,49 @@ public class InstallerViewModel : INotifyPropertyChanged } }; SelectedPackage.DownloadComplete += (_, _) => InstalledText = "Download Complete"; + InstalledText = "Downloading package..."; await SelectedPackage.DownloadPackage(); - }); + } + + private void UnzipPackage() + { + InstalledText = "Unzipping package..."; + ProgressValue = 0; + + Directory.CreateDirectory(SelectedPackage.InstallLocation); + + using var zip = ZipFile.OpenRead(SelectedPackage.DownloadLocation); + var zipDirName = string.Empty; + var totalEntries = zip.Entries.Count; + var currentEntry = 0; + + foreach (var entry in zip.Entries) + { + if (string.IsNullOrWhiteSpace(entry.Name) && entry.FullName.EndsWith("/")) + { + if (string.IsNullOrWhiteSpace(zipDirName)) + { + zipDirName = entry.FullName; + continue; + } + + var folderPath = Path.Combine(SelectedPackage.InstallLocation, + entry.FullName.Replace(zipDirName, string.Empty)); + Directory.CreateDirectory(folderPath); + continue; + } + + + var destinationPath = Path.GetFullPath(Path.Combine(SelectedPackage.InstallLocation, + entry.FullName.Replace(zipDirName, string.Empty))); + entry.ExtractToFile(destinationPath, true); + currentEntry++; + + ProgressValue = (int) ((double) currentEntry / totalEntries * 100); + } + + } + private async Task InstallGitIfNecessary() { var gitOutput = await ProcessRunner.GetProcessOutputAsync("git", "--version"); diff --git a/StabilityMatrix/ViewModels/LaunchViewModel.cs b/StabilityMatrix/ViewModels/LaunchViewModel.cs index 36a39ecd..50a69d2b 100644 --- a/StabilityMatrix/ViewModels/LaunchViewModel.cs +++ b/StabilityMatrix/ViewModels/LaunchViewModel.cs @@ -97,6 +97,10 @@ public partial class LaunchViewModel : ObservableObject public void OnLoaded() { LoadPackages(); + if (InstalledPackages.Any()) + { + SelectedPackage = InstalledPackages[0]; + } } private void LoadPackages() @@ -107,6 +111,8 @@ public partial class LaunchViewModel : ObservableObject return; } + InstalledPackages.Clear(); + foreach (var package in packages) { InstalledPackages.Add(package);