Merge pull request #238 from wabbajack-tools/exceptions-as-data

Exceptions as data
This commit is contained in:
Timothy Baldridge 2019-12-05 22:27:59 -07:00 committed by GitHub
commit 822236de8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 115 additions and 109 deletions

View File

@ -48,12 +48,11 @@ namespace Wabbajack.Common
else if (source.EndsWith(".exe")) else if (source.EndsWith(".exe"))
ExtractAllWithInno(source, dest); ExtractAllWithInno(source, dest);
else else
ExtractAllWith7Zip(queue, source, dest); ExtractAllWith7Zip(source, dest);
} }
catch (Exception ex) catch (Exception ex)
{ {
queue.Log($"Error while extracting {source}"); Utils.ErrorThrow(ex, $"Error while extracting {source}");
throw ex;
} }
} }
@ -83,7 +82,7 @@ namespace Wabbajack.Common
} }
catch (Exception e) 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); var name = Path.GetFileName(source);
@ -104,7 +103,7 @@ namespace Wabbajack.Common
} }
catch (Exception e) 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(); p.WaitForExit();
@ -154,14 +153,13 @@ namespace Wabbajack.Common
} }
catch (Exception ex) catch (Exception ex)
{ {
queue.Log($"While Extracting {source}"); Utils.ErrorThrow(ex, $"While Extracting {source}");
throw ex;
} }
} }
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 var info = new ProcessStartInfo
{ {
@ -210,7 +208,7 @@ namespace Wabbajack.Common
{ {
return; return;
} }
queue.Log(new _7zipReturnError(p.ExitCode, source, dest, p.StandardOutput.ReadToEnd())); Utils.Log(new _7zipReturnError(p.ExitCode, source, dest, p.StandardOutput.ReadToEnd()));
} }
/// <summary> /// <summary>

View File

@ -6,10 +6,11 @@ using System.Threading.Tasks;
namespace Wabbajack.Common.StatusFeed namespace Wabbajack.Common.StatusFeed
{ {
public abstract class AErrorMessage : Exception, IError public abstract class AErrorMessage : Exception, IException
{ {
public DateTime Timestamp { get; } = DateTime.Now; public DateTime Timestamp { get; } = DateTime.Now;
public abstract string ShortDescription { get; } public abstract string ShortDescription { get; }
public abstract string ExtendedDescription { get; } public abstract string ExtendedDescription { get; }
Exception IException.Exception => this;
} }
} }

View File

@ -8,25 +8,25 @@ namespace Wabbajack.Common.StatusFeed.Errors
{ {
public class _7zipReturnError : AStatusMessage, IError public class _7zipReturnError : AStatusMessage, IError
{ {
private string _destination; public string Destination { get; }
private string _filename; public string Filename;
private int _code; public int Code;
private string _7zip_output; public string _7zip_output;
public override string ShortDescription => $"7Zip returned an error while executing"; public override string ShortDescription => $"7Zip returned an error while executing";
public override string ExtendedDescription => public override string ExtendedDescription =>
$@"7Zip.exe should always return 0 when it finishes executing. While extracting {_filename} 7Zip encountered some error and $@"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 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. haven't run out of disk space in the {Destination} folder.
7Zip Output: 7Zip Output:
{_7zip_output}"; {_7zip_output}";
public _7zipReturnError(int code, string filename, string destination, string output) public _7zipReturnError(int code, string filename, string destination, string output)
{ {
_code = code; Code = code;
_filename = filename; Filename = filename;
_destination = destination; Destination = destination;
_7zip_output = output; _7zip_output = output;
} }
} }

View File

@ -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;
}
}
}

View File

@ -15,7 +15,7 @@ namespace Wabbajack.Common.StatusFeed.Errors
_msg = msg; _msg = msg;
} }
public override string ShortDescription { get => _msg; } public override string ShortDescription => _msg;
public override string ExtendedDescription { get; } = ""; public override string ExtendedDescription => _msg;
} }
} }

View File

@ -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; }
}
}

View File

