Browse Source

Merge pull request #42 from ionite34/one-click

pull/5/head
Ionite 1 year ago committed by GitHub
parent
commit
3caa94cc02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      StabilityMatrix/App.xaml.cs
  2. 27
      StabilityMatrix/Helper/DialogErrorHandler.cs
  3. 4
      StabilityMatrix/Helper/EventManager.cs
  4. 8
      StabilityMatrix/Helper/IDialogErrorHandler.cs
  5. 9
      StabilityMatrix/Helper/IPrerequisiteHelper.cs
  6. 38
      StabilityMatrix/Helper/PrerequisiteHelper.cs
  7. 1
      StabilityMatrix/LaunchOptionsDialog.xaml.cs
  8. 19
      StabilityMatrix/LaunchPage.xaml
  9. 63
      StabilityMatrix/MainWindow.xaml
  10. 9
      StabilityMatrix/Models/Packages/A3WebUI.cs
  11. 2
      StabilityMatrix/ViewModels/InstallerViewModel.cs
  12. 20
      StabilityMatrix/ViewModels/LaunchViewModel.cs
  13. 185
      StabilityMatrix/ViewModels/MainWindowViewModel.cs
  14. 48
      StabilityMatrix/ViewModels/PackageManagerViewModel.cs

2
StabilityMatrix/App.xaml.cs

@ -9,6 +9,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using NLog.Layouts;
using Polly;
using Polly.Contrib.WaitAndRetry;
using Polly.Extensions.Http;
@ -82,6 +83,7 @@ namespace StabilityMatrix
serviceCollection.AddSingleton<BasePackage, VladAutomatic>();
serviceCollection.AddSingleton<ISnackbarService, SnackbarService>();
serviceCollection.AddSingleton<ISettingsManager, SettingsManager>();
serviceCollection.AddSingleton<IPrerequisiteHelper, PrerequisiteHelper>();
serviceCollection.AddSingleton<IDialogErrorHandler, DialogErrorHandler>();
serviceCollection.AddMemoryCache();
serviceCollection.AddSingleton<IGithubApiCache, GithubApiCache>();

27
StabilityMatrix/Helper/DialogErrorHandler.cs

@ -42,7 +42,7 @@ public class DialogErrorHandler : IDialogErrorHandler
}
/// <summary>
/// Attempt to run the given action, showing a generic error snackbar if it fails.
/// Attempt to run the given task, showing a generic error snackbar if it fails.
/// </summary>
public async Task<TaskResult<T>> TryAsync<T>(Task<T> task, string message, LogLevel level = LogLevel.Error, int timeoutMilliseconds = 5000)
{
@ -62,4 +62,29 @@ public class DialogErrorHandler : IDialogErrorHandler
};
}
}
/// <summary>
/// Attempt to run the given void task, showing a generic error snackbar if it fails.
/// Return a TaskResult with true if the task succeeded, false if it failed.
/// </summary>
public async Task<TaskResult<bool>> TryAsync(Task task, string message, LogLevel level = LogLevel.Error, int timeoutMilliseconds = 5000)
{
try
{
await task;
return new TaskResult<bool>
{
Result = true
};
}
catch (Exception e)
{
ShowSnackbarAsync(message, level, timeoutMilliseconds);
return new TaskResult<bool>
{
Result = false,
Exception = e
};
}
}
}

4
StabilityMatrix/Helper/EventManager.cs

@ -13,6 +13,10 @@ public class EventManager
public event EventHandler<int>? GlobalProgressChanged;
public event EventHandler<Type>? PageChangeRequested;
public event EventHandler? InstalledPackagesChanged;
public event EventHandler? OneClickInstallFinished;
public void OnGlobalProgressChanged(int progress) => GlobalProgressChanged?.Invoke(this, progress);
public void RequestPageChange(Type pageType) => PageChangeRequested?.Invoke(this, pageType);
public void OnInstalledPackagesChanged() => InstalledPackagesChanged?.Invoke(this, EventArgs.Empty);
public void OnOneClickInstallFinished() => OneClickInstallFinished?.Invoke(this, EventArgs.Empty);
}

