b61a02db73
Merge-request: KT-MR-8690 Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
165 lines
5.6 KiB
Kotlin
165 lines
5.6 KiB
Kotlin
rootProject {
|
|
apply<DegradePlugin>()
|
|
}
|
|
|
|
class DegradePlugin : Plugin<Project> {
|
|
override fun apply(target: Project) {
|
|
if (target != target.rootProject) return
|
|
|
|
Degrade(target).register()
|
|
}
|
|
}
|
|
|
|
private class Degrade(val rootProject: Project) {
|
|
private val scriptDir = rootProject.file("degrade")
|
|
|
|
private class TaskLog {
|
|
val stdout = StringBuilder()
|
|
|
|
fun clear() {
|
|
stdout.clear()
|
|
}
|
|
}
|
|
|
|
private fun setupTaskLog(task: Task): TaskLog {
|
|
val log = TaskLog()
|
|
task.logging.addStandardOutputListener { log.stdout.append(it) }
|
|
return log
|
|
}
|
|
|
|
fun register() {
|
|
rootProject.gradle.addListener(object : BuildAdapter(), TaskExecutionListener {
|
|
val taskToLog = mutableMapOf<Task, TaskLog>()
|
|
val allScripts = mutableListOf<String>()
|
|
val failedScripts = mutableListOf<String>()
|
|
|
|
@Synchronized
|
|
override fun beforeExecute(task: Task) {
|
|
taskToLog.getOrPut(task) { setupTaskLog(task) }.clear()
|
|
}
|
|
|
|
@Synchronized
|
|
override fun afterExecute(task: Task, state: TaskState) {
|
|
val log = taskToLog[task] ?: return
|
|
val script = generateScriptForTask(task, log) ?: return
|
|
allScripts += script
|
|
if (state.failure != null) {
|
|
failedScripts += script
|
|
}
|
|
}
|
|
|
|
@Synchronized
|
|
override fun buildFinished(result: BuildResult) {
|
|
try {
|
|
generateAggregateScript("rerun-all.sh", allScripts)
|
|
generateAggregateScript("rerun-failed.sh", failedScripts)
|
|
} finally {
|
|
failedScripts.clear()
|
|
allScripts.clear()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
private fun generateAggregateScript(name: String, scripts: List<String>) = generateScript(name) {
|
|
appendLine("""cd "$(dirname "$0")"""")
|
|
appendLine()
|
|
scripts.forEach {
|
|
appendLine("./$it")
|
|
}
|
|
}
|
|
|
|
private fun generateScriptForTask(task: Task, taskLog: TaskLog): String? {
|
|
val project = task.project
|
|
|
|
val stdoutLinesIterator = taskLog.stdout.split('\n').iterator()
|
|
val commands = parseKotlinNativeCommands { stdoutLinesIterator.takeIf { it.hasNext() }?.next() }
|
|
|
|
if (commands.isEmpty()) return null
|
|
|
|
val konanHome = project.properties["konanHome"] ?: project.properties["kotlinNativeDist"]
|
|
|
|
val scriptName = task.path.substring(1).replace(':', '_') + ".sh"
|
|
|
|
generateScript(scriptName) {
|
|
appendLine("""kotlinNativeDist="$konanHome"""")
|
|
appendLine()
|
|
commands.forEach { command ->
|
|
appendLine(""""${"$"}kotlinNativeDist/bin/run_konan" \""")
|
|
command.transformedArguments.forEachIndexed { index, argument ->
|
|
append(" ")
|
|
append(argument)
|
|
if (index != command.transformedArguments.lastIndex) {
|
|
appendLine(" \\")
|
|
}
|
|
}
|
|
appendLine()
|
|
appendLine()
|
|
}
|
|
}
|
|
|
|
return scriptName
|
|
}
|
|
|
|
private fun parseKotlinNativeCommands(nextLine: () -> String?): List<KotlinNativeCommand> {
|
|
val result = mutableListOf<KotlinNativeCommand>()
|
|
|
|
while (true) {
|
|
val line = nextLine() ?: break
|
|
if (line != "Main class = $kotlinNativeEntryPointClass"
|
|
&& !line.startsWith("Entry point method = $kotlinNativeEntryPointClass.")) continue
|
|
|
|
generateSequence(nextLine)
|
|
.firstOrNull { it.startsWith("Transformed arguments = ") }
|
|
.takeIf { it == "Transformed arguments = [" }
|
|
?: continue
|
|
|
|
val transformedArguments = generateSequence(nextLine)
|
|
.takeWhile { it != "]" }
|
|
.flatMap {
|
|
val line = it.trimStart()
|
|
if (line.startsWith("@")) { // argument with filename containing list of arguments
|
|
File(line.substringAfter("@"))
|
|
.readText()
|
|
.split("\n")
|
|
.map { it.substringAfter('"').substringBeforeLast('"') }
|
|
} else
|
|
listOf(line)
|
|
}
|
|
.toList()
|
|
|
|
result += KotlinNativeCommand(transformedArguments)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
private class KotlinNativeCommand(val transformedArguments: List<String>)
|
|
|
|
private companion object {
|
|
const val kotlinNativeEntryPointClass = "org.jetbrains.kotlin.cli.utilities.MainKt"
|
|
|
|
// appendLine is not available in Kotlin stdlib shipped with older Gradle versions;
|
|
// Copied here:
|
|
|
|
/** Appends a line feed character (`\n`) to this Appendable. */
|
|
private fun Appendable.appendLine(): Appendable = append('\n')
|
|
|
|
/** Appends value to the given Appendable and a line feed character (`\n`) after it. */
|
|
private fun Appendable.appendLine(value: CharSequence?): Appendable = append(value).appendLine()
|
|
}
|
|
|
|
private fun generateScript(name: String, generateBody: Appendable.() -> Unit) {
|
|
scriptDir.mkdirs()
|
|
val file = File(scriptDir, name)
|
|
file.bufferedWriter().use { writer ->
|
|
writer.appendLine("#!/bin/sh")
|
|
writer.appendLine("set -e")
|
|
writer.appendLine()
|
|
|
|
writer.generateBody()
|
|
}
|
|
file.setExecutable(true)
|
|
}
|
|
}
|