diff --git a/Wabbajack.Common/FileExtractor.cs b/Wabbajack.Common/FileExtractor.cs index 77e9bd87..48b478b2 100644 --- a/Wabbajack.Common/FileExtractor.cs +++ b/Wabbajack.Common/FileExtractor.cs @@ -48,12 +48,11 @@ namespace Wabbajack.Common else if (source.EndsWith(".exe")) ExtractAllWithInno(source, dest); else - ExtractAllWith7Zip(queue, source, dest); + ExtractAllWith7Zip(source, dest); } catch (Exception ex) { - queue.Log($"Error while extracting {source}"); - throw ex; + Utils.ErrorThrow(ex, $"Error while extracting {source}"); } } @@ -83,7 +82,7 @@ namespace Wabbajack.Common } catch (Exception e) { - Utils.LogToFile($"Error while setting process priority level for innounp.exe\n{e}"); + Utils.Error(e, "Error while setting process priority level for innounp.exe"); } var name = Path.GetFileName(source); @@ -104,7 +103,7 @@ namespace Wabbajack.Common } catch (Exception e) { - Utils.LogToFile($"Error while reading StandardOutput for innounp.exe\n{e}"); + Utils.Error(e, "Error while reading StandardOutput for innounp.exe"); } p.WaitForExit(); @@ -154,14 +153,13 @@ namespace Wabbajack.Common } catch (Exception ex) { - queue.Log($"While Extracting {source}"); - throw ex; + Utils.ErrorThrow(ex, $"While Extracting {source}"); } } - private static void ExtractAllWith7Zip(WorkQueue queue, string source, string dest) + private static void ExtractAllWith7Zip(string source, string dest) { - queue.Log(new GenericInfo($"Extracting {Path.GetFileName(source)}", $"The contents of {source} are being extracted to {dest} using 7zip.exe")); + Utils.Log(new GenericInfo($"Extracting {Path.GetFileName(source)}", $"The contents of {source} are being extracted to {dest} using 7zip.exe")); var info = new ProcessStartInfo { @@ -210,7 +208,7 @@ namespace Wabbajack.Common { return; } - queue.Log(new _7zipReturnError(p.ExitCode, source, dest, p.StandardOutput.ReadToEnd())); + Utils.Log(new _7zipReturnError(p.ExitCode, source, dest, p.StandardOutput.ReadToEnd())); } /// diff --git a/Wabbajack.Common/StatusFeed/AErrorMessage.cs b/Wabbajack.Common/StatusFeed/AErrorMessage.cs index ce1a1349..bcb16e3d 100644 --- a/Wabbajack.Common/StatusFeed/AErrorMessage.cs +++ b/Wabbajack.Common/StatusFeed/AErrorMessage.cs @@ -6,10 +6,11 @@ using System.Threading.Tasks; namespace Wabbajack.Common.StatusFeed { - public abstract class AErrorMessage : Exception, IError + public abstract class AErrorMessage : Exception, IException { public DateTime Timestamp { get; } = DateTime.Now; public abstract string ShortDescription { get; } public abstract string ExtendedDescription { get; } + Exception IException.Exception => this; } } diff --git a/Wabbajack.Common/StatusFeed/Errors/7zipReturnError.cs b/Wabbajack.Common/StatusFeed/Errors/7zipReturnError.cs index cf35f15a..6766a38d 100644 --- a/Wabbajack.Common/StatusFeed/Errors/7zipReturnError.cs +++ b/Wabbajack.Common/StatusFeed/Errors/7zipReturnError.cs @@ -8,25 +8,25 @@ namespace Wabbajack.Common.StatusFeed.Errors { public class _7zipReturnError : AStatusMessage, IError { - private string _destination; - private string _filename; - private int _code; - private string _7zip_output; + public string Destination { get; } + public string Filename; + public int Code; + public string _7zip_output; public override string ShortDescription => $"7Zip returned an error while executing"; public override string ExtendedDescription => - $@"7Zip.exe should always return 0 when it finishes executing. While extracting {_filename} 7Zip encountered some error and -instead returned {_code} which indicates there was an error. The archive might be corrupt or in a format that 7Zip cannot handle. Please verify the file is valid and that you -haven't run out of disk space in the {_destination} folder. + $@"7Zip.exe should always return 0 when it finishes executing. While extracting {Filename} 7Zip encountered some error and +instead returned {Code} which indicates there was an error. The archive might be corrupt or in a format that 7Zip cannot handle. Please verify the file is valid and that you +haven't run out of disk space in the {Destination} folder. 7Zip Output: {_7zip_output}"; public _7zipReturnError(int code, string filename, string destination, string output) { - _code = code; - _filename = filename; - _destination = destination; + Code = code; + Filename = filename; + Destination = destination; _7zip_output = output; } } diff --git a/Wabbajack.Common/StatusFeed/Errors/GenericException.cs b/Wabbajack.Common/StatusFeed/Errors/GenericException.cs new file mode 100644 index 00000000..b091636c --- /dev/null +++ b/Wabbajack.Common/StatusFeed/Errors/GenericException.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wabbajack.Common.StatusFeed.Errors +{ + public class GenericException : IException + { + public string ExtraMessage { get; } + + public DateTime Timestamp { get; } = DateTime.Now; + + public string ShortDescription => ExtraMessage ?? Exception?.Message; + + public string ExtendedDescription => $"{ExtraMessage}: {Exception?.ToString()}"; + + public Exception Exception { get; } + + public GenericException(Exception exception, string extraMessage = null) + { + ExtraMessage = extraMessage; + Exception = exception; + } + } +} diff --git a/Wabbajack.Common/StatusFeed/Errors/UnconvertedError.cs b/Wabbajack.Common/StatusFeed/Errors/UnconvertedError.cs index 0fa64eda..9c82485c 100644 --- a/Wabbajack.Common/StatusFeed/Errors/UnconvertedError.cs +++ b/Wabbajack.Common/StatusFeed/Errors/UnconvertedError.cs @@ -15,7 +15,7 @@ namespace Wabbajack.Common.StatusFeed.Errors _msg = msg; } - public override string ShortDescription { get => _msg; } - public override string ExtendedDescription { get; } = ""; + public override string ShortDescription => _msg; + public override string ExtendedDescription => _msg; } } diff --git a/Wabbajack.Common/StatusFeed/IException.cs b/Wabbajack.Common/StatusFeed/IException.cs new file mode 100644 index 00000000..dcdc63b0 --- /dev/null +++ b/Wabbajack.Common/StatusFeed/IException.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wabbajack.Common.StatusFeed +{ + public interface IException : IError + { + Exception Exception { get; } + } +} diff --git a/Wabbajack.Common/StatusFeed/IUserIntervention.cs b/Wabbajack.Common/StatusFeed/IUserIntervention.cs index d3c253f6..6285fc70 100644 --- a/Wabbajack.Common/StatusFeed/IUserIntervention.cs +++ b/Wabbajack.Common/StatusFeed/IUserIntervention.cs @@ -6,24 +6,6 @@ using System.Threading.Tasks; namespace Wabbajack.Common.StatusFeed { - /// - /// Defines a message that requires user interaction. The user must perform some action - /// or make a choice. - /// - public interface IUserIntervention : IStatusMessage - { - /// - /// The user didn't make a choice, so this action should be aborted - /// - void Cancel(); - - /// - /// The user has provided the required information. - /// - /// - void Resume(T result); - } - /// /// Defines a message that requires user interaction. The user must perform some action /// or make a choice. @@ -34,10 +16,5 @@ namespace Wabbajack.Common.StatusFeed /// The user didn't make a choice, so this action should be aborted /// void Cancel(); - - /// - /// Resume without any further information - /// - void Resume(); } } diff --git a/Wabbajack.Common/Utils.cs b/Wabbajack.Common/Utils.cs index 6df6748b..02bf424e 100644 --- a/Wabbajack.Common/Utils.cs +++ b/Wabbajack.Common/Utils.cs @@ -18,6 +18,7 @@ using IniParser; using Newtonsoft.Json; using ReactiveUI; using Wabbajack.Common.StatusFeed; +using Wabbajack.Common.StatusFeed.Errors; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; using Directory = System.IO.Directory; @@ -63,31 +64,39 @@ namespace Wabbajack.Common public static T Log(T msg) where T : IStatusMessage { - lock (_lock) - { - File.AppendAllText(LogFile, msg + "\r\n"); - } + LogToFile(msg.ShortDescription); LoggerSubj.OnNext(msg); return msg; } - public static void Error(AErrorMessage err) + public static void Error(Exception ex, string extraMessage = null) { - lock (_lock) - { - File.AppendAllText(LogFile, err.ShortDescription + "\r\n"); - } - LoggerSubj.OnNext(err); - throw err; + Log(new GenericException(ex, extraMessage)); } - public static void LogToFile(string msg) + public static void ErrorThrow(Exception ex, string extraMessage = null) + { + Error(ex, extraMessage); + throw ex; + } + + public static void Error(IException err) + { + LogToFile($"{err.ShortDescription}\n{err.Exception.StackTrace}"); + LoggerSubj.OnNext(err); + } + + public static void ErrorThrow(IException err) + { + Error(err); + throw err.Exception; + } + + private static void LogToFile(string msg) { lock (_lock) { - msg = $"{(DateTime.Now - _startTime).TotalSeconds:0.##} - {msg}"; - - File.AppendAllText(LogFile, msg + "\r\n"); + File.AppendAllText(LogFile, $"{(DateTime.Now - _startTime).TotalSeconds:0.##} - {msg}\r\n"); } } @@ -593,11 +602,6 @@ namespace Wabbajack.Common return stream.Result; } - public static string ExceptionToString(this Exception ex) - { - return ex.ToString(); - } - public static IEnumerable DistinctBy(this IEnumerable vs, Func select) { var set = new HashSet(); diff --git a/Wabbajack.Common/Wabbajack.Common.csproj b/Wabbajack.Common/Wabbajack.Common.csproj index 3631d2f0..bf5b61a4 100644 --- a/Wabbajack.Common/Wabbajack.Common.csproj +++ b/Wabbajack.Common/Wabbajack.Common.csproj @@ -112,9 +112,11 @@ + + diff --git a/Wabbajack.Common/WorkQueue.cs b/Wabbajack.Common/WorkQueue.cs index 67a885b5..97a13a14 100644 --- a/Wabbajack.Common/WorkQueue.cs +++ b/Wabbajack.Common/WorkQueue.cs @@ -22,9 +22,6 @@ namespace Wabbajack.Common private readonly Subject _Status = new Subject(); public IObservable Status => _Status; - private static readonly Subject _messages = new Subject(); - public IObservable Messages => _messages; - public static List Threads { get; private set; } public WorkQueue(int threadCount = 0) @@ -32,16 +29,6 @@ namespace Wabbajack.Common StartThreads(threadCount == 0 ? Environment.ProcessorCount : threadCount); } - public void Log(IStatusMessage msg) - { - _messages.OnNext(msg); - } - - public void Log(string msg) - { - _messages.OnNext(new GenericInfo(msg)); - } - private void StartThreads(int threadCount) { ThreadCount = threadCount; diff --git a/Wabbajack.Lib/CompilationSteps/CompilationErrors/InvalidGameESMError.cs b/Wabbajack.Lib/CompilationSteps/CompilationErrors/InvalidGameESMError.cs index 52ebcb3c..7b43ce72 100644 --- a/Wabbajack.Lib/CompilationSteps/CompilationErrors/InvalidGameESMError.cs +++ b/Wabbajack.Lib/CompilationSteps/CompilationErrors/InvalidGameESMError.cs @@ -10,29 +10,29 @@ namespace Wabbajack.Lib.CompilationSteps.CompilationErrors { public class InvalidGameESMError : AErrorMessage { - private readonly string _hash; - private readonly string _path; + public string Hash { get; } + public string PathToFile { get; } private readonly CleanedESM _esm; - private string _gameFileName => Path.GetFileName(_esm.To); + public string GameFileName => Path.GetFileName(_esm.To); public override string ShortDescription { get => - $"Game file {_gameFileName} has a hash of {_hash} which does not match the expected value of {_esm.SourceESMHash}"; + $"Game file {GameFileName} has a hash of {Hash} which does not match the expected value of {_esm.SourceESMHash}"; } public override string ExtendedDescription { get => - $@"This modlist is setup to perform automatic cleaning of the stock game file {_gameFileName} in order to perform this cleaning Wabbajack must first verify that the -source file is in the correct state. It seems that the file in your game directory has a hash of {_hash} instead of the expect hash of {_esm.SourceESMHash}. This could be caused by + $@"This modlist is setup to perform automatic cleaning of the stock game file {GameFileName} in order to perform this cleaning Wabbajack must first verify that the +source file is in the correct state. It seems that the file in your game directory has a hash of {Hash} instead of the expect hash of {_esm.SourceESMHash}. This could be caused by the modlist expecting a different of the game than you currently have installed, or perhaps you have already cleaned the file. You could attempt to fix this error by re-installing the game, and then attempting to re-install this modlist. Also verify that the version of the game you have installed matches the version expected by this modlist."; } public InvalidGameESMError(CleanedESM esm, string hash, string path) { - _hash = hash; - _path = path; + Hash = hash; + PathToFile = path; _esm = esm; } } diff --git a/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs b/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs index d1877a5f..2e00bc31 100644 --- a/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs +++ b/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs @@ -73,7 +73,7 @@ namespace Wabbajack.Lib.CompilationSteps foreach (var match in matches) { if (match is IgnoredDirectly) - Utils.Error(new UnconvertedError($"File required for BSA {source.Path} creation doesn't exist: {match.To}")); + Utils.ErrorThrow(new UnconvertedError($"File required for BSA {source.Path} creation doesn't exist: {match.To}")); _mo2Compiler.ExtraFiles.Add(match); } diff --git a/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs b/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs index 56ee2bcd..dec90f70 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs @@ -42,7 +42,7 @@ namespace Wabbajack.Lib.CompilationSteps } catch (Exception e) { - Utils.LogToFile($"Exception while trying to evolve source to FromSteam\n{e}"); + Utils.Error(e, $"Exception while trying to evolve source to FromSteam"); return null; } } diff --git a/Wabbajack.Lib/Downloaders/HTTPDownloader.cs b/Wabbajack.Lib/Downloaders/HTTPDownloader.cs index 1b3e3518..71c75f34 100644 --- a/Wabbajack.Lib/Downloaders/HTTPDownloader.cs +++ b/Wabbajack.Lib/Downloaders/HTTPDownloader.cs @@ -98,7 +98,7 @@ namespace Wabbajack.Lib.Downloaders if (stream.IsFaulted || response.StatusCode != HttpStatusCode.OK) { - Utils.Log($"While downloading {Url} - {stream.Exception.ExceptionToString()}"); + Utils.Error(stream.Exception, $"While downloading {Url}"); return false; } diff --git a/Wabbajack.Lib/Downloaders/NexusDownloader.cs b/Wabbajack.Lib/Downloaders/NexusDownloader.cs index b17d1ee5..6a754712 100644 --- a/Wabbajack.Lib/Downloaders/NexusDownloader.cs +++ b/Wabbajack.Lib/Downloaders/NexusDownloader.cs @@ -46,12 +46,12 @@ namespace Wabbajack.Lib.Downloaders var status = client.GetUserStatus(); if (!client.IsAuthenticated) { - Utils.Error(new UnconvertedError($"Authenticating for the Nexus failed. A nexus account is required to automatically download mods.")); + Utils.ErrorThrow(new UnconvertedError($"Authenticating for the Nexus failed. A nexus account is required to automatically download mods.")); return; } if (status.is_premium) return; - Utils.Error(new UnconvertedError($"Automated installs with Wabbajack requires a premium nexus account. {client.Username} is not a premium account.")); + Utils.ErrorThrow(new UnconvertedError($"Automated installs with Wabbajack requires a premium nexus account. {client.Username} is not a premium account.")); } public class State : AbstractDownloadState diff --git a/Wabbajack.Lib/MO2Installer.cs b/Wabbajack.Lib/MO2Installer.cs index 5c6f5dc2..26506228 100644 --- a/Wabbajack.Lib/MO2Installer.cs +++ b/Wabbajack.Lib/MO2Installer.cs @@ -140,7 +140,7 @@ namespace Wabbajack.Lib var hash = gameFile.FileHash(); if (hash != esm.SourceESMHash) { - Utils.Error(new InvalidGameESMError(esm, hash, gameFile)); + Utils.ErrorThrow(new InvalidGameESMError(esm, hash, gameFile)); } } } diff --git a/Wabbajack.Lib/StatusMessages/ConfirmUpdateOfExistingInstall.cs b/Wabbajack.Lib/StatusMessages/ConfirmUpdateOfExistingInstall.cs index 4cc00a82..97b51326 100644 --- a/Wabbajack.Lib/StatusMessages/ConfirmUpdateOfExistingInstall.cs +++ b/Wabbajack.Lib/StatusMessages/ConfirmUpdateOfExistingInstall.cs @@ -35,7 +35,7 @@ will be reverted. Are you sure you wish to continue?"; _source.SetResult(Choice.Abort); } - public void Resume() + public void Confirm() { _source.SetResult(Choice.Continue); } diff --git a/Wabbajack.Lib/VortexCompiler.cs b/Wabbajack.Lib/VortexCompiler.cs index 4f3560a1..57ef6212 100644 --- a/Wabbajack.Lib/VortexCompiler.cs +++ b/Wabbajack.Lib/VortexCompiler.cs @@ -238,9 +238,7 @@ namespace Wabbajack.Lib } catch (JsonSerializationException e) { - Info("Failed to parse vortex.deployment.json!"); - Utils.LogToFile(e.Message); - Utils.LogToFile(e.StackTrace); + Utils.Error(e, "Failed to parse vortex.deployment.json!"); } VortexDeployment.files.Do(f => @@ -352,7 +350,7 @@ namespace Wabbajack.Lib } catch (Exception e) { - Utils.LogToFile($"Exception while writing to disk at {filePath}\n{e}"); + Utils.Error(e, $"Exception while writing to disk at {filePath}"); } }); } diff --git a/Wabbajack/View Models/Compilers/MO2CompilerVM.cs b/Wabbajack/View Models/Compilers/MO2CompilerVM.cs index 56f34136..80f006ea 100644 --- a/Wabbajack/View Models/Compilers/MO2CompilerVM.cs +++ b/Wabbajack/View Models/Compilers/MO2CompilerVM.cs @@ -136,7 +136,7 @@ namespace Wabbajack catch (Exception ex) { while (ex.InnerException != null) ex = ex.InnerException; - Utils.Log($"Compiler error: {ex.ExceptionToString()}"); + Utils.Error(ex, $"Compiler error"); return; } @@ -147,7 +147,7 @@ namespace Wabbajack catch (Exception ex) { while (ex.InnerException != null) ex = ex.InnerException; - Utils.Log($"Compiler error: {ex.ExceptionToString()}"); + Utils.Error(ex, $"Compiler error"); } finally { diff --git a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs index ea0e16ec..44d1bcf2 100644 --- a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs +++ b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs @@ -103,7 +103,7 @@ namespace Wabbajack catch (Exception ex) { while (ex.InnerException != null) ex = ex.InnerException; - Utils.Log($"Compiler error: {ex.ExceptionToString()}"); + Utils.Error(ex, $"Compiler error"); return; } await Task.Run(async () => @@ -115,7 +115,7 @@ namespace Wabbajack catch (Exception ex) { while (ex.InnerException != null) ex = ex.InnerException; - Utils.Log($"Compiler error: {ex.ExceptionToString()}"); + Utils.Error(ex, $"Compiler error"); } finally { diff --git a/Wabbajack/View Models/MainWindowVM.cs b/Wabbajack/View Models/MainWindowVM.cs index c1f1af14..89b4be81 100644 --- a/Wabbajack/View Models/MainWindowVM.cs +++ b/Wabbajack/View Models/MainWindowVM.cs @@ -75,7 +75,7 @@ namespace Wabbajack { var result = MessageBox.Show(msg.ExtendedDescription, msg.ShortDescription, MessageBoxButton.OKCancel); if (result == MessageBoxResult.OK) - msg.Resume(); + msg.Confirm(); else msg.Cancel(); } diff --git a/Wabbajack/View Models/ModListVM.cs b/Wabbajack/View Models/ModListVM.cs index 0b155379..814c2597 100644 --- a/Wabbajack/View Models/ModListVM.cs +++ b/Wabbajack/View Models/ModListVM.cs @@ -61,7 +61,7 @@ namespace Wabbajack } catch (Exception ex) { - Utils.LogToFile($"Exception while caching Mod List image {Name}\n{ex.ExceptionToString()}"); + Utils.Error(ex, $"Exception while caching Mod List image {Name}"); return default(MemoryStream); } }) @@ -80,7 +80,7 @@ namespace Wabbajack } catch (Exception ex) { - Utils.LogToFile($"Exception while caching Mod List image {Name}\n{ex.ExceptionToString()}"); + Utils.Error(ex, $"Exception while caching Mod List image {Name}"); return default(BitmapImage); } }) diff --git a/Wabbajack/View Models/ModVM.cs b/Wabbajack/View Models/ModVM.cs index b280831f..3b37ee75 100644 --- a/Wabbajack/View Models/ModVM.cs +++ b/Wabbajack/View Models/ModVM.cs @@ -59,7 +59,7 @@ namespace Wabbajack } catch (Exception ex) { - Utils.LogToFile($"Exception while caching slide {ModName} ({ModID})\n{ex.ExceptionToString()}"); + Utils.Error(ex, $"Exception while caching slide {ModName} ({ModID})"); return default(MemoryStream); } }) @@ -79,7 +79,7 @@ namespace Wabbajack } catch (Exception ex) { - Utils.LogToFile($"Exception while caching slide {ModName} ({ModID})\n{ex.ExceptionToString()}"); + Utils.Error(ex, $"Exception while caching slide {ModName} ({ModID})"); return default(BitmapImage); } finally diff --git a/Wabbajack/Views/MainWindow.xaml.cs b/Wabbajack/Views/MainWindow.xaml.cs index dd58971f..734f1b85 100644 --- a/Wabbajack/Views/MainWindow.xaml.cs +++ b/Wabbajack/Views/MainWindow.xaml.cs @@ -23,8 +23,7 @@ namespace Wabbajack AppDomain.CurrentDomain.UnhandledException += (sender, e) => { // Don't do any special logging side effects - Wabbajack.Common.Utils.Log("Uncaught error:"); - Wabbajack.Common.Utils.Log(((Exception)e.ExceptionObject).ExceptionToString()); + Wabbajack.Common.Utils.Error(((Exception)e.ExceptionObject), "Uncaught error"); }; var appPath = System.Reflection.Assembly.GetExecutingAssembly().Location;