8
StabilityMatrix/Helper/IDialogErrorHandler.cs

@ -12,7 +12,13 @@ public interface IDialogErrorHandler
void ShowSnackbarAsync(string message, LogLevel level = LogLevel.Error, int timeoutMilliseconds = 5000);
/// <summary>
/// Attempt to run the given action, showing a generic error snackbar if it fails.
/// Attempt to run the given task, showing a generic error snackbar if it fails.
/// </summary>
Task<TaskResult<T>> TryAsync<T>(Task<T> task, string message, LogLevel level = LogLevel.Error, int timeoutMilliseconds = 5000);
/// <summary>
/// Attempt to run the given void task, showing a generic error snackbar if it fails.
/// Return a TaskResult with true if the task succeeded, false if it failed.
/// </summary>
Task<TaskResult<bool>> TryAsync(Task task, string message, LogLevel level = LogLevel.Error, int timeoutMilliseconds = 5000);
}

9
StabilityMatrix/Helper/IPrerequisiteHelper.cs

@ -0,0 +1,9 @@
using System.Diagnostics;
using System.Threading.Tasks;
namespace StabilityMatrix.Helper;
public interface IPrerequisiteHelper
{
Task<Process?> InstallGitIfNecessary();
}

38
StabilityMatrix/Helper/PrerequisiteHelper.cs

@ -0,0 +1,38 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace StabilityMatrix.Helper;
public class PrerequisiteHelper : IPrerequisiteHelper
{
private readonly ILogger<PrerequisiteHelper> logger;
public PrerequisiteHelper(ILogger<PrerequisiteHelper> logger)
{
this.logger = logger;
}
public async Task<Process?> InstallGitIfNecessary()
{
try
{
var gitOutput = await ProcessRunner.GetProcessOutputAsync("git", "--version");
if (gitOutput.Contains("git version 2"))
{
return default;
}
}
catch (Exception e)
{
logger.LogError(e, "Error running git: ");
}
var installProcess =
ProcessRunner.StartProcess("Assets\\Git-2.40.1-64-bit.exe", "/VERYSILENT /NORESTART");
installProcess.OutputDataReceived += (sender, args) => { logger.LogDebug(args.Data); };
return installProcess;
}
}

1
StabilityMatrix/LaunchOptionsDialog.xaml.cs

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

19
StabilityMatrix/LaunchPage.xaml

@ -99,6 +99,25 @@
<ColumnDefinition Width="0.8*" />
<ColumnDefinition Width="0.2*" />
</Grid.ColumnDefinitions>
<ui:Flyout
Background="{DynamicResource SystemAccentColorPrimaryBrush}"
FontSize="18"
Grid.Column="0"
Grid.Row="0"
IsOpen="{Binding IsLaunchTeachingTipsOpen, Mode=TwoWay}"
Placement="Bottom">
<StackPanel Orientation="Horizontal">
<Grid HorizontalAlignment="Left">
<ui:SymbolIcon Symbol="ArrowCurveUpLeft20" />
</Grid>
<TextBlock
HorizontalAlignment="Left"
Text="Click here to get started!"
TextWrapping="WrapWithOverflow"
Width="280" />
</StackPanel>
</ui:Flyout>
<ui:Button
Background="Green"
Command="{Binding LaunchCommand}"

63
StabilityMatrix/MainWindow.xaml

