Skip to content

Commit 04b544e

Browse files
author
RandomCrocodile
committed
feature: add --dump diagnostic report flag to CLI (#65)
Wraps the logger and progress reporter with a DiagnosticCollector when --dump is passed, and writes the markdown report after the run completes (success or failure). --dump uses a default filename; --dump=<file> writes to a custom path. The report path is printed to the console. E2E test asserts the report is written with the expected sections.
1 parent b9fc475 commit 04b544e

2 files changed

Lines changed: 87 additions & 4 deletions

File tree

Confuser.CLI/Program.cs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq;
66
using System.Xml;
77
using Confuser.Core;
8+
using Confuser.Core.Diagnostics;
89
using Confuser.Core.Project;
910
using Microsoft.Extensions.Logging;
1011
using NDesk.Options;
@@ -25,6 +26,8 @@ static int Main(string[] args) {
2526
bool noPause = false;
2627
bool debug = false;
2728
bool quiet = false;
29+
bool dumpRequested = false;
30+
string dumpPath = null;
2831
int verbosity = 0;
2932
string outDir = null;
3033
string snKeyPath = null;
@@ -59,6 +62,9 @@ static int Main(string[] args) {
5962
}, {
6063
"q|quiet", "only show warnings and errors.",
6164
value => { quiet = (value != null); }
65+
}, {
66+
"dump:", "write a diagnostic report (optionally to the given file).",
67+
value => { dumpRequested = true; if (!string.IsNullOrEmpty(value)) dumpPath = value; }
6268
}
6369
};
6470

@@ -141,7 +147,7 @@ static int Main(string[] args) {
141147
parameters.Project = proj;
142148
}
143149

144-
int retVal = RunProject(parameters, quiet, verbosity);
150+
int retVal = RunProject(parameters, quiet, verbosity, dumpRequested, dumpPath);
145151

146152
if (NeedPause() && !noPause) {
147153
Console.WriteLine("Press any key to continue...");
@@ -203,7 +209,7 @@ static void LoadTemplateProject(string templatePath, ConfuserProject proj, List<
203209
templateModules.Add(templateModule);
204210
}
205211

206-
static int RunProject(ConfuserParameters parameters, bool quiet, int verbosity) {
212+
static int RunProject(ConfuserParameters parameters, bool quiet, int verbosity, bool dumpRequested, string dumpPath) {
207213
var levelSwitch = quiet
208214
? LogEventLevel.Warning
209215
: verbosity >= 3 ? LogEventLevel.Verbose
@@ -222,17 +228,44 @@ static int RunProject(ConfuserParameters parameters, bool quiet, int verbosity)
222228
var melLogger = loggerFactory.CreateLogger("ConfuserEx");
223229

224230
var progressReporter = new ConsoleProgressReporter();
225-
parameters.Logger = melLogger;
226-
parameters.ProgressReporter = progressReporter;
231+
232+
// When a diagnostic report is requested, wrap both the logger and the progress reporter
233+
// with a collector so the report captures the full transcript, timing and outcome even
234+
// when the run fails.
235+
DiagnosticCollector collector = null;
236+
if (dumpRequested) {
237+
collector = new DiagnosticCollector(melLogger, progressReporter) { Project = parameters.Project };
238+
parameters.Logger = collector;
239+
parameters.ProgressReporter = collector;
240+
}
241+
else {
242+
parameters.Logger = melLogger;
243+
parameters.ProgressReporter = progressReporter;
244+
}
227245

228246
if (OperatingSystem.IsWindows())
229247
Console.Title = "ConfuserEx - Running...";
230248
ConfuserEngine.Run(parameters).GetAwaiter().GetResult();
231249

232250
Log.CloseAndFlush();
251+
252+
if (collector != null)
253+
WriteDiagnosticReport(collector, dumpPath);
254+
233255
return progressReporter.ReturnValue;
234256
}
235257

258+
static void WriteDiagnosticReport(DiagnosticCollector collector, string dumpPath) {
259+
string path = string.IsNullOrEmpty(dumpPath) ? "confuser-diagnostic-report.md" : dumpPath;
260+
try {
261+
File.WriteAllText(path, collector.GenerateReport());
262+
WriteLineWithColor(ConsoleColor.Cyan, "Diagnostic report written to: " + Path.GetFullPath(path));
263+
}
264+
catch (Exception ex) {
265+
WriteLineWithColor(ConsoleColor.Red, "Failed to write diagnostic report: " + ex.Message);
266+
}
267+
}
268+
236269
static bool NeedPause() {
237270
return Debugger.IsAttached || string.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROMPT"));
238271
}
@@ -250,6 +283,7 @@ static void PrintUsage() {
250283
WriteLine(" -snkeypass : specifies strong name key password.");
251284
WriteLine(" -v|verbose : increase verbosity (-v debug, -vv trace).");
252285
WriteLine(" -q|quiet : only show warnings and errors.");
286+
WriteLine(" -dump : write a diagnostic report (-dump=<file> for a custom path).");
253287
}
254288

255289
static void WriteLineWithColor(ConsoleColor color, string txt) {

Tests/Confuser.CLI.Test/CliEndToEndTest.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,55 @@ public void Obfuscate_SampleApp_ProducesRunnableOutput() {
7070
}
7171
}
7272

73+
[Fact]
74+
public void Cli_DumpFlag_WritesDiagnosticReport() {
75+
var sampleAppExe = Path.Combine(AppContext.BaseDirectory, "Fixtures", "SampleApp", "bin", "SampleApp.exe");
76+
Assert.True(File.Exists(sampleAppExe), $"Pre-built SampleApp.exe not found at {sampleAppExe}");
77+
78+
var cliDll = Path.Combine(AppContext.BaseDirectory, "Confuser.CLI.dll");
79+
Assert.True(File.Exists(cliDll), $"Confuser.CLI.dll not found at {cliDll}");
80+
81+
var testDir = Path.Combine(Path.GetTempPath(), "confuserex-cli-dump-" + Guid.NewGuid().ToString("N")[..8]);
82+
Directory.CreateDirectory(testDir);
83+
84+
try {
85+
File.Copy(sampleAppExe, Path.Combine(testDir, "SampleApp.exe"));
86+
87+
var crproj = Path.Combine(testDir, "SampleApp.crproj");
88+
File.WriteAllText(crproj,
89+
@"<project outputDir="".\obfuscated"" baseDir=""."" xmlns=""http://confuser.codeplex.com"">
90+
<rule pattern=""true"" preset=""none"" inherit=""false"">
91+
<protection id=""rename"" />
92+
</rule>
93+
<module path=""SampleApp.exe"" />
94+
</project>");
95+
96+
var reportPath = Path.Combine(testDir, "report.md");
97+
98+
// Act — run Confuser.CLI with the --dump flag pointing at an explicit path
99+
var cliResult = RunProcess("dotnet", $"\"{cliDll}\" -n --dump=\"{reportPath}\" \"{crproj}\"");
100+
output.WriteLine("=== Confuser.CLI Output ===");
101+
output.WriteLine(cliResult.stdout);
102+
if (!string.IsNullOrEmpty(cliResult.stderr))
103+
output.WriteLine(cliResult.stderr);
104+
Assert.Equal(0, cliResult.exitCode);
105+
106+
// Assert — the report was written and announced
107+
Assert.True(File.Exists(reportPath), $"Diagnostic report should exist at {reportPath}");
108+
Assert.Contains("Diagnostic report written to:", cliResult.stdout);
109+
110+
var report = File.ReadAllText(reportPath);
111+
Assert.Contains("## System", report);
112+
Assert.Contains("## Project Configuration", report);
113+
Assert.Contains("## Result: SUCCESS", report);
114+
Assert.Contains("## Log Output", report);
115+
Assert.Contains("SampleApp.exe", report);
116+
}
117+
finally {
118+
try { Directory.Delete(testDir, true); } catch { }
119+
}
120+
}
121+
73122
[Fact]
74123
public void Cli_NoArgs_ReturnsNonZeroAndShowsUsage() {
75124
var cliDll = Path.Combine(AppContext.BaseDirectory, "Confuser.CLI.dll");

0 commit comments

Comments
 (0)