Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade AD mods with mismatched version in filename #3287

Merged
merged 1 commit into from
Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Core/GameInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ public bool Scan()
// The least evil is to walk it once, and filter it ourselves.
IEnumerable<string> files = Directory
.EnumerateFiles(game.PrimaryModDirectory(this), "*", SearchOption.AllDirectories)
.Where(file => dllRegex.IsMatch(file))
.Where(file => file.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase))
.Select(CKANPathUtils.NormalizePath)
.Where(absPath => !game.StockFolders.Any(f =>
ToRelativeGameDir(absPath).StartsWith($"{f}/")));
Expand All @@ -365,8 +365,6 @@ public bool Scan()
}
}

private static readonly Regex dllRegex = new Regex(@"\.dll$", RegexOptions.IgnoreCase | RegexOptions.Compiled);

#endregion

/// <summary>
Expand Down
37 changes: 26 additions & 11 deletions Core/ModuleInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ private static void CheckKindInstallationKraken(CkanModule module)
/// <summary>
/// Installs the module from the zipfile provided.
/// Returns a list of files installed.
/// Propagates a DllLocationMismatchKraken if the user has a bad manual install.
/// Propagates a BadMetadataKraken if our install metadata is bad.
/// Propagates a CancelledActionKraken if the user decides not to overwite unowned files.
/// Propagates a FileExistsKraken if we were going to overwrite a file.
Expand All @@ -348,9 +349,27 @@ private IEnumerable<string> InstallModule(CkanModule module, string zip_filename
try
{
var dll = registry.DllPath(module.identifier);
if (dll != null && !files.Any(f => ksp.ToRelativeGameDir(f.destination) == dll))
if (!string.IsNullOrEmpty(dll))
{
throw new DllLocationMismatchKraken(dll, $"DLL for module {module.identifier} found at {dll}, but it's not where CKAN would install it. Aborting to prevent multiple copies of the same mod being installed. To install this module, uninstall it manually and try again.");
// Find where we're installing identifier.optionalversion.dll
// (file name might not be an exact match with manually installed)
var dllFolders = files.Where(f =>
Path.GetFileName(f.destination).StartsWith(module.identifier)
&& f.destination.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase))
.Select(f => Path.GetDirectoryName(ksp.ToRelativeGameDir(f.destination)))
.ToHashSet();
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, $"DLL for module {module.identifier} found at {dll}, but it's not where CKAN would install it. Aborting to prevent multiple copies of the same mod being installed. To install this module, uninstall it manually and try again.");
}
// 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
Expand Down Expand Up @@ -474,14 +493,10 @@ private bool StreamsEqual(Stream s1, Stream s2)
private void DeleteConflictingFiles(IEnumerable<InstallableFile> files)
{
TxFileManager file_transaction = new TxFileManager();
using (var transaction = CkanTransaction.CreateTransactionScope())
foreach (InstallableFile file in files)
{
foreach (InstallableFile file in files)
{
log.DebugFormat("Trying to delete {0}", file.destination);
file_transaction.Delete(file.destination);
}
transaction.Complete();
log.DebugFormat("Trying to delete {0}", file.destination);
file_transaction.Delete(file.destination);
}
}

Expand Down Expand Up @@ -585,8 +600,8 @@ internal static void CopyZipEntry(ZipFile zipfile, ZipEntry entry, string fullPa
}

// Snapshot whatever was there before. If there's nothing, this will just
// remove our file on rollback. We still need this even thought we won't
// overwite files, as it ensures deletiion on rollback.
// remove our file on rollback. We still need this even though we won't
// overwite files, as it ensures deletion on rollback.
file_transaction.Snapshot(fullPath);

try
Expand Down
6 changes: 3 additions & 3 deletions Core/Registry/Registry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -836,9 +836,9 @@ public void RegisterDll(GameInstance ksp, string absolute_path)

// http://xkcd.com/208/
// This regex works great for things like GameData/Foo/Foo-1.2.dll
Match match = Regex.Match(
relative_path, @"
^GameData/ # DLLs only live in GameData
Match match = Regex.Match(relative_path,
// DLLs only live in the primary mod directory
$"^{ksp.game.PrimaryModDirectoryRelative}/" + @"
(?:.*/)? # Intermediate paths (ending with /)
(?<modname>[^.]+) # Our DLL name, up until the first dot.
.*\.dll$ # Everything else, ending in dll
Expand Down