@ -6,24 +6,6 @@ using System.Threading.Tasks;
namespace Wabbajack.Common.StatusFeed namespace Wabbajack.Common.StatusFeed
{ {
/// <summary>
/// Defines a message that requires user interaction. The user must perform some action
/// or make a choice.
/// </summary>
public interface IUserIntervention<T> : IStatusMessage
{
/// <summary>
/// The user didn't make a choice, so this action should be aborted
/// </summary>
void Cancel();
/// <summary>
/// The user has provided the required information.
/// </summary>
/// <param name="result"></param>
void Resume(T result);
}
/// <summary> /// <summary>
/// Defines a message that requires user interaction. The user must perform some action /// Defines a message that requires user interaction. The user must perform some action
/// or make a choice. /// 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 /// The user didn't make a choice, so this action should be aborted
/// </summary> /// </summary>
void Cancel(); void Cancel();
/// <summary>
/// Resume without any further information
/// </summary>
void Resume();
} }
} }

View File

@ -18,6 +18,7 @@ using IniParser;
using Newtonsoft.Json; using Newtonsoft.Json;
using ReactiveUI; using ReactiveUI;
using Wabbajack.Common.StatusFeed; using Wabbajack.Common.StatusFeed;
using Wabbajack.Common.StatusFeed.Errors;
using YamlDotNet.Serialization; using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NamingConventions;
using Directory = System.IO.Directory; using Directory = System.IO.Directory;
@ -63,31 +64,39 @@ namespace Wabbajack.Common
public static T Log<T>(T msg) where T : IStatusMessage public static T Log<T>(T msg) where T : IStatusMessage
{ {
lock (_lock) LogToFile(msg.ShortDescription);
{
File.AppendAllText(LogFile, msg + "\r\n");
}
LoggerSubj.OnNext(msg); LoggerSubj.OnNext(msg);
return msg; return msg;
} }
public static void Error(AErrorMessage err) public static void Error(Exception ex, string extraMessage = null)
{ {
lock (_lock) Log(new GenericException(ex, extraMessage));
{
File.AppendAllText(LogFile, err.ShortDescription + "\r\n");
}
LoggerSubj.OnNext(err);
throw err;
} }
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) lock (_lock)
{ {
msg = $"{(DateTime.Now - _startTime).TotalSeconds:0.##} - {msg}"; File.AppendAllText(LogFile, $"{(DateTime.Now - _startTime).TotalSeconds:0.##} - {msg}\r\n");
File.AppendAllText(LogFile, msg + "\r\n");
} }
} }
@ -593,11 +602,6 @@ namespace Wabbajack.Common
return stream.Result; return stream.Result;
} }
public static string ExceptionToString(this Exception ex)
{
return ex.ToString();
}
public static IEnumerable<T> DistinctBy<T, V>(this IEnumerable<T> vs, Func<T, V> select) public static IEnumerable<T> DistinctBy<T, V>(this IEnumerable<T> vs, Func<T, V> select)
{ {
var set = new HashSet<V>(); var set = new HashSet<V>();

View File

@ -112,9 +112,11 @@
<Compile Include="StatusFeed\AStatusMessage.cs" /> <Compile Include="StatusFeed\AStatusMessage.cs" />
<Compile Include="StatusFeed\Errors\7zipReturnError.cs" /> <Compile Include="StatusFeed\Errors\7zipReturnError.cs" />
<Compile Include="StatusFeed\Errors\FileExtractionError.cs" /> <Compile Include="StatusFeed\Errors\FileExtractionError.cs" />
<Compile Include="StatusFeed\Errors\GenericException.cs" />
<Compile Include="StatusFeed\Errors\UnconvertedError.cs" /> <Compile Include="StatusFeed\Errors\UnconvertedError.cs" />
<Compile Include="StatusFeed\GenericInfo.cs" /> <Compile Include="StatusFeed\GenericInfo.cs" />
<Compile Include="StatusFeed\IError.cs" /> <Compile Include="StatusFeed\IError.cs" />
<Compile Include="StatusFeed\IException.cs" />
<Compile Include="StatusFeed\IInfo.cs" /> <Compile Include="StatusFeed\IInfo.cs" />
<Compile Include="StatusFeed\IStatusMessage.cs" /> <Compile Include="StatusFeed\IStatusMessage.cs" />
<Compile Include="StatusFeed\IUserIntervention.cs" /> <Compile Include="StatusFeed\IUserIntervention.cs" />

View File

@ -22,9 +22,6 @@ namespace Wabbajack.Common
private readonly Subject<CPUStatus> _Status = new Subject<CPUStatus>(); private readonly Subject<CPUStatus> _Status = new Subject<CPUStatus>();
public IObservable<CPUStatus> Status => _Status; public IObservable<CPUStatus> Status => _Status;
private static readonly Subject<IStatusMessage> _messages = new Subject<IStatusMessage>();
public IObservable<IStatusMessage> Messages => _messages;
public static List<Thread> Threads { get; private set; } public static List<Thread> Threads { get; private set; }
public WorkQueue(int threadCount = 0) public WorkQueue(int threadCount = 0)
@ -32,16 +29,6 @@ namespace Wabbajack.Common
StartThreads(threadCount == 0 ? Environment.ProcessorCount : threadCount); 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) private void StartThreads(int threadCount)
{ {
ThreadCount = threadCount; ThreadCount = threadCount;

View File

@ -10,29 +10,29 @@ namespace Wabbajack.Lib.CompilationSteps.CompilationErrors
{ {
public class InvalidGameESMError : AErrorMessage public class InvalidGameESMError : AErrorMessage
{ {
private readonly string _hash; public string Hash { get; }
private readonly string _path; public string PathToFile { get; }
private readonly CleanedESM _esm; private readonly CleanedESM _esm;
private string _gameFileName => Path.GetFileName(_esm.To); public string GameFileName => Path.GetFileName(_esm.To);
public override string ShortDescription public override string ShortDescription
{ {
get => 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 public override string ExtendedDescription
{ {
get => 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 $@"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 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 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."; 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) public InvalidGameESMError(CleanedESM esm, string hash, string path)
{ {
_hash = hash; Hash = hash;
_path = path; PathToFile = path;
_esm = esm; _esm = esm;
} }
} }

View File

@ -73,7 +73,7 @@ namespace Wabbajack.Lib.CompilationSteps
foreach (var match in matches) foreach (var match in matches)
{ {
if (match is IgnoredDirectly) 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); _mo2Compiler.ExtraFiles.Add(match);
} }

View File

@ -42,7 +42,7 @@ namespace Wabbajack.Lib.CompilationSteps
} }
catch (Exception e) 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; return null;
} }
} }

View File

@ -98,7 +98,7 @@ namespace Wabbajack.Lib.Downloaders
if (stream.IsFaulted || response.StatusCode != HttpStatusCode.OK) if (stream.IsFaulted || response.StatusCode != HttpStatusCode.OK)
{ {
Utils.Log($"While downloading {Url} - {stream.Exception.ExceptionToString()}"); Utils.Error(stream.Exception, $"While downloading {Url}");
return false; return false;
} }

View File

@ -46,12 +46,12 @@ namespace Wabbajack.Lib.Downloaders
var status = client.GetUserStatus(); var status = client.GetUserStatus();
if (!client.IsAuthenticated) 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; return;
} }
if (status.is_premium) 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 public class State : AbstractDownloadState

