You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
3.3 KiB
108 lines
3.3 KiB
10 months ago
|
using System.Diagnostics.CodeAnalysis;
|
||
1 year ago
|
using Microsoft.Extensions.Logging;
|
||
|
using Polly;
|
||
|
using StabilityMatrix.Core.Models.FileInterfaces;
|
||
|
|
||
10 months ago
|
namespace StabilityMatrix.Core.Extensions;
|
||
1 year ago
|
|
||
|
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||
|
public static class DirectoryPathExtensions
|
||
|
{
|
||
|
/// <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>
|
||
10 months ago
|
public static Task DeleteVerboseAsync(
|
||
|
this DirectoryPath directory,
|
||
|
ILogger? logger = default,
|
||
|
CancellationToken cancellationToken = default
|
||
|
)
|
||
1 year ago
|
{
|
||
10 months ago
|
var policy = Policy
|
||
|
.Handle<IOException>()
|
||
|
.WaitAndRetryAsync(
|
||
|
3,
|
||
|
attempt => TimeSpan.FromMilliseconds(50 * Math.Pow(2, attempt)),
|
||
1 year ago
|
onRetry: (exception, calculatedWaitDuration) =>
|
||
|
{
|
||
|
logger?.LogWarning(
|
||
|
exception,
|
||
|
"Deletion of {TargetDirectory} failed. Retrying in {CalculatedWaitDuration}",
|
||
10 months ago
|
directory,
|
||
|
calculatedWaitDuration
|
||
|
);
|
||
|
}
|
||
|
);
|
||
1 year ago
|
|
||
|
return policy.ExecuteAsync(async () =>
|
||
|
{
|
||
10 months ago
|
await Task.Run(() => DeleteVerbose(directory, logger, cancellationToken), cancellationToken)
|
||
|
.ConfigureAwait(false);
|
||
1 year ago
|
});
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Deletes a directory and all of its contents recursively.
|
||
|
/// Removes link targets without deleting the source.
|
||
|
/// </summary>
|
||
10 months ago
|
public static void DeleteVerbose(
|
||
|
this DirectoryPath directory,
|
||
|
ILogger? logger = default,
|
||
|
CancellationToken cancellationToken = default
|
||
|
)
|
||
1 year ago
|
{
|
||
10 months ago
|
cancellationToken.ThrowIfCancellationRequested();
|
||
|
|
||
1 year ago
|
// Skip if directory does not exist
|
||
|
if (!directory.Exists)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
// For junction points, delete with recursive false
|
||
|
if (directory.IsSymbolicLink)
|
||
|
{
|
||
10 months ago
|
logger?.LogInformation("Removing junction point {TargetDirectory}", directory.FullPath);
|
||
1 year ago
|
try
|
||
|
{
|
||
|
directory.Delete(false);
|
||
|
return;
|
||
|
}
|
||
|
catch (IOException ex)
|
||
|
{
|
||
10 months ago
|
throw new IOException($"Failed to delete junction point {directory.FullPath}", ex);
|
||
1 year ago
|
}
|
||
|
}
|
||
|
// Recursively delete all subdirectories
|
||
10 months ago
|
foreach (var subDir in directory.EnumerateDirectories())
|
||
1 year ago
|
{
|
||
10 months ago
|
DeleteVerbose(subDir, logger, cancellationToken);
|
||
1 year ago
|
}
|
||
10 months ago
|
|
||
1 year ago
|
// Delete all files in the directory
|
||
10 months ago
|
foreach (var filePath in directory.EnumerateFiles())
|
||
1 year ago
|
{
|
||
10 months ago
|
cancellationToken.ThrowIfCancellationRequested();
|
||
|
|
||
1 year ago
|
try
|
||
|
{
|
||
10 months ago
|
filePath.Info.Attributes = FileAttributes.Normal;
|
||
1 year ago
|
filePath.Delete();
|
||
|
}
|
||
|
catch (IOException ex)
|
||
|
{
|
||
10 months ago
|
throw new IOException($"Failed to delete file {filePath.FullPath}", ex);
|
||
1 year ago
|
}
|
||
|
}
|
||
10 months ago
|
|
||
1 year ago
|
// Delete this directory
|
||
|
try
|
||
|
{
|
||
|
directory.Delete(false);
|
||
|
}
|
||
|
catch (IOException ex)
|
||
|
{
|
||
|
throw new IOException($"Failed to delete directory {directory}", ex);
|
||
|
}
|
||
|
}
|
||
|
}
|