diff --git a/Cmdline/Action/Install.cs b/Cmdline/Action/Install.cs index 3f148bf6f..26b452dba 100644 --- a/Cmdline/Action/Install.cs +++ b/Cmdline/Action/Install.cs @@ -118,6 +118,7 @@ public int RunCommand(CKAN.GameInstance instance, object raw_options) without_enforce_consistency = user.Headless, }; + var autoInstalled = new HashSet(); for (bool done = false; !done; ) { // Install everything requested. :) @@ -129,7 +130,8 @@ public int RunCommand(CKAN.GameInstance instance, object raw_options) new InstalledFilesDeduplicator(instance, manager.Instances.Values, repoData), - options?.NetUserAgent); + options?.NetUserAgent, + null, autoInstalled); user.RaiseMessage(""); done = true; } @@ -165,6 +167,7 @@ public int RunCommand(CKAN.GameInstance instance, object raw_options) // Add the module to the list. modules.Add(choices[result]); + autoInstalled.Add(choices[result]); // DON'T return so we can loop around and try again } catch (CancelledActionKraken k) diff --git a/Cmdline/Action/Upgrade.cs b/Cmdline/Action/Upgrade.cs index d1d9992b9..a31ef2474 100644 --- a/Cmdline/Action/Upgrade.cs +++ b/Cmdline/Action/Upgrade.cs @@ -187,10 +187,10 @@ private void UpgradeModules(NetModuleCache cache, { UpgradeModules( cache, userAgent, user, instance, repoData, - (ModuleInstaller installer, NetAsyncModulesDownloader downloader, RegistryManager regMgr, ref HashSet? possibleConfigOnlyDirs) => + (ModuleInstaller installer, NetAsyncModulesDownloader downloader, RegistryManager regMgr, ref HashSet? possibleConfigOnlyDirs, ISet autoInstalled) => installer.Upgrade(modules, downloader, ref possibleConfigOnlyDirs, - regMgr, deduper, true, true), + regMgr, deduper, autoInstalled, true, true), modules.Add); } @@ -210,7 +210,7 @@ private void UpgradeModules(NetModuleCache cache, { UpgradeModules( cache, userAgent, user, instance, repoData, - (ModuleInstaller installer, NetAsyncModulesDownloader downloader, RegistryManager regMgr, ref HashSet? possibleConfigOnlyDirs) => + (ModuleInstaller installer, NetAsyncModulesDownloader downloader, RegistryManager regMgr, ref HashSet? possibleConfigOnlyDirs, ISet autoInstalled) => { var crit = instance.VersionCriteria(); var registry = regMgr.registry; @@ -251,7 +251,7 @@ private void UpgradeModules(NetModuleCache cache, if (to_upgrade.Count > 0) { installer.Upgrade(to_upgrade, downloader, - ref possibleConfigOnlyDirs, regMgr, deduper, true); + ref possibleConfigOnlyDirs, regMgr, deduper, autoInstalled, true); } }, m => identsAndVersions.Add(m.identifier)); @@ -265,7 +265,7 @@ private static string UpTo(string orig, int pos) : orig; // Action isn't allowed - private delegate void AttemptUpgradeAction(ModuleInstaller installer, NetAsyncModulesDownloader downloader, RegistryManager regMgr, ref HashSet? possibleConfigOnlyDirs); + private delegate void AttemptUpgradeAction(ModuleInstaller installer, NetAsyncModulesDownloader downloader, RegistryManager regMgr, ref HashSet? possibleConfigOnlyDirs, ISet autoInstalled); /// /// The core of the module upgrading logic, with callbacks to @@ -292,12 +292,13 @@ private void UpgradeModules(NetModuleCache cache, var downloader = new NetAsyncModulesDownloader(user, cache, userAgent); var regMgr = RegistryManager.Instance(instance, repoData); HashSet? possibleConfigOnlyDirs = null; + var autoInstalled = new HashSet(); bool done = false; while (!done) { try { - attemptUpgradeCallback?.Invoke(installer, downloader, regMgr, ref possibleConfigOnlyDirs); + attemptUpgradeCallback?.Invoke(installer, downloader, regMgr, ref possibleConfigOnlyDirs, autoInstalled); transact.Complete(); done = true; } diff --git a/ConsoleUI/InstallScreen.cs b/ConsoleUI/InstallScreen.cs index 142084eb4..ff67b0399 100644 --- a/ConsoleUI/InstallScreen.cs +++ b/ConsoleUI/InstallScreen.cs @@ -55,6 +55,7 @@ public override void Run(Action? process = null) if (manager.CurrentInstance != null && manager.Cache != null) { using (TransactionScope trans = CkanTransaction.CreateTransactionScope()) { + var autoInstalled = new HashSet(); bool retry = false; do { Draw(); @@ -109,7 +110,7 @@ public override void Run(Action? process = null) ?? m) .ToArray(); inst.InstallList(iList, resolvOpts(stabilityTolerance), regMgr, - ref possibleConfigOnlyDirs, deduper, userAgent, dl); + ref possibleConfigOnlyDirs, deduper, userAgent, dl, autoInstalled); plan.Install.Clear(); } if (plan.Upgrade.Count > 0) { @@ -120,7 +121,7 @@ public override void Run(Action? process = null) .Keys .Except(plan.Upgrade) .ToHashSet()); - inst.Upgrade(upgGroups[true], dl, ref possibleConfigOnlyDirs, regMgr, deduper); + inst.Upgrade(upgGroups[true], dl, ref possibleConfigOnlyDirs, regMgr, deduper, autoInstalled); plan.Upgrade.Clear(); } if (plan.Replace.Count > 0) { @@ -148,6 +149,7 @@ public override void Run(Action? process = null) if (chosen != null) { // Use chosen to continue installing plan.Install.Add(chosen); + autoInstalled.Add(chosen); retry = true; } diff --git a/Core/IO/ModuleInstaller.cs b/Core/IO/ModuleInstaller.cs index 76d06775d..374c98a25 100644 --- a/Core/IO/ModuleInstaller.cs +++ b/Core/IO/ModuleInstaller.cs @@ -64,6 +64,7 @@ public void InstallList(IReadOnlyCollection modules, InstalledFilesDeduplicator? deduper = null, string? userAgent = null, IDownloader? downloader = null, + ISet? autoInstalled = null, bool ConfirmPrompt = true) { if (modules.Count == 0) @@ -141,7 +142,8 @@ public void InstallList(IReadOnlyCollection modules, // Re-check that there's enough free space in case game dir and cache are on same drive CKANPathUtils.CheckFreeSpace(gameDir, mod.install_size, Properties.Resources.NotEnoughSpaceToInstall); - Install(mod, resolver.IsAutoInstalled(mod), + Install(mod, + (autoInstalled?.Contains(mod) ?? false) || resolver.IsAutoInstalled(mod), registry_manager.registry, deduper?.ModuleCandidateDuplicates(mod.identifier, mod.version), ref possibleConfigOnlyDirs, @@ -1173,7 +1175,7 @@ private void AddRemove(ref HashSet? possibleConfigOnlyDi RegistryManager registry_manager, RelationshipResolver resolver, IReadOnlyCollection add, - IDictionary autoInstalled, + ISet autoInstalled, IReadOnlyCollection remove, IDownloader downloader, bool enforceConsistency, @@ -1242,7 +1244,7 @@ private void AddRemove(ref HashSet? possibleConfigOnlyDi // for replacing, new modules are the replacements and should not be marked auto-installed remove?.FirstOrDefault(im => im.Module.identifier == mod.identifier) ?.AutoInstalled - ?? autoInstalled[mod], + ?? autoInstalled.Contains(mod), registry_manager.registry, deduper?.ModuleCandidateDuplicates(mod.identifier, mod.version), ref possibleConfigOnlyDirs, @@ -1277,6 +1279,7 @@ public void Upgrade(in IReadOnlyCollection modules, ref HashSet? possibleConfigOnlyDirs, RegistryManager registry_manager, InstalledFilesDeduplicator? deduper = null, + ISet? autoInstalled = null, bool enforceConsistency = true, bool ConfirmPrompt = true) { @@ -1316,7 +1319,8 @@ public void Upgrade(in IReadOnlyCollection modules, .Select(im => im.Module) .Except(modules)) .ToArray(); - var autoInstalled = toInstall.ToDictionary(m => m, resolver.IsAutoInstalled); + autoInstalled ??= new HashSet(); + autoInstalled.UnionWith(toInstall.Where(resolver.IsAutoInstalled)); User.RaiseMessage(Properties.Resources.ModuleInstallerAboutToUpgrade); User.RaiseMessage(""); @@ -1526,7 +1530,7 @@ public void Replace(IEnumerable replacements, registry_manager, resolver, resolvedModsToInstall, - resolvedModsToInstall.ToDictionary(m => m, m => false), + new HashSet(), modsToRemove, downloader, enforceConsistency, diff --git a/GUI/Main/MainInstall.cs b/GUI/Main/MainInstall.cs index 0c614c1e2..e93fea466 100644 --- a/GUI/Main/MainInstall.cs +++ b/GUI/Main/MainInstall.cs @@ -112,6 +112,7 @@ private void InstallMods(object? sender, DoWorkEventArgs? e) // this will be the final list of mods we want to install var toInstall = new List(); + var autoInstalled = new HashSet(); var toUninstall = new HashSet(); var toUpgrade = new HashSet(); @@ -253,13 +254,13 @@ private void InstallMods(object? sender, DoWorkEventArgs? e) if (!canceled && toInstall.Count > 0) { installer.InstallList(toInstall, options, registry_manager, ref possibleConfigOnlyDirs, - deduper, userAgent, downloader, false); + deduper, userAgent, downloader, autoInstalled, false); toInstall.Clear(); } if (!canceled && toUpgrade.Count > 0) { installer.Upgrade(toUpgrade, downloader, ref possibleConfigOnlyDirs, registry_manager, - deduper, true, false); + deduper, autoInstalled, true, false); toUpgrade.Clear(); } if (canceled) @@ -345,6 +346,7 @@ private void InstallMods(object? sender, DoWorkEventArgs? e) { // User picked a mod, queue it up for installation toInstall.Add(chosen); + autoInstalled.Add(chosen); // DON'T return so we can loop around and try the above InstallList call again tabController.ShowTab(WaitTabPage.Name); Util.Invoke(this, () => StatusProgress.Visible = true); diff --git a/Tests/Core/IO/ModuleInstallerDirTest.cs b/Tests/Core/IO/ModuleInstallerDirTest.cs index 75d72a0df..61818f624 100644 --- a/Tests/Core/IO/ModuleInstallerDirTest.cs +++ b/Tests/Core/IO/ModuleInstallerDirTest.cs @@ -60,7 +60,7 @@ public void SetUp() _manager.Cache?.Store(_testModule!, testModFile, new Progress(bytes => {})); HashSet? possibleConfigOnlyDirs = null; _installer.InstallList( - new List() { _testModule! }, + new CkanModule[] { _testModule! }, new RelationshipResolverOptions(_instance.KSP.StabilityToleranceConfig), _registryManager, ref possibleConfigOnlyDirs); diff --git a/Tests/Core/IO/ModuleInstallerTests.cs b/Tests/Core/IO/ModuleInstallerTests.cs index 6938ad0c2..d7e5e99da 100644 --- a/Tests/Core/IO/ModuleInstallerTests.cs +++ b/Tests/Core/IO/ModuleInstallerTests.cs @@ -1608,7 +1608,7 @@ public void Upgrade_WithAutoInst_RemovesAutoRemovable(string[] regularMods, registry.LatestAvailable(ident, inst.KSP.StabilityToleranceConfig, inst.KSP.VersionCriteria())) .OfType() .ToArray(), - downloader, ref possibleConfigOnlyDirs, regMgr, null, false); + downloader, ref possibleConfigOnlyDirs, regMgr, null, null, false); // Assert CollectionAssert.AreEquivalent(correctRemainingIdentifiers, @@ -1706,7 +1706,7 @@ public void Upgrade_WithUnstableAutoinstDep_NotRemoved(string[] regularInstalled installer.Upgrade(toUpgrade.Select(CkanModule.FromJson) .ToArray(), downloader, ref possibleConfigOnlyDirs, - regMgr, null, false); + regMgr, null, null, false); }); CollectionAssert.AreEquivalent(registry.InstalledModules.Select(im => im.Module), autoInstalled.Select(CkanModule.FromJson) diff --git a/Tests/GUI/Model/ModList.cs b/Tests/GUI/Model/ModList.cs index 267d06ff8..c71c26886 100644 --- a/Tests/GUI/Model/ModList.cs +++ b/Tests/GUI/Model/ModList.cs @@ -777,7 +777,7 @@ public void InstallAndSortByCompat_WithAnyCompat_NoCrash() HashSet? possibleConfigOnlyDirs = null; installer.InstallList( - new List { anyVersionModule }, + new CkanModule[] { anyVersionModule }, new RelationshipResolverOptions(instance.KSP.StabilityToleranceConfig), regMgr, ref possibleConfigOnlyDirs, @@ -825,7 +825,7 @@ public void InstallAndSortByCompat_WithAnyCompat_NoCrash() installer.InstallList( modList.ComputeUserChangeSet(Registry.Empty(repoData.Manager), inst2.KSP, null, null) .Select(change => change.Mod) - .ToList(), + .ToArray(), new RelationshipResolverOptions(inst2.KSP.StabilityToleranceConfig), regMgr, ref possibleConfigOnlyDirs,