View File

@ -140,7 +140,7 @@ namespace Wabbajack.Lib
var hash = gameFile.FileHash(); var hash = gameFile.FileHash();
if (hash != esm.SourceESMHash) if (hash != esm.SourceESMHash)
{ {
Utils.Error(new InvalidGameESMError(esm, hash, gameFile)); Utils.ErrorThrow(new InvalidGameESMError(esm, hash, gameFile));
} }
} }
} }

View File

@ -35,7 +35,7 @@ will be reverted. Are you sure you wish to continue?";
_source.SetResult(Choice.Abort); _source.SetResult(Choice.Abort);
} }
public void Resume() public void Confirm()
{ {
_source.SetResult(Choice.Continue); _source.SetResult(Choice.Continue);
} }

View File

@ -273,9 +273,7 @@ namespace Wabbajack.Lib
} }
catch (JsonSerializationException e) catch (JsonSerializationException e)
{ {
Info("Failed to parse vortex.deployment.json!"); Utils.Error(e, "Failed to parse vortex.deployment.json!");
Utils.LogToFile(e.Message);
Utils.LogToFile(e.StackTrace);
} }
VortexDeployment.files.Do(f => VortexDeployment.files.Do(f =>
@ -408,7 +406,7 @@ namespace Wabbajack.Lib
} }
catch (Exception e) catch (Exception e)
{ {
Utils.LogToFile($"Exception while writing to disk at {filePath}\n{e}"); Utils.Error(e, $"Exception while writing to disk at {filePath}");
} }
}); });
} }

