Skip to content

Commit 0b421e8

Browse files
committed
Merge #4609 Don't revert removals on providing mod choice
2 parents 2651fef + 13ed64e commit 0b421e8

2 files changed

Lines changed: 117 additions & 109 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ All notable changes to this project will be documented in this file.
4343
- [Multiple] Non-Latin letter search (#4605 by: HebaruSan)
4444
- [Build] Automatically pull focus for the Terminal window on MacOS (#4606 by: cheesebellies; reviewed: HebaruSan)
4545
- [GUI] Resets Play Button state if the game launch is cancelled (#4607 by: neilsapno; reviewed: HebaruSan)
46+
- [GUI] Don't revert removals on providing mod choice (#4609 by: HebaruSan)
4647

4748
### Internal
4849

GUI/Main/MainInstall.cs

Lines changed: 116 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -256,125 +256,132 @@ private void InstallMods(object? sender, DoWorkEventArgs? e)
256256
for (bool resolvedAllProvidedMods = false; !resolvedAllProvidedMods;)
257257
{
258258
// Treat whole changeset as atomic
259-
using (TransactionScope transaction = CkanTransaction.CreateTransactionScope())
259+
using (var transaction = CkanTransaction.CreateTransactionScope())
260260
{
261-
try
261+
// Don't repeat these steps within the same transaction
262+
bool didUninstall = false;
263+
bool didInstall = false;
264+
// Re-use the transaction for providing mod prompts
265+
while (!resolvedAllProvidedMods
266+
&& Transaction.Current?.TransactionInformation.Status != TransactionStatus.Aborted)
262267
{
263-
e.Result = new InstallResult(false, changes);
264-
if (!canceled && toUninstall.Count > 0)
265-
{
266-
installer.UninstallList(toUninstall.Select(m => m.identifier),
267-
ref possibleConfigOnlyDirs, registry_manager, false, toInstall);
268-
toUninstall.Clear();
269-
}
270-
if (!canceled && toInstall.Count > 0)
271-
{
272-
installer.InstallList(toInstall, options, registry_manager, ref possibleConfigOnlyDirs,
273-
deduper, userAgent, downloader, autoInstalled, false);
274-
toInstall.Clear();
275-
}
276-
if (!canceled && toUpgrade.Count > 0)
277-
{
278-
installer.Upgrade(toUpgrade, downloader, ref possibleConfigOnlyDirs, registry_manager,
279-
deduper, autoInstalled, skipFiles, true, false);
280-
toUpgrade.Clear();
281-
}
282-
if (canceled)
268+
try
283269
{
284270
e.Result = new InstallResult(false, changes);
285-
throw new CancelledActionKraken();
271+
if (!canceled && toUninstall.Count > 0 && !didUninstall)
272+
{
273+
installer.UninstallList(toUninstall.Select(m => m.identifier),
274+
ref possibleConfigOnlyDirs, registry_manager, false, toInstall);
275+
didUninstall = true;
276+
}
277+
if (!canceled && toInstall.Count > 0 && !didInstall)
278+
{
279+
installer.InstallList(toInstall, options, registry_manager, ref possibleConfigOnlyDirs,
280+
deduper, userAgent, downloader, autoInstalled, false);
281+
didInstall = true;
282+
}
283+
if (!canceled && toUpgrade.Count > 0)
284+
{
285+
installer.Upgrade(toUpgrade, downloader, ref possibleConfigOnlyDirs, registry_manager,
286+
deduper, autoInstalled, skipFiles, true, false);
287+
}
288+
if (canceled)
289+
{
290+
e.Result = new InstallResult(false, changes);
291+
throw new CancelledActionKraken();
292+
}
293+
transaction.Complete();
294+
resolvedAllProvidedMods = true;
286295
}
287-
transaction.Complete();
288-
resolvedAllProvidedMods = true;
289-
}
290-
catch (ModuleDownloadErrorsKraken k)
291-
{
292-
// Get full changeset (toInstall only includes user's selections, not dependencies)
293-
var crit = CurrentInstance.VersionCriteria();
294-
var fullChangeset = new RelationshipResolver(
295-
toInstall.Concat(toUpgrade), toUninstall, options, registry, CurrentInstance.Game, crit
296-
).ModList().ToList();
297-
DownloadsFailedDialog? dfd = null;
298-
Util.Invoke(this, () =>
296+
catch (ModuleDownloadErrorsKraken k)
299297
{
300-
dfd = new DownloadsFailedDialog(
301-
Properties.Resources.ModDownloadsFailedMessage,
302-
Properties.Resources.ModDownloadsFailedColHdr,
303-
Properties.Resources.ModDownloadsFailedAbortBtn,
304-
k.Exceptions.Select(kvp => new KeyValuePair<object[], Exception>(
305-
fullChangeset.Where(m => (m.download ?? Enumerable.Empty<Uri>())
306-
.IntersectsWith(kvp.Key.download ?? Enumerable.Empty<Uri>()))
307-
.ToArray(),
308-
kvp.Value)),
309-
(m1, m2) => (m1 as CkanModule)?.download == (m2 as CkanModule)?.download);
310-
dfd.ShowDialog(this);
311-
});
312-
var skip = (dfd?.Wait()?.OfType<CkanModule>() ?? Enumerable.Empty<CkanModule>())
313-
.ToArray();
314-
var abort = dfd?.Abort ?? false;
315-
dfd?.Dispose();
316-
if (abort)
317-
{
318-
canceled = true;
319-
e.Result = new InstallResult(false, changes);
320-
throw new CancelledActionKraken();
321-
}
298+
// Get full changeset (toInstall only includes user's selections, not dependencies)
299+
var crit = CurrentInstance.VersionCriteria();
300+
var fullChangeset = new RelationshipResolver(
301+
toInstall.Concat(toUpgrade), toUninstall, options, registry, CurrentInstance.Game, crit
302+
).ModList().ToList();
303+
DownloadsFailedDialog? dfd = null;
304+
Util.Invoke(this, () =>
305+
{
306+
dfd = new DownloadsFailedDialog(
307+
Properties.Resources.ModDownloadsFailedMessage,
308+
Properties.Resources.ModDownloadsFailedColHdr,
309+
Properties.Resources.ModDownloadsFailedAbortBtn,
310+
k.Exceptions.Select(kvp => new KeyValuePair<object[], Exception>(
311+
fullChangeset.Where(m => (m.download ?? Enumerable.Empty<Uri>())
312+
.IntersectsWith(kvp.Key.download ?? Enumerable.Empty<Uri>()))
313+
.ToArray(),
314+
kvp.Value)),
315+
(m1, m2) => (m1 as CkanModule)?.download == (m2 as CkanModule)?.download);
316+
dfd.ShowDialog(this);
317+
});
318+
var skip = (dfd?.Wait()?.OfType<CkanModule>() ?? Enumerable.Empty<CkanModule>())
319+
.ToArray();
320+
var abort = dfd?.Abort ?? false;
321+
dfd?.Dispose();
322+
if (abort)
323+
{
324+
canceled = true;
325+
e.Result = new InstallResult(false, changes);
326+
throw new CancelledActionKraken();
327+
}
322328

323-
if (skip.Length > 0)
324-
{
325-
// Remove mods from changeset that user chose to skip
326-
// and any mods depending on them
327-
var dependers = Registry.FindReverseDependencies(
328-
skip.Select(s => s.identifier).ToList(),
329-
Array.Empty<CkanModule>(),
330-
registry.InstalledModules.Select(im => im.Module)
331-
.Concat(fullChangeset)
332-
.ToArray(),
333-
registry.InstalledDlls, registry.InstalledDlc,
334-
// Consider virtual dependencies satisfied so user can make a new choice if they skip
335-
rel => rel.LatestAvailableWithProvides(registry, stabilityTolerance, crit).Count > 1)
336-
.ToHashSet();
337-
toInstall.RemoveAll(m => dependers.Contains(m.identifier));
338-
}
329+
if (skip.Length > 0)
330+
{
331+
// Remove mods from changeset that user chose to skip
332+
// and any mods depending on them
333+
var dependers = Registry.FindReverseDependencies(
334+
skip.Select(s => s.identifier).ToList(),
335+
Array.Empty<CkanModule>(),
336+
registry.InstalledModules.Select(im => im.Module)
337+
.Concat(fullChangeset)
338+
.ToArray(),
339+
registry.InstalledDlls, registry.InstalledDlc,
340+
// Consider virtual dependencies satisfied so user can make a new choice if they skip
341+
rel => rel.LatestAvailableWithProvides(registry, stabilityTolerance, crit).Count > 1)
342+
.ToHashSet();
343+
toInstall.RemoveAll(m => dependers.Contains(m.identifier));
344+
}
339345

340-
// Now we loop back around again
341-
}
342-
catch (TooManyModsProvideKraken k)
343-
{
344-
// Prompt user to choose which mod to use
345-
tabController.ShowTab(ChooseProvidedModsTabPage.Name, 3);
346-
Util.Invoke(this, () => StatusProgress.Visible = false);
347-
var repoData = ServiceLocator.Container.Resolve<RepositoryDataManager>();
348-
ChooseProvidedMods.LoadProviders(
349-
k.Message,
350-
k.modules.OrderByDescending(Manager.Cache.IsCached)
351-
.ThenByDescending(m => repoData.GetDownloadCount(registry.Repositories.Values,
352-
m.identifier)
353-
?? 0)
354-
.ThenByDescending(m => m.identifier == k.requested)
355-
.ThenBy(m => m.name)
356-
.ToList(),
357-
Manager.Cache,
358-
ServiceLocator.Container.Resolve<IConfiguration>());
359-
tabController.SetTabLock(true);
360-
var chosen = ChooseProvidedMods.Wait();
361-
// Close the selection prompt
362-
tabController.SetTabLock(false);
363-
if (chosen != null)
364-
{
365-
// User picked a mod, queue it up for installation
366-
toInstall.Add(chosen);
367-
autoInstalled.Add(chosen);
368-
// DON'T return so we can loop around and try the above InstallList call again
369-
tabController.ShowTab(WaitTabPage.Name);
370-
tabController.HideTab(ChooseProvidedModsTabPage.Name);
371-
Util.Invoke(this, () => StatusProgress.Visible = true);
346+
// Now we loop back around again
372347
}
373-
else
348+
catch (TooManyModsProvideKraken k)
374349
{
375-
tabController.HideTab(ChooseProvidedModsTabPage.Name);
376-
e.Result = new InstallResult(false, changes);
377-
throw new CancelledActionKraken();
350+
// Prompt user to choose which mod to use
351+
tabController.ShowTab(ChooseProvidedModsTabPage.Name, 3);
352+
Util.Invoke(this, () => StatusProgress.Visible = false);
353+
var repoData = ServiceLocator.Container.Resolve<RepositoryDataManager>();
354+
ChooseProvidedMods.LoadProviders(
355+
k.Message,
356+
k.modules.OrderByDescending(Manager.Cache.IsCached)
357+
.ThenByDescending(m => repoData.GetDownloadCount(registry.Repositories.Values,
358+
m.identifier)
359+
?? 0)
360+
.ThenByDescending(m => m.identifier == k.requested)
361+
.ThenBy(m => m.name)
362+
.ToList(),
363+
Manager.Cache,
364+
ServiceLocator.Container.Resolve<IConfiguration>());
365+
tabController.SetTabLock(true);
366+
var chosen = ChooseProvidedMods.Wait();
367+
// Close the selection prompt
368+
tabController.SetTabLock(false);
369+
if (chosen != null)
370+
{
371+
// User picked a mod, queue it up for installation
372+
toInstall.Add(chosen);
373+
autoInstalled.Add(chosen);
374+
// DON'T return so we can loop around and try the above InstallList call again
375+
tabController.ShowTab(WaitTabPage.Name);
376+
tabController.HideTab(ChooseProvidedModsTabPage.Name);
377+
Util.Invoke(this, () => StatusProgress.Visible = true);
378+
}
379+
else
380+
{
381+
tabController.HideTab(ChooseProvidedModsTabPage.Name);
382+
e.Result = new InstallResult(false, changes);
383+
throw new CancelledActionKraken();
384+
}
378385
}
379386
}
380387
}

0 commit comments

Comments
 (0)