Extend logging with a new state (fixes #944)

This commit is contained in:
Matt Nadareski
2026-02-02 16:23:48 -05:00
parent 3f61957715
commit 8f6305a7c4
11 changed files with 97 additions and 40 deletions

View File

@@ -235,7 +235,7 @@ namespace MPF.CLI.Features
Console.WriteLine($"Invoking {Options.InternalProgram} using '{paramStr}'");
var dumpResult = env.Run(MediaType).GetAwaiter().GetResult();
Console.WriteLine(dumpResult.Message);
if (!dumpResult)
if (dumpResult == false)
return false;
// If it was not a dumping command

View File

@@ -4,6 +4,23 @@ namespace MPF.Frontend.Test
{
public class ResultEventArgsTests
{
[Fact]
public void EmptyNeutralTest()
{
var actual = ResultEventArgs.Neutral();
Assert.Null((bool?)actual);
Assert.Empty(actual.Message);
}
[Fact]
public void CustomMessageNeutralTest()
{
string message = "Success!";
var actual = ResultEventArgs.Neutral(message);
Assert.Null((bool?)actual);
Assert.Equal(message, actual.Message);
}
[Fact]
public void EmptySuccessTest()
{

View File

@@ -10,7 +10,14 @@ namespace MPF.Frontend
/// </summary>
public static void ProgressUpdated(object? sender, ResultEventArgs value)
{
Console.WriteLine(value.Message);
string prefix = (bool?)value switch
{
true => "SUCCESS: ",
false => "FAILURE: ",
_ => "",
};
Console.WriteLine($"{prefix}{value.Message}");
}
/// <summary>

View File

@@ -455,11 +455,11 @@ namespace MPF.Frontend
// Check that we have the basics for dumping
ResultEventArgs result = IsValidForDump(mediaType);
if (!result)
if (result == false)
return result;
// Execute internal tool
progress?.Report(ResultEventArgs.Success($"Executing {_internalProgram}... please wait!"));
progress?.Report(ResultEventArgs.Neutral($"Executing {_internalProgram}... please wait!"));
var directoryName = Path.GetDirectoryName(OutputPath);
if (!string.IsNullOrEmpty(directoryName))
@@ -507,7 +507,7 @@ namespace MPF.Frontend
protectionProgress = temp;
}
resultProgress.Report(ResultEventArgs.Success("Gathering submission information... please wait!"));
resultProgress.Report(ResultEventArgs.Neutral("Gathering submission information... please wait!"));
// Get the output directory and filename separately
var outputDirectory = Path.GetDirectoryName(OutputPath);
@@ -530,7 +530,7 @@ namespace MPF.Frontend
return ResultEventArgs.Failure("Could not determine the media type from output files...");
// Extract the information from the output files
resultProgress.Report(ResultEventArgs.Success("Extracting output information from output files..."));
resultProgress.Report(ResultEventArgs.Neutral("Extracting output information from output files..."));
var submissionInfo = await SubmissionGenerator.ExtractOutputInformation(
OutputPath,
_drive,
@@ -548,7 +548,7 @@ namespace MPF.Frontend
// Inject seed submission info data, if necessary
if (seedInfo is not null)
{
resultProgress.Report(ResultEventArgs.Success("Injecting user-supplied information..."));
resultProgress.Report(ResultEventArgs.Neutral("Injecting user-supplied information..."));
submissionInfo = Builder.InjectSubmissionInformation(submissionInfo, seedInfo);
resultProgress.Report(ResultEventArgs.Success("Information injection complete!"));
}
@@ -556,7 +556,7 @@ namespace MPF.Frontend
// Get user-modifiable information if configured to
if (_options.PromptForDiscInformation && processUserInfo is not null)
{
resultProgress.Report(ResultEventArgs.Success("Waiting for additional media information..."));
resultProgress.Report(ResultEventArgs.Neutral("Waiting for additional media information..."));
bool? filledInfo = processUserInfo.Invoke(_options, ref submissionInfo);
if (filledInfo == true)
resultProgress.Report(ResultEventArgs.Success("Additional media information added!"));
@@ -565,12 +565,12 @@ namespace MPF.Frontend
}
// Process special fields for site codes
resultProgress.Report(ResultEventArgs.Success("Processing site codes..."));
resultProgress.Report(ResultEventArgs.Neutral("Processing site codes..."));
Formatter.ProcessSpecialFields(submissionInfo!);
resultProgress.Report(ResultEventArgs.Success("Processing complete!"));
// Format the information for the text output
resultProgress.Report(ResultEventArgs.Success("Formatting information..."));
resultProgress.Report(ResultEventArgs.Neutral("Formatting information..."));
var formattedValues = Formatter.FormatOutputData(submissionInfo, _options.EnableRedumpCompatibility, out string? formatResult);
if (formattedValues is null)
resultProgress.Report(ResultEventArgs.Failure(formatResult));
@@ -581,7 +581,7 @@ namespace MPF.Frontend
var filenameSuffix = _options.AddFilenameSuffix ? Path.GetFileNameWithoutExtension(outputFilename) : null;
// Write the text output
resultProgress.Report(ResultEventArgs.Success("Writing submission information file..."));
resultProgress.Report(ResultEventArgs.Neutral("Writing submission information file..."));
bool txtSuccess = WriteOutputData(outputDirectory, filenameSuffix, formattedValues, out string txtResult);
if (txtSuccess)
resultProgress.Report(ResultEventArgs.Success(txtResult));
@@ -593,7 +593,7 @@ namespace MPF.Frontend
{
if (_options.ScanForProtection)
{
resultProgress.Report(ResultEventArgs.Success("Writing protection information file..."));
resultProgress.Report(ResultEventArgs.Neutral("Writing protection information file..."));
bool scanSuccess = WriteProtectionData(outputDirectory, filenameSuffix, submissionInfo, _options.HideDriveLetters);
if (scanSuccess)
resultProgress.Report(ResultEventArgs.Success("Writing complete!"));
@@ -605,7 +605,7 @@ namespace MPF.Frontend
// Write the JSON output, if required
if (_options.OutputSubmissionJSON)
{
resultProgress.Report(ResultEventArgs.Success($"Writing submission information JSON file{(_options.IncludeArtifacts ? " with artifacts" : string.Empty)}..."));
resultProgress.Report(ResultEventArgs.Neutral($"Writing submission information JSON file{(_options.IncludeArtifacts ? " with artifacts" : string.Empty)}..."));
bool jsonSuccess = WriteOutputData(outputDirectory, filenameSuffix, submissionInfo, _options.IncludeArtifacts);
if (jsonSuccess)
resultProgress.Report(ResultEventArgs.Success("Writing complete!"));
@@ -616,7 +616,7 @@ namespace MPF.Frontend
// Compress the logs, if required
if (_options.CompressLogFiles)
{
resultProgress.Report(ResultEventArgs.Success("Compressing log files..."));
resultProgress.Report(ResultEventArgs.Neutral("Compressing log files..."));
#if NET40
await Task.Factory.StartNew(() =>
#else
@@ -636,7 +636,7 @@ namespace MPF.Frontend
// Delete unnecessary files, if required
if (_options.DeleteUnnecessaryFiles)
{
resultProgress.Report(ResultEventArgs.Success("Deleting unnecessary files..."));
resultProgress.Report(ResultEventArgs.Neutral("Deleting unnecessary files..."));
bool deleteSuccess = _processor.DeleteUnnecessaryFiles(mediaType, outputDirectory, outputFilename, out string deleteResult);
if (deleteSuccess)
resultProgress.Report(ResultEventArgs.Success(deleteResult));
@@ -647,7 +647,7 @@ namespace MPF.Frontend
// Create PS3 IRD, if required
if (_options.CreateIRDAfterDumping && _system == RedumpSystem.SonyPlayStation3 && mediaType == MediaType.BluRay)
{
resultProgress.Report(ResultEventArgs.Success("Creating IRD... please wait!"));
resultProgress.Report(ResultEventArgs.Neutral("Creating IRD... please wait!"));
bool deleteSuccess = await IRDTool.WriteIRD(OutputPath, submissionInfo?.Extras?.DiscKey, submissionInfo?.Extras?.DiscID, submissionInfo?.Extras?.PIC, submissionInfo?.SizeAndChecksums.Layerbreak, submissionInfo?.SizeAndChecksums.CRC32);
if (deleteSuccess)
resultProgress.Report(ResultEventArgs.Success("IRD created!"));

View File

@@ -63,7 +63,8 @@ namespace MPF.Frontend
/// </summary>
public enum LogLevel
{
USER,
USER_GENERIC,
USER_SUCCESS,
VERBOSE,
ERROR,
SECRET,

View File

@@ -10,19 +10,30 @@ namespace MPF.Frontend
/// <summary>
/// Internal representation of success
/// </summary>
private readonly bool _success;
private readonly bool? _success;
/// <summary>
/// Optional message for the result
/// </summary>
public string Message { get; }
private ResultEventArgs(bool success, string message)
private ResultEventArgs(bool? success, string message)
{
_success = success;
Message = message;
}
/// <summary>
/// Create a default neutral result with no message
/// </summary>
public static ResultEventArgs Neutral() => new(null, string.Empty);
/// <summary>
/// Create a neutral result with a custom message
/// </summary>
/// <param name="message">String to add as a message</param>
public static ResultEventArgs Neutral(string? message) => new(null, message ?? string.Empty);
/// <summary>
/// Create a default success result with no message
/// </summary>
@@ -49,7 +60,7 @@ namespace MPF.Frontend
/// <summary>
/// Results can be compared to boolean values based on the success value
/// </summary>
public static implicit operator bool(ResultEventArgs result) => result._success;
public static implicit operator bool?(ResultEventArgs result) => result._success;
/// <summary>
/// Results can be compared to boolean values based on the success value

View File

@@ -121,7 +121,7 @@ namespace MPF.Frontend.Tools
// Run anti-modchip check, if necessary
if (drive is not null && system.SupportsAntiModchipScans() && info.CopyProtection.AntiModchip == YesNo.NULL)
{
resultProgress?.Report(ResultEventArgs.Success("Checking for anti-modchip strings... this might take a while!"));
resultProgress?.Report(ResultEventArgs.Neutral("Checking for anti-modchip strings... this might take a while!"));
info.CopyProtection.AntiModchip = await ProtectionTool.GetPlayStationAntiModchipDetected(drive?.Name) ? YesNo.Yes : YesNo.No;
resultProgress?.Report(ResultEventArgs.Success("Anti-modchip string scan complete!"));
}
@@ -129,7 +129,7 @@ namespace MPF.Frontend.Tools
// Run copy protection, if possible or necessary
if (system.SupportsCopyProtectionScans())
{
resultProgress?.Report(ResultEventArgs.Success("Running copy protection scan... this might take a while!"));
resultProgress?.Report(ResultEventArgs.Neutral("Running copy protection scan... this might take a while!"));
try
{
@@ -210,7 +210,7 @@ namespace MPF.Frontend.Tools
List<int[]> foundIdSets = [];
// Loop through all of the hashdata to find matching IDs
resultProgress?.Report(ResultEventArgs.Success("Finding disc matches on Redump..."));
resultProgress?.Report(ResultEventArgs.Neutral("Finding disc matches on Redump..."));
var splitData = info.TracksAndWriteOffsets.ClrMameProData?.TrimEnd('\n')?.Split('\n');
int trackCount = splitData?.Length ?? 0;
foreach (string hashData in splitData ?? [])
@@ -219,7 +219,7 @@ namespace MPF.Frontend.Tools
if (string.IsNullOrEmpty(hashData))
{
trackCount--;
resultProgress?.Report(ResultEventArgs.Success("Blank line found, skipping!"));
resultProgress?.Report(ResultEventArgs.Neutral("Blank line found, skipping!"));
continue;
}
@@ -254,7 +254,7 @@ namespace MPF.Frontend.Tools
|| hashData.Contains("(Track AA.5).bin"))
{
trackCount--;
resultProgress?.Report(ResultEventArgs.Success("Extra track found, skipping!"));
resultProgress?.Report(ResultEventArgs.Neutral("Extra track found, skipping!"));
continue;
}
@@ -349,7 +349,7 @@ namespace MPF.Frontend.Tools
continue;
// Fill in the fields from the existing ID
resultProgress?.Report(ResultEventArgs.Success($"Filling fields from existing ID {fullyMatchedIdsList[i]}..."));
resultProgress?.Report(ResultEventArgs.Neutral($"Filling fields from existing ID {fullyMatchedIdsList[i]}..."));
_ = await Builder.FillFromId(wc, info, fullyMatchedIdsList[i], options.PullAllInformation);
resultProgress?.Report(ResultEventArgs.Success("Information filling complete!"));

View File

@@ -1,4 +1,6 @@
using System;
#if !(NET20 || NET35 || NET40)
using System;
#endif
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;

View File

@@ -1121,7 +1121,7 @@ namespace MPF.Frontend.ViewModels
/// <param name="text">Text to write to the log</param>
private void Log(string text)
{
_logger?.Invoke(LogLevel.USER, text);
_logger?.Invoke(LogLevel.USER_GENERIC, text);
}
/// <summary>
@@ -1160,6 +1160,21 @@ namespace MPF.Frontend.ViewModels
/// <param name="text">Text to write to the log</param>
private void SecretLogLn(string text) => SecretLog(text + "\n");
/// <summary>
/// Enqueue success text to the log
/// </summary>
/// <param name="text">Text to write to the log</param>
private void SuccessLog(string text)
{
_logger?.Invoke(LogLevel.USER_SUCCESS, text);
}
/// <summary>
/// Enqueue text with a newline to the log
/// </summary>
/// <param name="text">Text to write to the log</param>
private void SuccessLogLn(string text) => SuccessLog(text + "\n");
/// <summary>
/// Enqueue verbose text to the log
/// </summary>
@@ -1360,7 +1375,7 @@ namespace MPF.Frontend.ViewModels
Status = result.Message;
// Enable or disable the button
StartStopButtonEnabled = result && ShouldEnableDumpingButton();
StartStopButtonEnabled = result == true && ShouldEnableDumpingButton();
// If we're in a type that doesn't support drive speeds
DriveSpeedComboBoxEnabled = DumpEnvironment.DoesSupportDriveSpeed(CurrentMediaType);
@@ -2231,7 +2246,7 @@ namespace MPF.Frontend.ViewModels
// If we didn't execute a dumping command we cannot get submission output
if (!_environment.IsDumpingCommand())
{
LogLn("No dumping command was run, submission information will not be gathered.");
SuccessLogLn("No dumping command was run, submission information will not be gathered.");
Status = "Execution complete!";
// Re-allow quick exiting
@@ -2243,14 +2258,14 @@ namespace MPF.Frontend.ViewModels
}
// Verify dump output and save it
if (result)
if (result == true)
{
result = await _environment.VerifyAndSaveDumpOutput(
resultProgress: resultProgress,
protectionProgress: protectionProgress,
processUserInfo: _processUserInfo);
if (!result)
if (result == false)
ErrorLogLn(result.Message);
}
else
@@ -2507,7 +2522,7 @@ namespace MPF.Frontend.ViewModels
/// </summary>
private void ProgressUpdated(object? sender, ResultEventArgs value)
{
var message = value?.Message;
var message = value.Message;
// Update the label with only the first line of output
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
@@ -2520,9 +2535,11 @@ namespace MPF.Frontend.ViewModels
Status = message ?? string.Empty;
// Log based on success or failure
if (value is not null && value)
VerboseLogLn(message ?? string.Empty);
else if (value is not null && !value)
if ((bool?)value is null)
LogLn(message ?? string.Empty);
else if (value == true)
SuccessLogLn(message ?? string.Empty);
else if (value == false)
ErrorLogLn(message ?? string.Empty);
}

View File

@@ -109,15 +109,17 @@ namespace MPF.UI.UserControls
/// <returns>Brush representing the color</returns>
public Brush GetForegroundColor()
{
#pragma warning disable IDE0072
return LogLevel switch
{
LogLevel.SECRET => Brushes.DarkGray,
LogLevel.ERROR => Brushes.Red,
LogLevel.VERBOSE => Brushes.Yellow,
_ => Brushes.White,
LogLevel.USER_SUCCESS => Brushes.ForestGreen,
LogLevel.USER_GENERIC => Brushes.White,
// Make unmatched log levels obvious
_ => Brushes.Pink,
};
#pragma warning restore IDE0072
}
/// <summary>

View File

@@ -159,7 +159,7 @@ namespace MPF.UI.Windows
private async void OnCheckDumpClick(object sender, EventArgs e)
{
var result = await CheckDumpViewModel.CheckDump(ShowMediaInformationWindow);
if (result)
if (result == true)
{
bool? checkAgain = DisplayUserMessage("Check Complete", "The dump has been processed successfully! Would you like to check another dump?", 2, false);
if (checkAgain == false)