Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 78 additions & 16 deletions src/main/kotlin/file/SetupApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,16 @@ object SetupApp {
}

private fun fail(message: String) {
log.error(message)
if (setup.quiet) {
System.err.println(message)
} else {
log.error(message)
}
}

private fun detail(message: String) {
if (setup.quiet) {
println(message)
System.err.println(message)
} else {
log.info(message)
}
Expand Down Expand Up @@ -366,13 +370,15 @@ object SetupApp {
if (printPjassFailure(result.output)) {
return
}
fail("❌ Wurst $commandName failed.")
detail("Exit code: ${result.exitCode}")
if (setup.quiet) {
detail("Next: rerun without `--quiet` only for the failed file/test.")
} else {
detail("Try: rerun with `--quiet` for a shorter error log, or `--debug` for troubleshooting details.")
val diagnostics = quietCompilerDiagnostics(result.output)
Comment thread
Frotty marked this conversation as resolved.
Outdated
diagnostics.forEach { System.err.println(it) }
fail("❌ Wurst $commandName failed. (Errors: ${quietCompilerErrorCount(result.output, diagnostics)})")
return
}
fail("❌ Wurst $commandName failed.")
detail("Exit code: ${result.exitCode}")
detail("Try: rerun with `--quiet` for a shorter error log, or `--debug` for troubleshooting details.")
}

private fun printPjassFailure(output: List<String>): Boolean {
Expand Down Expand Up @@ -402,14 +408,75 @@ object SetupApp {
return true
}

private fun isImportantCompilerLine(line: String): Boolean {
return line.contains("error", ignoreCase = true) ||
line.contains("warning", ignoreCase = true) ||
line.contains("FAILED", ignoreCase = true) ||
internal fun quietCompilerDiagnostics(output: List<String>): List<String> {
val diagnostics = ArrayList<String>()
var pendingVerboseError: MatchResult? = null

for (rawLine in output) {
val line = rawLine.trimEnd()
if (line.isBlank() || isNoisyCompilerVersionLine(line) || isQuietCompilerNoiseLine(line)) {
continue
}

val verboseError = Regex("""^Error in File (.+):(\d+):\s*$""").find(line.trim())
if (verboseError != null) {
pendingVerboseError = verboseError
continue
}

if (pendingVerboseError != null) {
diagnostics.add(
"Error ${pendingVerboseError.groupValues[1]}:${pendingVerboseError.groupValues[2]}: ${line.trim()}"
)
pendingVerboseError = null
continue
}

if (isQuietCompilerDiagnosticLine(line)) {
diagnostics.add(line)
}
}

return diagnostics.distinct()
}

internal fun quietCompilerErrorCount(
output: List<String>,
diagnostics: List<String> = quietCompilerDiagnostics(output)
): Int {
output.asSequence()
.map { Regex("""^Errors:\s*(\d+)\s*$""").find(it.trim()) }
.filterNotNull()
.firstOrNull()
?.let { return it.groupValues[1].toIntOrNull() ?: diagnostics.size.coerceAtLeast(1) }

return diagnostics.count {
it.startsWith("Error ", ignoreCase = true) ||
it.startsWith("FAILED ", ignoreCase = true) ||
it.contains(" exception", ignoreCase = true) ||
it.contains("Pjass", ignoreCase = true)
}.coerceAtLeast(1)
}

private fun isQuietCompilerDiagnosticLine(line: String): Boolean {
return line.startsWith("Error ", ignoreCase = true) ||
line.startsWith("FAILED ", ignoreCase = true) ||
Comment thread
Frotty marked this conversation as resolved.
line.contains(" assertion", ignoreCase = true) ||
line.contains("Exception", ignoreCase = true) ||
line.contains("Pjass", ignoreCase = true)
}

private fun isQuietCompilerNoiseLine(line: String): Boolean {
val trimmed = line.trim()
return trimmed.startsWith("Warning", ignoreCase = true) ||
trimmed.matches(Regex("""^Errors:\s*\d+\s*$""")) ||
trimmed.matches(Regex("""^Warnings:\s*\d+\s*$""")) ||
trimmed.matches(Regex("""^Tests:\s*\d+/\d+\s+passed\s*$""", RegexOption.IGNORE_CASE)) ||
trimmed.startsWith("compilation finished", ignoreCase = true) ||
trimmed.startsWith("Running tests", ignoreCase = true) ||
trimmed.startsWith("Finished running tests", ignoreCase = true)
}

private fun isNoisyCompilerVersionLine(line: String): Boolean {
val trimmed = line.trim()
return trimmed == "Warning: Ignoring unknown wc3Patch in wurst.build: ${CoreJassProvider.DEFAULT_PATCH}" ||
Expand Down Expand Up @@ -960,11 +1027,6 @@ object SetupApp {
}
}
val exitCode = p.waitFor()
if (setup.quiet && exitCode != 0) {
val printableOutput = if (setup.debug) output else output.filterNot(::isNoisyCompilerVersionLine)
val linesToPrint = if (compactFallback) printableOutput.filter(::isImportantCompilerLine) else printableOutput
linesToPrint.forEach { println(it) }
}
return WurstProcessResult(exitCode, output)
}

Expand Down
54 changes: 54 additions & 0 deletions src/test/kotlin/GenerateTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,60 @@ class GenerateTests {
Assert.assertTrue(setup.quiet)
}

@Test(priority = 10)
fun testQuietCompilerDiagnosticsSuppressGeneratedJassNoise() {
val output = listOf(
"Warnings: 3",
"Warning: Error: e:Could not find variable silverGladeCounter.",
"Warning: Error: e:Could not find a function with name eg",
"Error Broken.wurst:12: Could not find variable realUserTypo.",
"compilation finished (errors: 1, warnings: 3)",
"Errors: 1"
)

Assert.assertEquals(
SetupApp.quietCompilerDiagnostics(output),
listOf("Error Broken.wurst:12: Could not find variable realUserTypo.")
)
Assert.assertEquals(SetupApp.quietCompilerErrorCount(output), 1)
}

@Test(priority = 10)
fun testQuietCompilerDiagnosticsKeepFailedTestDetails() {
val output = listOf(
"Running tests",
"Tests: 1/2 passed",
"FAILED MyPkg.testExplodes",
"Errors: 1",
"Error MyTest.wurst:9: expected 1 but got 2",
"Finished running tests"
)

Assert.assertEquals(
SetupApp.quietCompilerDiagnostics(output),
listOf(
"FAILED MyPkg.testExplodes",
"Error MyTest.wurst:9: expected 1 but got 2"
)
)
Assert.assertEquals(SetupApp.quietCompilerErrorCount(output), 1)
}

@Test(priority = 10)
fun testQuietCompilerDiagnosticsNormalizeVerboseFallbackErrors() {
val output = listOf(
"Error in File Broken.wurst:12:",
" Could not find variable realUserTypo.",
"Warning in File war3map.j:44:",
" Error: e:Could not find variable silverGladeCounter."
)

Assert.assertEquals(
SetupApp.quietCompilerDiagnostics(output),
listOf("Error Broken.wurst:12: Could not find variable realUserTypo.")
)
}

@Test(priority = 10)
fun testDevBuildFlag() {
val setup = SetupMain()
Expand Down
Loading