diff --git a/src/dnvm/PruneCommand.cs b/src/dnvm/PruneCommand.cs index 8d0d83d..19c4e10 100644 --- a/src/dnvm/PruneCommand.cs +++ b/src/dnvm/PruneCommand.cs @@ -54,7 +54,7 @@ public static async Task Run(DnvmEnv env, Logger logger, Options options) if (!manifest.IsSdkInstalled(sdk.Version, sdk.Dir)) { env.Console.Warn($"SDK {sdk.Version} was not found in installed SDKs, cleaning up stale manifest entry."); - manifest = RemoveSdkFromChannels(manifest, sdk.Version); + manifest = RemoveSdkFromChannels(manifest, sdk.Version, sdk.Dir); await @lock.WriteManifest(env, manifest); continue; } @@ -110,18 +110,26 @@ public static async Task Run(DnvmEnv env, Logger logger, Options options) } } - return sdksToRemove; + return sdksToRemove.Distinct().ToList(); } /// - /// Removes an SDK version from all RegisteredChannels.InstalledSdkVersions. + /// Removes an SDK version from RegisteredChannels.InstalledSdkVersions for one SDK directory. /// This is used to clean up stale entries left by a bug fixed in /// https://github.com/dn-vm/dnvm/pull/274. /// - private static Manifest RemoveSdkFromChannels(Manifest manifest, SemVersion sdkVersion) + private static Manifest RemoveSdkFromChannels( + Manifest manifest, + SemVersion sdkVersion, + SdkDirName sdkDir) { var updatedChannels = manifest.RegisteredChannels.Select(channel => { + if (channel.SdkDirName != sdkDir) + { + return channel; + } + var updatedInstalledVersions = channel.InstalledSdkVersions .Where(version => version != sdkVersion) .ToEq(); diff --git a/src/dnvm/UninstallCommand.cs b/src/dnvm/UninstallCommand.cs index fbe1762..61641da 100644 --- a/src/dnvm/UninstallCommand.cs +++ b/src/dnvm/UninstallCommand.cs @@ -71,7 +71,7 @@ public static async Task Run(ManifestLock @lock, DnvmEnv env, Logger logger DeleteAspnets(env, aspnetToRemove, logger); DeleteWins(env, winToRemove, logger); - manifest = UninstallSdk(manifest, sdkVersion); + manifest = UninstallSdks(manifest, sdksToRemove); await @lock.WriteManifest(env, manifest); return 0; @@ -137,18 +137,18 @@ private static void DeleteWins(DnvmEnv env, IEnumerable<(SemVersion, SdkDirName) } } - private static Manifest UninstallSdk(Manifest manifest, SemVersion sdkVersion) + private static Manifest UninstallSdks( + Manifest manifest, + HashSet<(SemVersion Version, SdkDirName Dir)> sdksToRemove) { - // Delete SDK version from all directories var newVersions = manifest.InstalledSdks - .Where(sdk => sdk.SdkVersion != sdkVersion) + .Where(sdk => !sdksToRemove.Contains((sdk.SdkVersion, sdk.SdkDirName))) .ToEq(); - // Also remove the SDK version from RegisteredChannels.InstalledSdkVersions var updatedChannels = manifest.RegisteredChannels.Select(channel => { var updatedInstalledVersions = channel.InstalledSdkVersions - .Where(version => version != sdkVersion) + .Where(version => !sdksToRemove.Contains((version, channel.SdkDirName))) .ToEq(); return channel with { InstalledSdkVersions = updatedInstalledVersions }; }).ToEq(); diff --git a/test/UnitTests/PruneTests.cs b/test/UnitTests/PruneTests.cs index c5f131f..dd536cc 100644 --- a/test/UnitTests/PruneTests.cs +++ b/test/UnitTests/PruneTests.cs @@ -178,6 +178,58 @@ public Task MissingDirectoriesHandled() => RunWithServer(async (server, env) => Assert.Equal(upgradeVersion, finalManifest.InstalledSdks[0].SdkVersion); }); + [Fact] + public Task StaleCleanupDoesNotAffectOtherSdkDirectories() => RunWithServer(async (server, env) => + { + var oldVersion = new SemVersion(8, 0, 100); + var newVersion = new SemVersion(8, 0, 101); + var defaultDir = DnvmEnv.DefaultSdkDirName; + var alternateDir = new SdkDirName("alternate"); + + var manifest = Manifest.Empty + .AddSdk(oldVersion, sdkDirParam: defaultDir) + .AddSdk(newVersion, sdkDirParam: defaultDir) + .AddSdk(oldVersion, sdkDirParam: alternateDir); + manifest = manifest with + { + RegisteredChannels = + [ + new RegisteredChannel + { + ChannelName = new Channel.Latest(), + SdkDirName = defaultDir, + InstalledSdkVersions = [oldVersion, newVersion], + }, + new RegisteredChannel + { + ChannelName = new Channel.VersionedMajorMinor(8, 0), + SdkDirName = defaultDir, + InstalledSdkVersions = [oldVersion, newVersion], + }, + new RegisteredChannel + { + ChannelName = new Channel.VersionedMajorMinor(8, 0), + SdkDirName = alternateDir, + InstalledSdkVersions = [oldVersion], + }, + ] + }; + await Manifest.WriteManifestUnsafe(env, manifest); + + Assert.Equal( + [(oldVersion, defaultDir)], + PruneCommand.GetOutOfDateSdks(manifest)); + + Assert.Equal(0, await PruneCommand.Run(env, _logger, new PruneCommand.Options())); + + var finalManifest = await Manifest.ReadManifestUnsafe(env); + Assert.Contains(finalManifest.InstalledSdks, + sdk => sdk.SdkVersion == oldVersion && sdk.SdkDirName == alternateDir); + Assert.Contains(finalManifest.RegisteredChannels, + channel => channel.SdkDirName == alternateDir + && channel.InstalledSdkVersions.Contains(oldVersion)); + }); + /// /// Tests the scenario from https://github.com/dn-vm/dnvm/issues/311: /// Before PR #274, uninstalling an SDK removed it from InstalledSdks but not from