Skip to content

Commit

Permalink
Merge #3287 Upgrade AD mods with mismatched version in filename
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Feb 3, 2021
2 parents 6de9c74 + 79bc521 commit cd33a56
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file.
- [GUI] Repo update usability fixes (#3249 by: HebaruSan; reviewed: DasSkelett)
- [GUI] Added null checks in ManageMods.cs to prevent crash on an empty filter (#3266 by: Hydroxa; reviewed: HebaruSan)
- [Updater] Report AutoUpdater errors to user, fix rare failure (#3250 by: HebaruSan; reviewed: DasSkelett)
- [Core] Upgrade AD mods with mismatched version in filename (#3287 by: HebaruSan; reviewed: DasSkelett)

### Internal

Expand Down
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

0 comments on commit cd33a56

Please sign in to comment.