All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.gradle.report.KotlinBuildReporterHandler.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-Beta1
Show newest version
/*
 * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.gradle.report

import org.gradle.api.invocation.Gradle
import org.jetbrains.kotlin.gradle.utils.appendLine
import java.io.File
import kotlin.math.max

class KotlinBuildReporterHandler {
    fun buildFinished(
        gradle: Gradle,
        perfReportFile: File,
        kotlinTaskTimeNs: Map,
        allTasksTimeNs: Long,
        failure: Throwable? = null
    ) {
        val logger = gradle.rootProject.logger
        try {
            perfReportFile.writeText(buildInfo(gradle, failure) + taskOverview(kotlinTaskTimeNs, allTasksTimeNs))
            logger.lifecycle("Kotlin build report is written to ${perfReportFile.canonicalPath}")
        } catch (e: Throwable) {
            logger.error("Could not write Kotlin build report to ${perfReportFile.canonicalPath}", e)
        }
    }

    private fun buildInfo(gradle: Gradle, failure: Throwable?): String {
        val startParams = arrayListOf()
        gradle.startParameter.apply {
            startParams.add("tasks = ${taskRequests.joinToString { it.args.toString() }}")
            startParams.add("excluded tasks = $excludedTaskNames")
            startParams.add("current dir = $currentDir")
            startParams.add("project properties args = $projectProperties")
            startParams.add("system properties args = $systemPropertiesArgs")
        }

        return buildString {
            appendLine("Gradle start parameters:")
            startParams.forEach {
                appendLine("  $it")
            }
            if (failure != null) {
                appendLine("Build failed: ${failure}")
            }
            appendLine()
        }
    }

    internal fun taskOverview(kotlinTaskTimeNs: Map, allTasksTimeNs: Long): String {
        if (kotlinTaskTimeNs.isEmpty()) return buildString { appendLine("No Kotlin task was run") }

        val sb = StringBuilder()
        val kotlinTotalTimeNs = kotlinTaskTimeNs.values.sum()
        val ktTaskPercent = (kotlinTotalTimeNs.toDouble() / allTasksTimeNs * 100).asString(1)

        sb.appendLine("Total time for Kotlin tasks: ${formatTime(kotlinTotalTimeNs)} ($ktTaskPercent % of all tasks time)")

        val table = TextTable("Time", "% of Kotlin time", "Task")
        kotlinTaskTimeNs.entries
            .sortedByDescending { (_, timeNs) -> timeNs }
            .forEach { (taskPath, timeNs) ->
                val percent = (timeNs.toDouble() / kotlinTotalTimeNs * 100).asString(1)
                table.addRow(formatTime(timeNs), "$percent %", taskPath)
            }
        table.printTo(sb)
        sb.appendLine()
        return sb.toString()
    }

    internal class TextTable(vararg columnNames: String) {
        private val rows = ArrayList>()
        private val columnsCount = columnNames.size
        private val maxLengths = IntArray(columnsCount) { columnNames[it].length }

        init {
            rows.add(columnNames.toList())
        }

        fun addRow(vararg row: String) {
            check(row.size == columnsCount) { "Row size ${row.size} differs from columns count $columnsCount" }
            rows.add(row.toList())

            for ((i, col) in row.withIndex()) {
                maxLengths[i] = max(maxLengths[i], col.length)
            }
        }

        fun printTo(sb: StringBuilder) {
            for (row in rows) {
                sb.appendLine()
                for ((i, col) in row.withIndex()) {
                    if (i > 0) sb.append("|")

                    sb.append(col.padEnd(maxLengths[i], ' '))
                }
            }
        }
    }
}

internal fun formatTime(ns: Long): String {
    val seconds = ns.toDouble() / 1_000
    return seconds.asString(2) + " s"
}

internal fun Double.asString(decPoints: Int): String =
    String.format("%.${decPoints}f", this)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy