From 383c7ebef3dd26ae1197a50bca6f1ea859ab0682 Mon Sep 17 00:00:00 2001 From: Paul Hebble Date: Tue, 13 Feb 2024 10:41:39 -0600 Subject: [PATCH] Only auto-delete manually installed DLLs unless also replacing them --- Core/ModuleInstaller.cs | 28 +++++++++++++++------------- Core/Registry/Registry.cs | 20 ++++++++++++-------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/Core/ModuleInstaller.cs b/Core/ModuleInstaller.cs index ead7186a85..63cba9192f 100644 --- a/Core/ModuleInstaller.cs +++ b/Core/ModuleInstaller.cs @@ -154,7 +154,7 @@ public void InstallList(ICollection modules, } } - if (ConfirmPrompt && !User.RaiseYesNoDialog("Continue?")) + if (ConfirmPrompt && !User.RaiseYesNoDialog(Properties.Resources.ModuleInstallerContinuePrompt)) { throw new CancelledActionKraken(Properties.Resources.ModuleInstallerUserDeclined); } @@ -347,20 +347,22 @@ private IEnumerable InstallModule(CkanModule module, string zip_filename .ToHashSet(); // Make sure that the DLL is actually included in the install // (NearFutureElectrical, NearFutureElectrical-Core) - if (dllFolders.Count > 0 - && !dllFolders.Contains(Path.GetDirectoryName(dll))) + if (dllFolders.Count > 0) { - // Manually installed DLL is somewhere else where we're not installing files, - // probable bad install, alert user and abort - throw new DllLocationMismatchKraken(dll, string.Format( - Properties.Resources.ModuleInstallerBadDLLLocation, module.identifier, dll)); + if (!dllFolders.Contains(Path.GetDirectoryName(dll))) + { + // Manually installed DLL is somewhere else where we're not installing files, + // probable bad install, alert user and abort + throw new DllLocationMismatchKraken(dll, string.Format( + Properties.Resources.ModuleInstallerBadDLLLocation, module.identifier, dll)); + } + // Delete the manually installed DLL transaction-style because we believe we'll be replacing it + var toDelete = ksp.ToAbsoluteGameDir(dll); + log.DebugFormat("Deleting manually installed DLL {0}", toDelete); + TxFileManager file_transaction = new TxFileManager(); + file_transaction.Snapshot(toDelete); + file_transaction.Delete(toDelete); } - // Delete the manually installed DLL transaction-style because we believe we'll be replacing it - var toDelete = ksp.ToAbsoluteGameDir(dll); - log.DebugFormat("Deleting manually installed DLL {0}", toDelete); - TxFileManager file_transaction = new TxFileManager(); - file_transaction.Snapshot(toDelete); - file_transaction.Delete(toDelete); } // Look for overwritable files if session is interactive diff --git a/Core/Registry/Registry.cs b/Core/Registry/Registry.cs index 113a15647e..fb1981e82d 100644 --- a/Core/Registry/Registry.cs +++ b/Core/Registry/Registry.cs @@ -35,7 +35,7 @@ public class Registry : IEnlistmentNotification, IRegistryQuerier [JsonProperty("sorted_repositories")] private SortedDictionary repositories; - // name => path + // name => relative path [JsonProperty] private Dictionary installed_dlls; @@ -834,7 +834,7 @@ public List LatestAvailableWithProvides( /// track of its metadata and files. /// public void RegisterModule(CkanModule mod, - IEnumerable absolute_files, + IEnumerable absoluteFiles, GameInstance inst, bool autoInstalled) { @@ -850,13 +850,14 @@ public void RegisterModule(CkanModule mod, var inconsistencies = new List(); // We always work with relative files, so let's get some! - IEnumerable relative_files = absolute_files - .Select(x => inst.ToRelativeGameDir(x)) - .Memoize(); + var relativeFiles = absoluteFiles.Select(x => inst.ToRelativeGameDir(x)) + .ToHashSet(Platform.IsWindows + ? StringComparer.OrdinalIgnoreCase + : StringComparer.Ordinal); // For now, it's always cool if a module wants to register a directory. // We have to flip back to absolute paths to actually test this. - foreach (string file in relative_files.Where(file => !Directory.Exists(inst.ToAbsoluteGameDir(file)))) + foreach (string file in relativeFiles.Where(file => !Directory.Exists(inst.ToAbsoluteGameDir(file)))) { if (installed_files.TryGetValue(file, out string owner)) { @@ -881,14 +882,17 @@ public void RegisterModule(CkanModule mod, // directories aren't really owned like files are. However because each mod maintains // its own list of files, we'll remove directories when the last mod using them // is uninstalled. - foreach (string file in relative_files) + foreach (string file in relativeFiles) { installed_files[file] = mod.identifier; } + // Make sure mod-owned files aren't in the manually installed DLL dict + installed_dlls.RemoveWhere(kvp => relativeFiles.Contains(kvp.Value)); + // Finally register our module proper installed_modules.Add(mod.identifier, - new InstalledModule(inst, mod, relative_files, autoInstalled)); + new InstalledModule(inst, mod, relativeFiles, autoInstalled)); // Installing and uninstalling mods can change compatibility due to conflicts, // so we'll need to reset the compatibility sorter