Skip to content

Instantly share code, notes, and snippets.

@dkilmer
Created April 28, 2022 18:15
Show Gist options
  • Save dkilmer/5f8a24816599d4be125cbc854eb7af98 to your computer and use it in GitHub Desktop.
Save dkilmer/5f8a24816599d4be125cbc854eb7af98 to your computer and use it in GitHub Desktop.
Poor person's gradle task timer
import java.io.BufferedReader
import java.io.File
import java.io.InputStream
import java.io.InputStreamReader
import java.time.Instant
import kotlin.system.exitProcess
private val WHITESPACE = Regex("\\s+")
class StreamProcessor(val stream: InputStream, val lineCb: (String) -> Unit) : Thread() {
init { start() }
override fun run() {
val rdr = BufferedReader(InputStreamReader(stream))
var line: String? = rdr.readLine()
while (line != null) {
lineCb(line)
line = rdr.readLine()
}
}
}
fun execBashProcessingOutput(
cmd: String, dir: String,
args: List<String> = listOf(),
envs: Map<String,String> = emptyMap(),
stdoutProcessor: (InputStream) -> Unit,
stderrProcessor: (InputStream) -> Unit,
) : Int {
val pb = if (args.isNotEmpty()) {
ProcessBuilder(cmd, *args.toTypedArray()).directory(File(dir))
} else {
ProcessBuilder(cmd).directory(File(dir))
}
if (envs.isNotEmpty()) pb.environment().putAll(envs)
val proc = pb.start()
stdoutProcessor(proc.inputStream)
stderrProcessor(proc.errorStream)
return proc.waitFor()
}
fun String.replaceLeadingTilde() = if (startsWith("~")) {
"${File(System.getProperty("user.home"))}/${substring(1)}"
} else {
this
}
fun Long.toDurationStr() : String {
val durations = listOf(
Pair("days", 86400000),
Pair("hours", 3600000),
Pair("minutes", 60000),
Pair("seconds", 1000),
Pair("ms", 1)
)
var ms = this
val sb = StringBuilder()
for (p in durations) {
var label = p.first
val dur = p.second
if (ms >= dur) {
val n = (ms / dur)
ms -= (dur * n)
if (sb.isNotEmpty()) sb.append(", ")
if (n == 1L) label = label.substring(0, label.length-1)
sb.append("$n $label")
}
}
return if (sb.isNotEmpty()) sb.toString() else "0 ms"
}
fun printUsage() {
println("usage: kotlin GradleTimer.kts {args-filename}")
}
if (args.isEmpty()) {
printUsage()
exitProcess(1)
}
val filename = args[0]
if (filename.lowercase() == "--help" || filename.lowercase() == "-h" ) {
printUsage()
exitProcess(0)
}
val gradleArgs = File(filename.replaceLeadingTilde()).apply {
if (!exists() || !isFile()) {
println("invalid file: $canonicalPath")
exitProcess(1)
}
}.readLines().let {
if (!it.contains("--console plain")) {
it.plus("--console plain")
} else {
it
}
}.flatMap {
it.split(WHITESPACE)
}
println("gradle args: $gradleArgs")
data class TaskTime(
val task: String,
val startTime: Long,
var endTime: Long = startTime
)
val timeList = mutableListOf<TaskTime>()
execBashProcessingOutput("gradle", System.getProperty("user.dir"), gradleArgs, System.getenv(),
{ stdout ->
StreamProcessor(stdout) { line ->
if (line.startsWith("> Task ") || line.startsWith("BUILD")) {
val time = Instant.now().toEpochMilli()
if (timeList.isNotEmpty()) {
timeList.last().endTime = time
}
if (!line.startsWith("BUILD")) {
timeList.add(TaskTime(line.substring(7), time))
}
}
println(line)
}
},
{ stderr ->
StreamProcessor(stderr) { line ->
println("stderr: $line")
}
}
)
println("-=-= ${filename}")
timeList.forEach {
println("${it.task} -> ${(it.endTime-it.startTime).toDurationStr()}")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment