diff --git a/StabilityMatrix/Helper/ArchiveHelper.cs b/StabilityMatrix/Helper/ArchiveHelper.cs index 84aeb5fd..aa32c09d 100644 --- a/StabilityMatrix/Helper/ArchiveHelper.cs +++ b/StabilityMatrix/Helper/ArchiveHelper.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; @@ -22,7 +23,9 @@ public static class ArchiveHelper public static string SevenZipPath => Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, RelativeSevenZipPath)); private static readonly Regex Regex7ZOutput = new(@"(?<=Size:\s*)\d+|(?<=Compressed:\s*)\d+"); - + private static readonly Regex Regex7ZProgressDigits = new(@"(?<=\s*)\d+(?=%)"); + private static readonly Regex Regex7ZProgressFull = new(@"(\d+)%.*- (.*)"); + public static async Task TestArchive(string archivePath) { var process = ProcessRunner.StartProcess(SevenZipPath, new[] {"t", archivePath}); @@ -33,6 +36,55 @@ public static class ArchiveHelper var compressed = ulong.Parse(matches[1].Value); return new ArchiveInfo(size, compressed); } + + public static async Task Extract7Z(string archivePath, string extractDirectory) + { + var process = ProcessRunner.StartProcess(SevenZipPath, new[] + { + "x", archivePath, $"-o{ProcessRunner.Quote(extractDirectory)}", "-y" + }); + await process.WaitForExitAsync(); + var output = await process.StandardOutput.ReadToEndAsync(); + var matches = Regex7ZOutput.Matches(output); + var size = ulong.Parse(matches[0].Value); + var compressed = ulong.Parse(matches[1].Value); + return new ArchiveInfo(size, compressed); + } + + public static async Task Extract7Z(string archivePath, string extractDirectory, IProgress progress) + { + var outputStore = new StringBuilder(); + var onOutput = new Action(s => + { + // Parse progress + Logger.Trace($"7z: {s}"); + outputStore.AppendLine(s); + var match = Regex7ZProgressFull.Match(s ?? ""); + if (match.Success) + { + var percent = int.Parse(match.Groups[1].Value); + var currentFile = match.Groups[2].Value; + progress.Report(new ProgressReport(percent / (float) 100, "Extracting", currentFile, type: ProgressType.Extract)); + } + }); + progress.Report(new ProgressReport(-1, isIndeterminate: true, type: ProgressType.Extract)); + + // Need -bsp1 for progress reports + var process = ProcessRunner.StartProcess(SevenZipPath, new[] + { + "x", archivePath, $"-o{ProcessRunner.Quote(extractDirectory)}", "-y", "-bsp1" + }, outputDataReceived: onOutput); + + await process.WaitForExitAsync(); + + progress.Report(new ProgressReport(1, "Finished extracting", type: ProgressType.Extract)); + + var output = outputStore.ToString(); + var matches = Regex7ZOutput.Matches(output); + var size = ulong.Parse(matches[0].Value); + var compressed = ulong.Parse(matches[1].Value); + return new ArchiveInfo(size, compressed); + } /// /// Extract an archive to the output directory. diff --git a/StabilityMatrix/Helper/PrerequisiteHelper.cs b/StabilityMatrix/Helper/PrerequisiteHelper.cs index d7ac3e67..974d6cbe 100644 --- a/StabilityMatrix/Helper/PrerequisiteHelper.cs +++ b/StabilityMatrix/Helper/PrerequisiteHelper.cs @@ -22,7 +22,7 @@ public class PrerequisiteHelper : IPrerequisiteHelper private static readonly string PortableGitDownloadPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StabilityMatrix", - "PortableGit.7z"); + "PortableGit.7z.exe"); private static readonly string GitExePath = Path.Combine(PortableGitInstallDir, "bin", "git.exe"); @@ -62,8 +62,14 @@ public class PrerequisiteHelper : IPrerequisiteHelper private async Task UnzipGit(IProgress? progress = null) { - progress?.Report(new ProgressReport(1, isIndeterminate: true, message: "Installing git...")); - await ArchiveHelper.Extract(PortableGitDownloadPath, PortableGitInstallDir, progress); + if (progress == null) + { + await ArchiveHelper.Extract7Z(PortableGitDownloadPath, PortableGitInstallDir); + } + else + { + await ArchiveHelper.Extract7Z(PortableGitDownloadPath, PortableGitInstallDir, progress); + } logger.LogInformation("Extracted Git"); diff --git a/StabilityMatrix/Models/ProgressReport.cs b/StabilityMatrix/Models/ProgressReport.cs index 8252de5c..e56ff6cd 100644 --- a/StabilityMatrix/Models/ProgressReport.cs +++ b/StabilityMatrix/Models/ProgressReport.cs @@ -20,16 +20,18 @@ public record struct ProgressReport public string? Message { get; init; } public bool IsIndeterminate { get; init; } = false; public float Percentage => (float) Math.Ceiling(Math.Clamp(Progress ?? 0, 0, 1) * 100); + public ProgressType Type { get; init; } = ProgressType.Generic; - public ProgressReport(double progress, string? title = null, string? message = null, bool isIndeterminate = false) + public ProgressReport(double progress, string? title = null, string? message = null, bool isIndeterminate = false, ProgressType type = ProgressType.Generic) { Progress = progress; Title = title; Message = message; IsIndeterminate = isIndeterminate; + Type = type; } - public ProgressReport(ulong current, ulong total, string? title = null, string? message = null, bool isIndeterminate = false) + public ProgressReport(ulong current, ulong total, string? title = null, string? message = null, bool isIndeterminate = false, ProgressType type = ProgressType.Generic) { Current = current; Total = total; @@ -37,13 +39,15 @@ public record struct ProgressReport Title = title; Message = message; IsIndeterminate = isIndeterminate; + Type = type; } - public ProgressReport(ulong current, string? title = null, string? message = null) + public ProgressReport(ulong current, string? title = null, string? message = null, ProgressType type = ProgressType.Generic) { Current = current; Title = title; Message = message; IsIndeterminate = true; + Type = type; } } diff --git a/StabilityMatrix/Models/ProgressType.cs b/StabilityMatrix/Models/ProgressType.cs new file mode 100644 index 00000000..14471f4f --- /dev/null +++ b/StabilityMatrix/Models/ProgressType.cs @@ -0,0 +1,8 @@ +namespace StabilityMatrix.Models; + +public enum ProgressType +{ + Generic, + Download, + Extract, +} diff --git a/StabilityMatrix/ViewModels/InstallerViewModel.cs b/StabilityMatrix/ViewModels/InstallerViewModel.cs index c0f1af45..c342ed30 100644 --- a/StabilityMatrix/ViewModels/InstallerViewModel.cs +++ b/StabilityMatrix/ViewModels/InstallerViewModel.cs @@ -397,7 +397,7 @@ public partial class InstallerViewModel : ObservableObject { ProgressText = $"Downloading Git... {progress.Percentage:N0}%"; } - else if (string.IsNullOrWhiteSpace(progress.Message)) + else if (progress.Type == ProgressType.Extract) { ProgressText = $"Installing Git... {progress.Percentage:N0}%"; } diff --git a/StabilityMatrix/ViewModels/OneClickInstallViewModel.cs b/StabilityMatrix/ViewModels/OneClickInstallViewModel.cs index 7366eff2..9f807eeb 100644 --- a/StabilityMatrix/ViewModels/OneClickInstallViewModel.cs +++ b/StabilityMatrix/ViewModels/OneClickInstallViewModel.cs @@ -81,7 +81,7 @@ public partial class OneClickInstallViewModel : ObservableObject { SubHeaderText = $"Downloading Git... {progress.Percentage:N0}%"; } - else if (progress.Message?.Contains("Extracting") ?? false) + else if (progress.Type == ProgressType.Extract) { SubHeaderText = $"Installing Git... {progress.Percentage:N0}%"; }