From 105f402936de357b648a09e323386d9268978b9c Mon Sep 17 00:00:00 2001 From: Philipp Heenemann Date: Sun, 18 Jun 2023 15:21:50 +0200 Subject: [PATCH 1/7] Adding initial size comparison between eft dir and target dir --- SPTInstaller/Helpers/DirectorySizeHelper.cs | 46 +++++++++++++++++++ .../Installer Tasks/IntializationTask.cs | 7 +++ 2 files changed, 53 insertions(+) create mode 100644 SPTInstaller/Helpers/DirectorySizeHelper.cs diff --git a/SPTInstaller/Helpers/DirectorySizeHelper.cs b/SPTInstaller/Helpers/DirectorySizeHelper.cs new file mode 100644 index 0000000..9aef26b --- /dev/null +++ b/SPTInstaller/Helpers/DirectorySizeHelper.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using System.Linq; +using Serilog; +using SPTInstaller.Models; + +namespace SPTInstaller.Helpers +{ + public static class DirectorySizeHelper + { + public static Result CheckAvailableSize(string eftSourceDirPath, string installTargetDirPath) + { + try + { + var eftSourceDirectoryInfo = new DirectoryInfo(eftSourceDirPath); + var installTargetDirectoryInfo = new DirectoryInfo(installTargetDirPath); + + var eftSourceDirSize = GetSizeOfDirectory(eftSourceDirectoryInfo); + var availableSize = DriveInfo.GetDrives().FirstOrDefault(d => d.Name == installTargetDirectoryInfo.Root.Name)?.AvailableFreeSpace ?? 0; + + if (eftSourceDirSize > availableSize) + { + return Result.FromError($"Not enough space on drive {installTargetDirectoryInfo.Root.Name}.\n\nRequired: {FormatFileSize(eftSourceDirSize)}\nAvailable: {FormatFileSize(availableSize)}"); + } + + return Result.FromSuccess(); + } + catch (Exception ex) + { + Log.Error(ex, "Error while checking available size"); + + return Result.FromError(ex.Message); + } + } + + private static long GetSizeOfDirectory(DirectoryInfo sourceDir) => sourceDir.EnumerateFiles("*", SearchOption.AllDirectories).Sum(fi => fi.Length); + + private static string FormatFileSize(long bytes) + { + const int unit = 1024; + var exp = (int)(Math.Log(bytes) / Math.Log(unit)); + + return $"{bytes / Math.Pow(unit, exp):F2} {"KMGTPE"[exp - 1]}B"; + } + } +} \ No newline at end of file diff --git a/SPTInstaller/Installer Tasks/IntializationTask.cs b/SPTInstaller/Installer Tasks/IntializationTask.cs index 6fdafc8..1f024f6 100644 --- a/SPTInstaller/Installer Tasks/IntializationTask.cs +++ b/SPTInstaller/Installer Tasks/IntializationTask.cs @@ -3,6 +3,7 @@ using SPTInstaller.Interfaces; using SPTInstaller.Models; using System.IO; using System.Threading.Tasks; +using SPTInstaller.Helpers; namespace SPTInstaller.Installer_Tasks { @@ -28,6 +29,12 @@ namespace SPTInstaller.Installer_Tasks SetStatus(null, $"Installed EFT Game Path: {FileHelper.GetRedactedPath(_data.OriginalGamePath)}"); + var directorySizeCheckResult = DirectorySizeHelper.CheckAvailableSize(_data.OriginalGamePath, _data.TargetInstallPath); + if (!directorySizeCheckResult.Succeeded) + { + return Result.FromError(directorySizeCheckResult.Message); + } + var result = PreCheckHelper.DetectOriginalGameVersion(_data.OriginalGamePath); if (!result.Succeeded) From e1afb9ce14cfef74766538716d7b1b533e4150b0 Mon Sep 17 00:00:00 2001 From: Philipp Heenemann Date: Sun, 18 Jun 2023 15:32:04 +0200 Subject: [PATCH 2/7] Update Version --- SPTInstaller/SPTInstaller.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SPTInstaller/SPTInstaller.csproj b/SPTInstaller/SPTInstaller.csproj index d6d32c4..7ae2630 100644 --- a/SPTInstaller/SPTInstaller.csproj +++ b/SPTInstaller/SPTInstaller.csproj @@ -9,8 +9,8 @@ icon.ico Assets\icon.ico Debug;Release;TEST - 2.2 - 2.2 + 2.3 + 2.3 From 84b718d81095492961cd18c2d9882abe7d6e276d Mon Sep 17 00:00:00 2001 From: Philipp Heenemann Date: Sun, 18 Jun 2023 15:47:27 +0200 Subject: [PATCH 3/7] Remove unused using --- SPTInstaller/Installer Tasks/IntializationTask.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/SPTInstaller/Installer Tasks/IntializationTask.cs b/SPTInstaller/Installer Tasks/IntializationTask.cs index 1f024f6..4223bf2 100644 --- a/SPTInstaller/Installer Tasks/IntializationTask.cs +++ b/SPTInstaller/Installer Tasks/IntializationTask.cs @@ -1,7 +1,6 @@ using SPTInstaller.Aki.Helper; using SPTInstaller.Interfaces; using SPTInstaller.Models; -using System.IO; using System.Threading.Tasks; using SPTInstaller.Helpers; From 68e50cf5e53e0cc9fb7ff1e1d2c6be71536aab49 Mon Sep 17 00:00:00 2001 From: Philipp Heenemann Date: Sun, 18 Jun 2023 15:54:54 +0200 Subject: [PATCH 4/7] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 403cf4f..9703d22 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ - Checks if .net 4.7.2 (or higher) is installed - Checks if .net 6 desktop runtime is installed - Checks if EFT is installed, +- Checks if there is enough space before install, - Checks installer is not in OG game directory, - Checks install folder does not have game files already in it, - Checks if gameversion matches aki version, if so skip patcher process, From d3767a0344e81986a1ecd34dd125121f2c69548b Mon Sep 17 00:00:00 2001 From: Philipp Heenemann Date: Wed, 12 Jul 2023 08:32:57 +0200 Subject: [PATCH 5/7] Add global using directives and free space pre-check Global System and System.IO usages have been replaced with global usings in GlobalUsings.cs for improved code readability. Alongside, a FreeSpacePreCheck has been added in FreeSpacePreCheck.cs to ensure enough drive space is available before installation. This check was initially taking place in InitializationTask.cs which has been removed for better separation of concerns. The PreCheckViewModel visibility is now dependent on the success status of PreChecks, enhancing user experience. --- SPTInstaller/GlobalUsings.cs | 3 + SPTInstaller/Helpers/DirectorySizeHelper.cs | 49 ++++------ .../Installer Tasks/IntializationTask.cs | 7 -- .../PreChecks/FreeSpacePreCheck.cs | 25 +++++ SPTInstaller/Models/InternalData.cs | 4 +- SPTInstaller/Program.cs | 5 +- SPTInstaller/ViewModels/PreChecksViewModel.cs | 93 ++++++++----------- SPTInstaller/Views/PreChecksView.axaml | 1 + 8 files changed, 90 insertions(+), 97 deletions(-) create mode 100644 SPTInstaller/GlobalUsings.cs create mode 100644 SPTInstaller/Installer Tasks/PreChecks/FreeSpacePreCheck.cs diff --git a/SPTInstaller/GlobalUsings.cs b/SPTInstaller/GlobalUsings.cs new file mode 100644 index 0000000..eee4b9d --- /dev/null +++ b/SPTInstaller/GlobalUsings.cs @@ -0,0 +1,3 @@ +// Global using directives +global using System; +global using System.IO; \ No newline at end of file diff --git a/SPTInstaller/Helpers/DirectorySizeHelper.cs b/SPTInstaller/Helpers/DirectorySizeHelper.cs index 9aef26b..59114d9 100644 --- a/SPTInstaller/Helpers/DirectorySizeHelper.cs +++ b/SPTInstaller/Helpers/DirectorySizeHelper.cs @@ -1,46 +1,29 @@ -using System; -using System.IO; -using System.Linq; +using System.Linq; using Serilog; -using SPTInstaller.Models; -namespace SPTInstaller.Helpers +namespace SPTInstaller.Helpers; + +public static class DirectorySizeHelper { - public static class DirectorySizeHelper + public static bool CheckAvailableSize(string eftSourceDirPath, string installTargetDirPath) { - public static Result CheckAvailableSize(string eftSourceDirPath, string installTargetDirPath) + try { - try - { - var eftSourceDirectoryInfo = new DirectoryInfo(eftSourceDirPath); - var installTargetDirectoryInfo = new DirectoryInfo(installTargetDirPath); + var eftSourceDirectoryInfo = new DirectoryInfo(eftSourceDirPath); + var installTargetDirectoryInfo = new DirectoryInfo(installTargetDirPath); - var eftSourceDirSize = GetSizeOfDirectory(eftSourceDirectoryInfo); - var availableSize = DriveInfo.GetDrives().FirstOrDefault(d => d.Name == installTargetDirectoryInfo.Root.Name)?.AvailableFreeSpace ?? 0; + var eftSourceDirSize = GetSizeOfDirectory(eftSourceDirectoryInfo); + var availableSize = DriveInfo.GetDrives().FirstOrDefault(d => d.Name == installTargetDirectoryInfo.Root.Name)?.AvailableFreeSpace ?? 0; - if (eftSourceDirSize > availableSize) - { - return Result.FromError($"Not enough space on drive {installTargetDirectoryInfo.Root.Name}.\n\nRequired: {FormatFileSize(eftSourceDirSize)}\nAvailable: {FormatFileSize(availableSize)}"); - } - - return Result.FromSuccess(); - } - catch (Exception ex) - { - Log.Error(ex, "Error while checking available size"); - - return Result.FromError(ex.Message); - } + return eftSourceDirSize < availableSize; } - - private static long GetSizeOfDirectory(DirectoryInfo sourceDir) => sourceDir.EnumerateFiles("*", SearchOption.AllDirectories).Sum(fi => fi.Length); - - private static string FormatFileSize(long bytes) + catch (Exception ex) { - const int unit = 1024; - var exp = (int)(Math.Log(bytes) / Math.Log(unit)); + Log.Error(ex, "Error while checking available size"); - return $"{bytes / Math.Pow(unit, exp):F2} {"KMGTPE"[exp - 1]}B"; + return false; } } + + private static long GetSizeOfDirectory(DirectoryInfo sourceDir) => sourceDir.EnumerateFiles("*", SearchOption.AllDirectories).Sum(fi => fi.Length); } \ No newline at end of file diff --git a/SPTInstaller/Installer Tasks/IntializationTask.cs b/SPTInstaller/Installer Tasks/IntializationTask.cs index 4223bf2..28dae32 100644 --- a/SPTInstaller/Installer Tasks/IntializationTask.cs +++ b/SPTInstaller/Installer Tasks/IntializationTask.cs @@ -2,7 +2,6 @@ using SPTInstaller.Interfaces; using SPTInstaller.Models; using System.Threading.Tasks; -using SPTInstaller.Helpers; namespace SPTInstaller.Installer_Tasks { @@ -28,12 +27,6 @@ namespace SPTInstaller.Installer_Tasks SetStatus(null, $"Installed EFT Game Path: {FileHelper.GetRedactedPath(_data.OriginalGamePath)}"); - var directorySizeCheckResult = DirectorySizeHelper.CheckAvailableSize(_data.OriginalGamePath, _data.TargetInstallPath); - if (!directorySizeCheckResult.Succeeded) - { - return Result.FromError(directorySizeCheckResult.Message); - } - var result = PreCheckHelper.DetectOriginalGameVersion(_data.OriginalGamePath); if (!result.Succeeded) diff --git a/SPTInstaller/Installer Tasks/PreChecks/FreeSpacePreCheck.cs b/SPTInstaller/Installer Tasks/PreChecks/FreeSpacePreCheck.cs new file mode 100644 index 0000000..f894265 --- /dev/null +++ b/SPTInstaller/Installer Tasks/PreChecks/FreeSpacePreCheck.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using SPTInstaller.Helpers; +using SPTInstaller.Models; + +namespace SPTInstaller.Installer_Tasks.PreChecks; + +public class FreeSpacePreCheck : PreCheckBase +{ + private readonly InternalData _internalData; + + public FreeSpacePreCheck(InternalData internalData) : base("Free Space", true) + { + _internalData = internalData; + } + + public override async Task CheckOperation() + { + if (_internalData.OriginalGamePath is null || _internalData.TargetInstallPath is null) + { + return false; + } + + return DirectorySizeHelper.CheckAvailableSize(_internalData.OriginalGamePath, _internalData.TargetInstallPath); + } +} \ No newline at end of file diff --git a/SPTInstaller/Models/InternalData.cs b/SPTInstaller/Models/InternalData.cs index 0ea2914..0c93498 100644 --- a/SPTInstaller/Models/InternalData.cs +++ b/SPTInstaller/Models/InternalData.cs @@ -8,12 +8,12 @@ namespace SPTInstaller.Models /// /// The folder to install SPT into /// - public string TargetInstallPath { get; set; } + public string? TargetInstallPath { get; set; } /// /// The orginal EFT game path /// - public string OriginalGamePath { get; set; } + public string? OriginalGamePath { get; set; } /// /// The original EFT game version diff --git a/SPTInstaller/Program.cs b/SPTInstaller/Program.cs index 64ec82f..78e8dc9 100644 --- a/SPTInstaller/Program.cs +++ b/SPTInstaller/Program.cs @@ -9,8 +9,6 @@ using SPTInstaller.Installer_Tasks; using SPTInstaller.Installer_Tasks.PreChecks; using SPTInstaller.Interfaces; using SPTInstaller.Models; -using System; -using System.IO; using System.Linq; using System.Reflection; @@ -35,8 +33,9 @@ namespace SPTInstaller ServiceHelper.Register(); ServiceHelper.Register(); ServiceHelper.Register(); + ServiceHelper.Register(); #if !TEST - string logPath = Path.Join(Environment.CurrentDirectory, "spt-aki-installer_.log"); + var logPath = Path.Join(Environment.CurrentDirectory, "spt-aki-installer_.log"); Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() diff --git a/SPTInstaller/ViewModels/PreChecksViewModel.cs b/SPTInstaller/ViewModels/PreChecksViewModel.cs index 4e8dbbf..0193e6e 100644 --- a/SPTInstaller/ViewModels/PreChecksViewModel.cs +++ b/SPTInstaller/ViewModels/PreChecksViewModel.cs @@ -1,59 +1,48 @@ -using ReactiveUI; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using System.Windows.Input; +using ReactiveUI; +using SPTInstaller.Aki.Helper; using SPTInstaller.Controllers; using SPTInstaller.Helpers; using SPTInstaller.Models; -using System; -using System.Collections.ObjectModel; -using System.Threading.Tasks; -using System.Windows.Input; -namespace SPTInstaller.ViewModels +namespace SPTInstaller.ViewModels; + +public class PreChecksViewModel : ViewModelBase { - public class PreChecksViewModel : ViewModelBase + private string _installPath; + + public ObservableCollection PreChecks { get; set; } = new(ServiceHelper.GetAll()); + public ICommand StartInstallCommand { get; set; } + public bool PreCheckSucceeded { get; set; } + public string InstallPath { - private string _InstallPath; - public string InstallPath - { - get => _InstallPath; - set => this.RaiseAndSetIfChanged(ref _InstallPath, value); - } - - ObservableCollection PreChecks { get; set; } - = new ObservableCollection(ServiceHelper.GetAll()); - - ICommand StartInstallCommand { get; set; } - - public PreChecksViewModel(IScreen host) : base(host) - { - var data = ServiceHelper.Get(); - var installer = ServiceHelper.Get(); - - if(data == null || installer == null) - { - NavigateTo(new MessageViewModel(HostScreen, Result.FromError("Failed to get required service for prechecks"))); - return; - } - - data.TargetInstallPath = Environment.CurrentDirectory; - - InstallPath = data.TargetInstallPath; - - StartInstallCommand = ReactiveCommand.Create(() => - { - NavigateTo(new InstallViewModel(HostScreen)); - }); - - - Task.Run(async () => - { - var result = await installer.RunPreChecks(); - - if(!result.Succeeded) - { - //if a required precheck fails, abort to message view - NavigateTo(new MessageViewModel(HostScreen ,result)); - } - }); - } + get => _installPath; + set => this.RaiseAndSetIfChanged(ref _installPath, value); } -} + + public PreChecksViewModel(IScreen host) : base(host) + { + var data = ServiceHelper.Get(); + var installer = ServiceHelper.Get(); + + if (data == null || installer == null) + { + NavigateTo(new MessageViewModel(HostScreen, Result.FromError("Failed to get required service for prechecks"))); + return; + } + + data.OriginalGamePath = PreCheckHelper.DetectOriginalGamePath(); + data.TargetInstallPath = Environment.CurrentDirectory; + InstallPath = data.TargetInstallPath; + + StartInstallCommand = ReactiveCommand.Create(() => NavigateTo(new InstallViewModel(HostScreen))); + + Task.Run(async () => + { + var result = await installer.RunPreChecks(); + PreCheckSucceeded = result.Succeeded; + }); + } +} \ No newline at end of file diff --git a/SPTInstaller/Views/PreChecksView.axaml b/SPTInstaller/Views/PreChecksView.axaml index 1058561..aa78b82 100644 --- a/SPTInstaller/Views/PreChecksView.axaml +++ b/SPTInstaller/Views/PreChecksView.axaml @@ -23,6 +23,7 @@ Margin="10" FontSize="15" FontWeight="SemiBold" Classes="yellow" + IsVisible="{Binding PreCheckSucceeded}" Command="{Binding StartInstallCommand}" /> From d6aaeda28c5a8effa1ce764e520ad96f6edb4914 Mon Sep 17 00:00:00 2001 From: Philipp Heenemann Date: Wed, 12 Jul 2023 09:00:00 +0200 Subject: [PATCH 6/7] Fixing update on PreCheckSucceeded --- SPTInstaller/ViewModels/PreChecksViewModel.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/SPTInstaller/ViewModels/PreChecksViewModel.cs b/SPTInstaller/ViewModels/PreChecksViewModel.cs index 0193e6e..f9c3f93 100644 --- a/SPTInstaller/ViewModels/PreChecksViewModel.cs +++ b/SPTInstaller/ViewModels/PreChecksViewModel.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using System.Windows.Input; using ReactiveUI; -using SPTInstaller.Aki.Helper; using SPTInstaller.Controllers; using SPTInstaller.Helpers; using SPTInstaller.Models; @@ -12,15 +11,21 @@ namespace SPTInstaller.ViewModels; public class PreChecksViewModel : ViewModelBase { private string _installPath; + private bool _preCheckSucceeded; public ObservableCollection PreChecks { get; set; } = new(ServiceHelper.GetAll()); public ICommand StartInstallCommand { get; set; } - public bool PreCheckSucceeded { get; set; } public string InstallPath { get => _installPath; set => this.RaiseAndSetIfChanged(ref _installPath, value); } + + public bool PreCheckSucceeded + { + get => _preCheckSucceeded; + set => this.RaiseAndSetIfChanged(ref _preCheckSucceeded, value); + } public PreChecksViewModel(IScreen host) : base(host) { From 83a3200813efcc3df7a62ccc9af8956fe58fb440 Mon Sep 17 00:00:00 2001 From: Philipp Heenemann Date: Wed, 12 Jul 2023 16:39:37 +0200 Subject: [PATCH 7/7] Update UI binding to IsEnabled --- SPTInstaller/ViewModels/PreChecksViewModel.cs | 11 ++++++----- SPTInstaller/Views/PreChecksView.axaml | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/SPTInstaller/ViewModels/PreChecksViewModel.cs b/SPTInstaller/ViewModels/PreChecksViewModel.cs index f9c3f93..5718b96 100644 --- a/SPTInstaller/ViewModels/PreChecksViewModel.cs +++ b/SPTInstaller/ViewModels/PreChecksViewModel.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using System.Windows.Input; using ReactiveUI; +using SPTInstaller.Aki.Helper; using SPTInstaller.Controllers; using SPTInstaller.Helpers; using SPTInstaller.Models; @@ -11,7 +12,7 @@ namespace SPTInstaller.ViewModels; public class PreChecksViewModel : ViewModelBase { private string _installPath; - private bool _preCheckSucceeded; + private bool _allowInstall; public ObservableCollection PreChecks { get; set; } = new(ServiceHelper.GetAll()); public ICommand StartInstallCommand { get; set; } @@ -21,10 +22,10 @@ public class PreChecksViewModel : ViewModelBase set => this.RaiseAndSetIfChanged(ref _installPath, value); } - public bool PreCheckSucceeded + public bool AllowInstall { - get => _preCheckSucceeded; - set => this.RaiseAndSetIfChanged(ref _preCheckSucceeded, value); + get => _allowInstall; + set => this.RaiseAndSetIfChanged(ref _allowInstall, value); } public PreChecksViewModel(IScreen host) : base(host) @@ -47,7 +48,7 @@ public class PreChecksViewModel : ViewModelBase Task.Run(async () => { var result = await installer.RunPreChecks(); - PreCheckSucceeded = result.Succeeded; + AllowInstall = result.Succeeded; }); } } \ No newline at end of file diff --git a/SPTInstaller/Views/PreChecksView.axaml b/SPTInstaller/Views/PreChecksView.axaml index aa78b82..003e0d9 100644 --- a/SPTInstaller/Views/PreChecksView.axaml +++ b/SPTInstaller/Views/PreChecksView.axaml @@ -23,7 +23,7 @@ Margin="10" FontSize="15" FontWeight="SemiBold" Classes="yellow" - IsVisible="{Binding PreCheckSucceeded}" + IsEnabled="{Binding AllowInstall}" Command="{Binding StartInstallCommand}" />