| File: ToolPackage\ToolPackageUninstaller.cs | Web Access |
| Project: src\sdk\src\Cli\dotnet\dotnet.csproj (dotnet) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable disable using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.ToolPackage; using Microsoft.DotNet.Cli.Utils; using Microsoft.Extensions.EnvironmentAbstractions; internal class ToolPackageUninstaller(IToolPackageStore toolPackageStoreQuery) : IToolPackageUninstaller { private readonly IToolPackageStore _toolPackageStoreQuery = toolPackageStoreQuery ?? throw new ArgumentException(nameof(toolPackageStoreQuery)); public void Uninstall(DirectoryPath packageDirectory) { var rootDirectory = packageDirectory.GetParentPath(); string tempPackageDirectory = null; TransactionalAction.Run( action: () => { try { if (Directory.Exists(packageDirectory.Value)) { // Use the staging directory for uninstall // This prevents cross-device moves when temp is mounted to a different device var tempPath = _toolPackageStoreQuery.GetRandomStagingDirectory().Value; FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(packageDirectory.Value, tempPath)); tempPackageDirectory = tempPath; } if (Directory.Exists(rootDirectory.Value) && !Directory.EnumerateFileSystemEntries(rootDirectory.Value).Any()) { Directory.Delete(rootDirectory.Value, false); } } catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException) { throw new ToolPackageException(ex.Message, ex); } }, commit: () => { if (tempPackageDirectory != null) { Directory.Delete(tempPackageDirectory, true); } }, rollback: () => { if (tempPackageDirectory != null) { Directory.CreateDirectory(rootDirectory.Value); FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(tempPackageDirectory, packageDirectory.Value)); } }); } }