From d269d674ad058494a290094d3352b75677a6188c Mon Sep 17 00:00:00 2001 From: "waffle.lord" Date: Sat, 29 Jul 2023 14:26:20 -0400 Subject: [PATCH] rework prechecks to return a precheckresult --- SPTInstaller/Controllers/InstallController.cs | 2 +- SPTInstaller/Helpers/DirectorySizeHelper.cs | 43 +++++++++++------- SPTInstaller/Interfaces/IPreCheck.cs | 2 + SPTInstaller/Models/PreCheckBase.cs | 44 ++++++++++++++++++- SPTInstaller/Models/PreCheckResult.cs | 37 ++++++++++++++++ 5 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 SPTInstaller/Models/PreCheckResult.cs diff --git a/SPTInstaller/Controllers/InstallController.cs b/SPTInstaller/Controllers/InstallController.cs index bc7056f..ac43ee6 100644 --- a/SPTInstaller/Controllers/InstallController.cs +++ b/SPTInstaller/Controllers/InstallController.cs @@ -32,7 +32,7 @@ public class InstallController { var result = await check.RunCheck(); - Log.Information($"PreCheck: {check.Name} ({(check.IsRequired ? "Required" : "Optional")}) -> {(result.Succeeded ? "Passed" : "Failed")}"); + Log.Information($"PreCheck: {check.Name} ({(check.IsRequired ? "Required" : "Optional")}) -> {(result.Succeeded ? "Passed" : "Failed")}\nDetail: {check.PreCheckDetails.ReplaceLineEndings(" ")}"); if (check.IsRequired) { diff --git a/SPTInstaller/Helpers/DirectorySizeHelper.cs b/SPTInstaller/Helpers/DirectorySizeHelper.cs index c27caa8..d87b6c4 100644 --- a/SPTInstaller/Helpers/DirectorySizeHelper.cs +++ b/SPTInstaller/Helpers/DirectorySizeHelper.cs @@ -1,29 +1,38 @@ using System.Linq; -using Serilog; namespace SPTInstaller.Helpers; public static class DirectorySizeHelper { - public static bool CheckAvailableSize(string eftSourceDirPath, string installTargetDirPath) + // SizeSuffix implementation found here: + // https://stackoverflow.com/a/14488941 + static readonly string[] SizeSuffixes = + { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; + public static string SizeSuffix(Int64 value, int decimalPlaces = 1) { - try - { - var eftSourceDirectoryInfo = new DirectoryInfo(eftSourceDirPath); - var installTargetDirectoryInfo = new DirectoryInfo(installTargetDirPath); - - var eftSourceDirSize = GetSizeOfDirectory(eftSourceDirectoryInfo); - var availableSize = DriveInfo.GetDrives().FirstOrDefault(d => d.Name.ToLower() == installTargetDirectoryInfo.Root.Name.ToLower())?.AvailableFreeSpace ?? 0; + if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); } + if (value < 0) { return "-" + SizeSuffix(-value, decimalPlaces); } + if (value == 0) { return string.Format("{0:n" + decimalPlaces + "} bytes", 0); } - return eftSourceDirSize < availableSize; - } - catch (Exception ex) - { - Log.Error(ex, "Error while checking available size"); + // mag is 0 for bytes, 1 for KB, 2, for MB, etc. + int mag = (int)Math.Log(value, 1024); - return false; + // 1L << (mag * 10) == 2 ^ (10 * mag) + // [i.e. the number of bytes in the unit corresponding to mag] + decimal adjustedSize = (decimal)value / (1L << (mag * 10)); + + // make adjustment when the value is large enough that + // it would round up to 1000 or more + if (Math.Round(adjustedSize, decimalPlaces) >= 1000) + { + mag += 1; + adjustedSize /= 1024; } + + return string.Format("{0:n" + decimalPlaces + "} {1}", + adjustedSize, + SizeSuffixes[mag]); } - - private static long GetSizeOfDirectory(DirectoryInfo sourceDir) => sourceDir.EnumerateFiles("*", SearchOption.AllDirectories).Sum(fi => fi.Length); + + public static long GetSizeOfDirectory(DirectoryInfo sourceDir) => sourceDir.EnumerateFiles("*", SearchOption.AllDirectories).Sum(fi => fi.Length); } \ No newline at end of file diff --git a/SPTInstaller/Interfaces/IPreCheck.cs b/SPTInstaller/Interfaces/IPreCheck.cs index 34f20cc..1bc789c 100644 --- a/SPTInstaller/Interfaces/IPreCheck.cs +++ b/SPTInstaller/Interfaces/IPreCheck.cs @@ -12,5 +12,7 @@ public interface IPreCheck public bool Passed { get; } + public string PreCheckDetails { get; } + public Task RunCheck(); } \ No newline at end of file diff --git a/SPTInstaller/Models/PreCheckBase.cs b/SPTInstaller/Models/PreCheckBase.cs index 923b727..31bd45f 100644 --- a/SPTInstaller/Models/PreCheckBase.cs +++ b/SPTInstaller/Models/PreCheckBase.cs @@ -1,6 +1,7 @@ using ReactiveUI; using SPTInstaller.Interfaces; using System.Threading.Tasks; +using System.Windows.Input; namespace SPTInstaller.Models; @@ -48,6 +49,34 @@ public abstract class PreCheckBase : ReactiveObject, IPreCheck set => this.RaiseAndSetIfChanged(ref _isRunning, value); } + private string _preCheckDetails; + public string PreCheckDetails + { + get => _preCheckDetails; + set => this.RaiseAndSetIfChanged(ref _preCheckDetails, value); + } + + private bool _actionButtonIsVisible; + public bool ActionButtonIsVisible + { + get => _actionButtonIsVisible; + set => this.RaiseAndSetIfChanged(ref _actionButtonIsVisible, value); + } + + private string _actionButtonText; + public string ActionButtonText + { + get => _actionButtonText; + set => this.RaiseAndSetIfChanged(ref _actionButtonText, value); + } + + private ICommand _actionButtonCommand; + public ICommand ActionButtonCommand + { + get => _actionButtonCommand; + set => this.RaiseAndSetIfChanged(ref _actionButtonCommand, value); + } + /// /// Base class for pre-checks to run before installation /// @@ -63,12 +92,23 @@ public abstract class PreCheckBase : ReactiveObject, IPreCheck public async Task RunCheck() { IsRunning = true; - Passed = await CheckOperation(); + + var result = await CheckOperation(); + Passed = result.Succeeded; + + PreCheckDetails = !string.IsNullOrWhiteSpace(result.Message) + ? result.Message + : (result.Succeeded ? "Pre-Check succeeded, but no details were provided" : "Pre-Check failed, but no details were provided"); + + ActionButtonText = result.ActionButtonText; + ActionButtonCommand = result.ButtonPressedCommand; + ActionButtonIsVisible = result.ActionButtonIsVisible; + IsRunning = false; IsPending = false; return Passed ? Result.FromSuccess() : Result.FromError($"PreCheck Failed: {Name}"); } - public abstract Task CheckOperation(); + public abstract Task CheckOperation(); } \ No newline at end of file diff --git a/SPTInstaller/Models/PreCheckResult.cs b/SPTInstaller/Models/PreCheckResult.cs new file mode 100644 index 0000000..3e4d746 --- /dev/null +++ b/SPTInstaller/Models/PreCheckResult.cs @@ -0,0 +1,37 @@ +using ReactiveUI; +using SPTInstaller.Interfaces; +using System.Windows.Input; + +namespace SPTInstaller.Models; +public class PreCheckResult : IResult +{ + public bool Succeeded { get; private set; } + + public string Message { get; private set; } + + public bool ActionButtonIsVisible { get; private set; } + + public string ActionButtonText { get; private set; } + + public ICommand ButtonPressedCommand { get; private set; } + + protected PreCheckResult(string message, bool succeeded, string actionButtonText, Action? buttonPressedAction) + { + Message = message; + Succeeded = succeeded; + + ActionButtonText = actionButtonText; + + ActionButtonIsVisible = buttonPressedAction != null && !string.IsNullOrWhiteSpace(actionButtonText); + + buttonPressedAction ??= () => { }; + + ButtonPressedCommand = ReactiveCommand.Create(buttonPressedAction); + } + + public static PreCheckResult FromSuccess(string message = "") => new PreCheckResult(message, true, "", null); + + public static PreCheckResult FromError(string message, string actionButtonText = "", Action? actionButtonPressedAction = null) => new PreCheckResult(message, false, actionButtonText, actionButtonPressedAction); + + public static PreCheckResult FromException(Exception ex, string actionButtonText = "", Action? actionButtonPressedAction = null) => new PreCheckResult($"An exception was thrown during this precheck\n\nException:\n{ex.Message}\n\nStacktrace:\n{ex.StackTrace}", false, actionButtonText, actionButtonPressedAction); +}