diff --git a/src/NexusMods.App.UI/Controls/Spine/SpineViewModel.cs b/src/NexusMods.App.UI/Controls/Spine/SpineViewModel.cs index 1d799a2244..ca21302ac7 100644 --- a/src/NexusMods.App.UI/Controls/Spine/SpineViewModel.cs +++ b/src/NexusMods.App.UI/Controls/Spine/SpineViewModel.cs @@ -75,6 +75,7 @@ public SpineViewModel(ILogger logger, this.WhenActivated(disposables => { router.Messages + .OnUI() .SubscribeWithErrorLogging(logger, HandleMessage) .DisposeWith(disposables); diff --git a/src/NexusMods.App.UI/RightContent/FoundGamesViewModel.cs b/src/NexusMods.App.UI/RightContent/FoundGamesViewModel.cs index a166ef5516..ec91a96c76 100644 --- a/src/NexusMods.App.UI/RightContent/FoundGamesViewModel.cs +++ b/src/NexusMods.App.UI/RightContent/FoundGamesViewModel.cs @@ -52,10 +52,7 @@ public void InitializeFromFound(IEnumerable games) vm.Installation = install; vm.PrimaryButton = ReactiveCommand.CreateFromTask(async () => { - await Task.Run(async () => - { - await ManageGame(install); - }); + await Task.Run(async () => await ManageGame(install)); }); return vm; }); diff --git a/src/NexusMods.DataModel/LoadoutSynchronizer/ALoadoutSynchronizer.cs b/src/NexusMods.DataModel/LoadoutSynchronizer/ALoadoutSynchronizer.cs index c4d8f375b6..fb7d885ebc 100644 --- a/src/NexusMods.DataModel/LoadoutSynchronizer/ALoadoutSynchronizer.cs +++ b/src/NexusMods.DataModel/LoadoutSynchronizer/ALoadoutSynchronizer.cs @@ -8,6 +8,7 @@ using NexusMods.DataModel.Loadouts.LoadoutSynchronizerDTOs; using NexusMods.DataModel.Loadouts.ModFiles; using NexusMods.DataModel.Loadouts.Mods; +using NexusMods.DataModel.LoadoutSynchronizer.Exceptions; using NexusMods.DataModel.Sorting; using NexusMods.DataModel.Sorting.Rules; using NexusMods.FileExtractor.StreamFactories; @@ -252,7 +253,7 @@ public virtual async Task GetDiskState(GameInstallation installation) /// public virtual void HandleNeedIngest(HashedEntry entry) { - throw new Exception("File changed during apply, need to ingest"); + throw new NeedsIngestException(); } /// diff --git a/src/NexusMods.DataModel/LoadoutSynchronizer/Exceptions/NeedsIngestException.cs b/src/NexusMods.DataModel/LoadoutSynchronizer/Exceptions/NeedsIngestException.cs new file mode 100644 index 0000000000..d17675b281 --- /dev/null +++ b/src/NexusMods.DataModel/LoadoutSynchronizer/Exceptions/NeedsIngestException.cs @@ -0,0 +1,16 @@ +namespace NexusMods.DataModel.LoadoutSynchronizer.Exceptions; + +/// +/// Thrown when there are changes in the game folder that need to be ingested before a loadout can be applied +/// +public class NeedsIngestException : Exception +{ + /// + /// Thrown when a loadout needs to be ingested before it can be applied + /// + public NeedsIngestException() : base("Loadout needs to be ingested before it can be applied") + { + + } + +} diff --git a/src/NexusMods.DataModel/ToolManager.cs b/src/NexusMods.DataModel/ToolManager.cs index c1aa7bfa1b..7c8167370e 100644 --- a/src/NexusMods.DataModel/ToolManager.cs +++ b/src/NexusMods.DataModel/ToolManager.cs @@ -1,8 +1,10 @@ -using NexusMods.DataModel.Abstractions; +using Microsoft.Extensions.Logging; +using NexusMods.DataModel.Abstractions; using NexusMods.DataModel.Games; using NexusMods.DataModel.Loadouts; using NexusMods.DataModel.Loadouts.Extensions; using NexusMods.DataModel.Loadouts.Mods; +using NexusMods.DataModel.LoadoutSynchronizer.Exceptions; namespace NexusMods.DataModel; @@ -14,6 +16,7 @@ public class ToolManager : IToolManager private readonly ILookup _tools; private readonly IDataStore _dataStore; private readonly LoadoutRegistry _loadoutRegistry; + private readonly ILogger _logger; /// /// DI Constructor @@ -22,8 +25,9 @@ public class ToolManager : IToolManager /// /// /// - public ToolManager(IEnumerable tools, IDataStore dataStore, LoadoutRegistry loadoutRegistry) + public ToolManager(ILogger logger, IEnumerable tools, IDataStore dataStore, LoadoutRegistry loadoutRegistry) { + _logger = logger; _dataStore = dataStore; _tools = tools.SelectMany(tool => tool.Domains.Select(domain => (domain, tool))) .ToLookup(t => t.domain, t => t.tool); @@ -43,10 +47,23 @@ public async Task RunTool(ITool tool, Loadout loadout, ModId? generated if (!tool.Domains.Contains(loadout.Installation.Game.Domain)) throw new Exception("Tool does not support this game"); - await loadout.Apply(); + _logger.LogInformation("Applying loadout {LoadoutId} to {GameName} {GameVersion}", loadout.LoadoutId, loadout.Installation.Game.Name, loadout.Installation.Version); + try + { + await loadout.Apply(); + } + catch (NeedsIngestException) + { + _logger.LogInformation("Ingesting loadout {LoadoutId} from {GameName} {GameVersion}", loadout.LoadoutId, loadout.Installation.Game.Name, loadout.Installation.Version); + await loadout.Ingest(); + _logger.LogInformation("Applying loadout {LoadoutId} to {GameName} {GameVersion}", loadout.LoadoutId, loadout.Installation.Game.Name, loadout.Installation.Version); + await loadout.Apply(); + } + _logger.LogInformation("Running tool {ToolName} for loadout {LoadoutId} on {GameName} {GameVersion}", tool.Name, loadout.LoadoutId, loadout.Installation.Game.Name, loadout.Installation.Version); await tool.Execute(loadout, token); + _logger.LogInformation("Ingesting loadout {LoadoutId} from {GameName} {GameVersion}", loadout.LoadoutId, loadout.Installation.Game.Name, loadout.Installation.Version); return await loadout.Ingest(); } }