@ -8,6 +8,8 @@
Title="Stability Matrix"
Width="1100"
WindowBackdropType="Mica"
d:DesignHeight="500"
d:DesignWidth="700"
d:DataContext="{d:DesignInstance Type=viewModels:MainWindowViewModel,
IsDesignTimeCreatable=True}"
mc:Ignorable="d"
@ -18,7 +20,16 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:viewModels="clr-namespace:StabilityMatrix.ViewModels"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:StabilityMatrix.Converters">
<ui:FluentWindow.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
<converters:ValueConverterGroup x:Key="InvertAndVisibilitate">
<converters:BoolNegationConverter />
<BooleanToVisibilityConverter />
</converters:ValueConverterGroup>
</ui:FluentWindow.Resources>
<ui:FluentWindow.TaskbarItemInfo>
<TaskbarItemInfo ProgressState="{Binding ProgressState}" ProgressValue="{Binding ProgressValue}" />
@ -35,7 +46,10 @@
<TextBlock Margin="16,8" Text="Stability Matrix" />
</ui:TitleBar.Header>
</ui:TitleBar>
<Grid Grid.Row="1" Visibility="{Binding AdvancedModeVisibility, FallbackValue=Visible}">
<Grid Grid.Row="1"
Visibility="{Binding IsAdvancedMode,
Converter={StaticResource BoolToVisConverter},
FallbackValue=Hidden}">
<ui:NavigationView
IsBackButtonVisible="Collapsed"
PaneClosed="RootNavigation_OnPaneClosed"
@ -81,16 +95,47 @@
</ui:NavigationView.ContentOverlay>
</ui:NavigationView>
</Grid>
<Grid Grid.Row="1" Visibility="{Binding SimpleModeVisibility, FallbackValue=Hidden}">
<Grid Grid.Row="1"
Visibility="{Binding IsAdvancedMode,
Converter={StaticResource InvertAndVisibilitate},
FallbackValue=Visible}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding HeaderText}"
TextWrapping="Wrap"
VerticalAlignment="Top" HorizontalAlignment="Center"
FontSize="36" FontWeight="Light" Margin="8"/>
<TextBlock Grid.Row="1"
Text="{Binding SubHeaderText}"
TextWrapping="Wrap" TextAlignment="Center"
VerticalAlignment="Top" HorizontalAlignment="Center"
FontSize="16" FontWeight="Light" Margin="8">
</TextBlock>
<StackPanel Grid.Row="2" VerticalAlignment="Center">
<ProgressBar Maximum="100" Value="{Binding OneClickInstallProgress}"
Visibility="{Binding ProgressBarVisibility}"
IsIndeterminate="{Binding IsIndeterminate}"
Margin="16"/>
<ui:Button
Content="Install"
FontSize="36"
Visibility="{Binding ShowInstallButton, Converter={StaticResource BoolToVisConverter}}"
Content="{Binding InstallButtonText, FallbackValue=Install}"
Command="{Binding InstallCommand}"
FontSize="32"
HorizontalAlignment="Center"
Padding="16" />
<Button
Margin="16"
Padding="16, 8, 16, 8" />
</StackPanel>
<Button Grid.Row="3"
Background="Transparent"
Command="{Binding GoAdvancedModeCommand}"
Content="Advanced Options"
Visibility="{Binding ShowInstallButton, Converter={StaticResource BoolToVisConverter}}"
Command="{Binding ToggleAdvancedModeCommand}"
Content="Skip first-time setup"
FontSize="14"
HorizontalAlignment="Center"
Margin="16"

9
StabilityMatrix/Models/Packages/A3WebUI.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using StabilityMatrix.Api;
using StabilityMatrix.Helper;
@ -100,7 +101,13 @@ public class A3WebUI : BaseGitPackage
if (s.Contains("Running on", StringComparison.OrdinalIgnoreCase))
{
WebUrl = s.Split(" ")[5];
var regex = new Regex(
"(?:https?|ftp)://[-a-zA-Z0-9.]+(:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9][0-9]|6[0-4][0-9][0-9][0-9]|\\d{2,4}|[1-9]))?");
var match = regex.Match(s);
if (match.Success)
{
WebUrl = match.Value;
}
}
Debug.WriteLine($"process stdout: {s}");

2
StabilityMatrix/ViewModels/InstallerViewModel.cs