View File

@ -136,7 +136,7 @@ namespace Wabbajack
catch (Exception ex) catch (Exception ex)
{ {
while (ex.InnerException != null) ex = ex.InnerException; while (ex.InnerException != null) ex = ex.InnerException;
Utils.Log($"Compiler error: {ex.ExceptionToString()}"); Utils.Error(ex, $"Compiler error");
return; return;
} }
@ -147,7 +147,7 @@ namespace Wabbajack
catch (Exception ex) catch (Exception ex)
{ {
while (ex.InnerException != null) ex = ex.InnerException; while (ex.InnerException != null) ex = ex.InnerException;
Utils.Log($"Compiler error: {ex.ExceptionToString()}"); Utils.Error(ex, $"Compiler error");
} }
finally finally
{ {

View File

@ -103,7 +103,7 @@ namespace Wabbajack
catch (Exception ex) catch (Exception ex)
{ {
while (ex.InnerException != null) ex = ex.InnerException; while (ex.InnerException != null) ex = ex.InnerException;
Utils.Log($"Compiler error: {ex.ExceptionToString()}"); Utils.Error(ex, $"Compiler error");
return; return;
} }
await Task.Run(async () => await Task.Run(async () =>
@ -115,7 +115,7 @@ namespace Wabbajack
catch (Exception ex) catch (Exception ex)
{ {
while (ex.InnerException != null) ex = ex.InnerException; while (ex.InnerException != null) ex = ex.InnerException;
Utils.Log($"Compiler error: {ex.ExceptionToString()}"); Utils.Error(ex, $"Compiler error");
} }
finally finally
{ {

View File

@ -75,7 +75,7 @@ namespace Wabbajack
{ {
var result = MessageBox.Show(msg.ExtendedDescription, msg.ShortDescription, MessageBoxButton.OKCancel); var result = MessageBox.Show(msg.ExtendedDescription, msg.ShortDescription, MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK) if (result == MessageBoxResult.OK)
msg.Resume(); msg.Confirm();
else else
msg.Cancel(); msg.Cancel();
} }

View File

@ -61,7 +61,7 @@ namespace Wabbajack
} }
catch (Exception ex) 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); return default(MemoryStream);
} }
}) })
@ -80,7 +80,7 @@ namespace Wabbajack
} }
catch (Exception ex) 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); return default(BitmapImage);
} }
}) })

View File

@ -59,7 +59,7 @@ namespace Wabbajack
} }
catch (Exception ex) 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); return default(MemoryStream);
} }
}) })
@ -79,7 +79,7 @@ namespace Wabbajack
} }
catch (Exception ex) 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); return default(BitmapImage);
} }
finally finally

View File

@ -23,8 +23,7 @@ namespace Wabbajack
AppDomain.CurrentDomain.UnhandledException += (sender, e) => AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{ {
// Don't do any special logging side effects // Don't do any special logging side effects
Wabbajack.Common.Utils.Log("Uncaught error:"); Wabbajack.Common.Utils.Error(((Exception)e.ExceptionObject), "Uncaught error");
Wabbajack.Common.Utils.Log(((Exception)e.ExceptionObject).ExceptionToString());
}; };
var appPath = System.Reflection.Assembly.GetExecutingAssembly().Location; var appPath = System.Reflection.Assembly.GetExecutingAssembly().Location;