@ -255,7 +255,7 @@ public partial class InstallerViewModel : ObservableObject
settingsManager.SetActiveInstalledPackage(package);
}
private Task<string?> DownloadPackage(string? version = null)
private Task<string?> DownloadPackage(string version)
{
SelectedPackage.DownloadProgressChanged += SelectedPackageOnProgressChanged;
SelectedPackage.DownloadComplete += (_, _) => ProgressText = "Download Complete";

20
StabilityMatrix/ViewModels/LaunchViewModel.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
@ -15,6 +16,7 @@ using StabilityMatrix.Models.Packages;
using StabilityMatrix.Python;
using Wpf.Ui.Contracts;
using Wpf.Ui.Controls.ContentDialogControl;
using EventManager = StabilityMatrix.Helper.EventManager;
namespace StabilityMatrix.ViewModels;
@ -39,6 +41,8 @@ public partial class LaunchViewModel : ObservableObject
[ObservableProperty] private Visibility stopButtonVisibility;
[ObservableProperty] private bool isLaunchTeachingTipsOpen = false;
private InstalledPackage? selectedPackage;
@ -80,9 +84,22 @@ public partial class LaunchViewModel : ObservableObject
this.packageFactory = packageFactory;
SetProcessRunning(false);
EventManager.Instance.InstalledPackagesChanged += OnInstalledPackagesChanged;
EventManager.Instance.OneClickInstallFinished += OnOneClickInstallFinished;
ToastNotificationManagerCompat.OnActivated += ToastNotificationManagerCompatOnOnActivated;
}
private void OnOneClickInstallFinished(object? sender, EventArgs e)
{
IsLaunchTeachingTipsOpen = true;
}
private void OnInstalledPackagesChanged(object? sender, EventArgs e)
{
OnLoaded();
}
private void ToastNotificationManagerCompatOnOnActivated(ToastNotificationActivatedEventArgsCompat e)
{
if (e.Argument.StartsWith("http"))
@ -222,8 +239,9 @@ public partial class LaunchViewModel : ObservableObject
private void LoadPackages()
{
var packages = settingsManager.Settings.InstalledPackages;
if (!packages.Any())
if (!packages?.Any() ?? true)
{
InstalledPackages.Clear();
return;
}

185
StabilityMatrix/ViewModels/MainWindowViewModel.cs

@ -1,11 +1,16 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Shell;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
using StabilityMatrix.Helper;
using StabilityMatrix.Models;
using StabilityMatrix.Python;
using Wpf.Ui.Appearance;
using EventManager = StabilityMatrix.Helper.EventManager;
@ -14,29 +19,192 @@ namespace StabilityMatrix.ViewModels;
public partial class MainWindowViewModel : ObservableObject
{
private readonly ISettingsManager settingsManager;
private readonly IPackageFactory packageFactory;
private readonly IPrerequisiteHelper prerequisiteHelper;
private readonly ILogger<MainWindowViewModel> logger;
private readonly IPyRunner pyRunner;
private const string DefaultPackageName = "stable-diffusion-webui";
public MainWindowViewModel(ISettingsManager settingsManager)
public MainWindowViewModel(ISettingsManager settingsManager, IPackageFactory packageFactory,
IPrerequisiteHelper prerequisiteHelper, ILogger<MainWindowViewModel> logger, IPyRunner pyRunner)
{
this.settingsManager = settingsManager;
this.packageFactory = packageFactory;
this.prerequisiteHelper = prerequisiteHelper;
this.logger = logger;
this.pyRunner = pyRunner;
}
[ObservableProperty]
private Visibility advancedModeVisibility;
private bool isAdvancedMode;
[ObservableProperty]
private Visibility simpleModeVisibility;
private float progressValue;
[ObservableProperty]
private float progressValue;
private string headerText;
[ObservableProperty]
private string subHeaderText;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(ProgressBarVisibility))]
private int oneClickInstallProgress;
[ObservableProperty]
private bool isIndeterminate;
[ObservableProperty]
private TaskbarItemProgressState progressState;
[ObservableProperty]
private bool showInstallButton;
[ObservableProperty]
private string installButtonText;
public Visibility ProgressBarVisibility => ProgressValue > 0 ? Visibility.Visible : Visibility.Collapsed;
private string webUrl = string.Empty;
public void OnLoaded()
{
SetTheme();
GoAdvancedMode();
ShowInstallButton = true;
EventManager.Instance.GlobalProgressChanged += OnGlobalProgressChanged;
if (settingsManager.Settings.InstalledPackages.Any())
{
IsAdvancedMode = true;
}
else
{
IsAdvancedMode = false;
InstallButtonText = "Install";
HeaderText = "Click the Install button below to get started!";
SubHeaderText =
"This will install the latest version of Stable Diffusion WebUI by Automatic1111.\nIf you don't know what this means, don't worry, you'll be generating images soon!";
}
}
[RelayCommand]
private void ToggleAdvancedMode()
{
IsAdvancedMode = !IsAdvancedMode;
EventManager.Instance.RequestPageChange(typeof(PackageManagerPage));
}
[RelayCommand]
private async Task Install()
{
if (InstallButtonText == "Install")
{
ShowInstallButton = false;
await DoInstall();
ShowInstallButton = true;
}
else
{
ToggleAdvancedMode();
}
}
private async Task DoInstall()
{
var a1111 = packageFactory.FindPackageByName(DefaultPackageName)!;
HeaderText = "Installing Stable Diffusion WebUI...";
// check git
var gitProcess = await prerequisiteHelper.InstallGitIfNecessary();
if (gitProcess != null) // git isn't installed
{
IsIndeterminate = true;
SubHeaderText = "Installing git...";
await gitProcess.WaitForExitAsync();
if (gitProcess.ExitCode != 0)
{
HeaderText = "Installation failed";
SubHeaderText = "Error installing git. Please try again later.";
OneClickInstallProgress = 0;
logger.LogError($"Git install failed with exit code {gitProcess.ExitCode}");
}
}
SubHeaderText = "Installing prerequisites...";
IsIndeterminate = true;
if (!PyRunner.PipInstalled)
{
await pyRunner.SetupPip();
}
if (!PyRunner.VenvInstalled)
{
await pyRunner.InstallPackage("virtualenv");
}
IsIndeterminate = false;
// get latest version & download & install
SubHeaderText = "Getting latest version...";
var latestVersion = await a1111.GetLatestVersion();
a1111.InstallLocation += "\\stable-diffusion-webui";
await DownloadPackage(a1111, latestVersion);
await InstallPackage(a1111);
var package = new InstalledPackage
{
DisplayName = a1111.DisplayName,
Path = a1111.InstallLocation,
Id = Guid.NewGuid(),
PackageName = a1111.Name,
PackageVersion = latestVersion,
LaunchCommand = a1111.LaunchCommand,
LastUpdateCheck = DateTimeOffset.Now
};
settingsManager.AddInstalledPackage(package);
settingsManager.SetActiveInstalledPackage(package);
EventManager.Instance.OnInstalledPackagesChanged();
HeaderText = "Installation complete!";
OneClickInstallProgress = 100;
SubHeaderText = "Proceeding to Launch page in 3 seconds...";
await Task.Delay(1000);
SubHeaderText = "Proceeding to Launch page in 2 seconds...";
await Task.Delay(1000);
SubHeaderText = "Proceeding to Launch page in 1 second...";
await Task.Delay(1000);
IsAdvancedMode = true;
EventManager.Instance.OnOneClickInstallFinished();
}
private Task<string?> DownloadPackage(BasePackage selectedPackage, string version)
{
selectedPackage.DownloadProgressChanged += SelectedPackageOnProgressChanged;
selectedPackage.DownloadComplete += (_, _) => SubHeaderText = "Download Complete";
SubHeaderText = "Downloading package...";
return selectedPackage.DownloadPackage(version: version);
}
private async Task InstallPackage(BasePackage selectedPackage)
{
selectedPackage.InstallProgressChanged += SelectedPackageOnProgressChanged;
selectedPackage.InstallComplete += (_, _) => HeaderText = "Install Complete";
SubHeaderText = "Installing package...";
await selectedPackage.InstallPackage();
}
private void SelectedPackageOnProgressChanged(object? sender, int progress)
{
if (progress == -1)
{
IsIndeterminate = true;
}
else
{
IsIndeterminate = false;
OneClickInstallProgress = progress;
}
OnGlobalProgressChanged(this, progress);
}
/// <summary>
@ -70,13 +238,6 @@ public partial class MainWindowViewModel : ObservableObject
}
}
[RelayCommand]
private void GoAdvancedMode()
{
AdvancedModeVisibility = Visibility.Visible;
SimpleModeVisibility = Visibility.Hidden;
}
private void SetTheme()
{
var theme = settingsManager.Settings.Theme;

48
StabilityMatrix/ViewModels/PackageManagerViewModel.cs

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using StabilityMatrix.Helper;
@ -9,6 +11,7 @@ using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
using Polly;
using Wpf.Ui.Contracts;
using Wpf.Ui.Controls.ContentDialogControl;
using EventManager = StabilityMatrix.Helper.EventManager;
@ -22,6 +25,7 @@ public partial class PackageManagerViewModel : ObservableObject
private readonly IPackageFactory packageFactory;
private readonly IDialogFactory dialogFactory;
private readonly IContentDialogService contentDialogService;
private readonly IDialogErrorHandler dialogErrorHandler;
private const int MinutesToWaitForUpdateCheck = 60;
[ObservableProperty]
@ -51,13 +55,14 @@ public partial class PackageManagerViewModel : ObservableObject
private bool updateAvailable;
public PackageManagerViewModel(ILogger<PackageManagerViewModel> logger, ISettingsManager settingsManager,
IPackageFactory packageFactory, IDialogFactory dialogFactory, IContentDialogService contentDialogService)
IPackageFactory packageFactory, IDialogFactory dialogFactory, IContentDialogService contentDialogService, IDialogErrorHandler dialogErrorHandler)
{
this.logger = logger;
this.settingsManager = settingsManager;
this.packageFactory = packageFactory;
this.dialogFactory = dialogFactory;
this.contentDialogService = contentDialogService;
this.dialogErrorHandler = dialogErrorHandler;
ProgressText = "shrug";
InstallButtonText = "Install";
@ -82,13 +87,19 @@ public partial class PackageManagerViewModel : ObservableObject
public async Task OnLoaded()
{
Packages.Clear();
var installedPackages = settingsManager.Settings.InstalledPackages;
if (installedPackages.Count == 0)
{
SelectedPackage = new InstalledPackage
{
DisplayName = "Click \"Add Package\" to install a package"
};
InstallButtonVisibility = Visibility.Collapsed;
return;
}
Packages.Clear();
foreach (var packageToUpdate in installedPackages)
{
@ -159,12 +170,43 @@ public partial class PackageManagerViewModel : ObservableObject
if (result == ContentDialogResult.Primary)
{
DeleteDirectory(SelectedPackage.Path);
var deleteTask = DeleteDirectoryAsync(SelectedPackage.Path);
var taskResult = await dialogErrorHandler.TryAsync(deleteTask,
"Some files could not be deleted. Please close any open files in the package directory and try again.");
if (taskResult.IsSuccessful)
{
settingsManager.RemoveInstalledPackage(SelectedPackage);
}
await OnLoaded();
}
}
/// <summary>
/// Deletes a directory and all of its contents recursively.
/// Uses Polly to retry the deletion if it fails, up to 5 times with an exponential backoff.
/// </summary>
/// <param name="targetDirectory"></param>
private Task DeleteDirectoryAsync(string targetDirectory)
{
var policy = Policy.Handle<IOException>()
.WaitAndRetryAsync(3, attempt => TimeSpan.FromMilliseconds(50 * Math.Pow(2, attempt)),
onRetry: (exception, calculatedWaitDuration) =>
{
logger.LogWarning(
exception,
"Deletion of {TargetDirectory} failed. Retrying in {CalculatedWaitDuration}",
targetDirectory, calculatedWaitDuration);
});
return policy.ExecuteAsync(async () =>
{
await Task.Run(() =>
{
DeleteDirectory(targetDirectory);
});
});
}
private void DeleteDirectory(string targetDirectory)
{
// Delete all files in the directory

Loading…
Cancel
Save