Build: Make DexMethodCount task cacheable, extract print stats to task
This commit is contained in:
@@ -5,10 +5,12 @@
|
|||||||
|
|
||||||
import com.jakewharton.dex.*
|
import com.jakewharton.dex.*
|
||||||
import org.gradle.api.DefaultTask
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
import org.gradle.jvm.tasks.Jar
|
import org.gradle.jvm.tasks.Jar
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
@CacheableTask
|
||||||
open class DexMethodCount : DefaultTask() {
|
open class DexMethodCount : DefaultTask() {
|
||||||
|
|
||||||
data class Counts(
|
data class Counts(
|
||||||
@@ -19,34 +21,23 @@ open class DexMethodCount : DefaultTask() {
|
|||||||
val byClass: Map<String, Int>
|
val byClass: Map<String, Int>
|
||||||
)
|
)
|
||||||
|
|
||||||
init {
|
@Classpath
|
||||||
outputs.upToDateWhen { !shouldPrintTeamCityStatistics } // always execute when teamCityStatistics output is required
|
|
||||||
}
|
|
||||||
|
|
||||||
@InputFile
|
|
||||||
lateinit var jarFile: File
|
lateinit var jarFile: File
|
||||||
|
|
||||||
@Input
|
|
||||||
@Optional
|
@Optional
|
||||||
|
@Input
|
||||||
var ownPackages: List<String>? = null
|
var ownPackages: List<String>? = null
|
||||||
|
|
||||||
// ##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}' value='62362']
|
@Internal
|
||||||
@Input
|
|
||||||
@Optional
|
|
||||||
var teamCityStatistics: Boolean? = null
|
|
||||||
|
|
||||||
private val shouldPrintTeamCityStatistics = teamCityStatistics ?: project.hasProperty("teamcity")
|
|
||||||
|
|
||||||
|
|
||||||
@Input
|
|
||||||
@Optional
|
|
||||||
var artifactName: String? = null
|
var artifactName: String? = null
|
||||||
|
|
||||||
private val artifactOrArchiveName get() = artifactName ?: project.name
|
@get:Input
|
||||||
|
val artifactOrArchiveName: String
|
||||||
|
get() = artifactName ?: project.name
|
||||||
|
|
||||||
fun from(jar: Jar) {
|
fun from(jar: Jar) {
|
||||||
jarFile = jar.archivePath
|
jarFile = jar.archiveFile.get().asFile
|
||||||
artifactName = jar.baseName
|
artifactName = jar.archiveBaseName.orNull
|
||||||
dependsOn(jar)
|
dependsOn(jar)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,16 +45,13 @@ open class DexMethodCount : DefaultTask() {
|
|||||||
lateinit var counts: Counts
|
lateinit var counts: Counts
|
||||||
|
|
||||||
@get:OutputFile
|
@get:OutputFile
|
||||||
val detailOutputFile: File get() = project.buildDir.resolve("$artifactOrArchiveName-method-count.txt")
|
val detailOutputFile: File
|
||||||
|
get() = project.buildDir.resolve("$artifactOrArchiveName-method-count.txt")
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
fun invoke() {
|
fun invoke() {
|
||||||
val methods = dexMethods(jarFile)
|
val methods = dexMethods(jarFile)
|
||||||
|
|
||||||
val counts = methods.getCounts().also { this.counts = it }
|
val counts = methods.getCounts().also { this.counts = it }
|
||||||
|
|
||||||
printTotals(counts)
|
|
||||||
printTCStats(counts)
|
|
||||||
outputDetails(counts)
|
outputDetails(counts)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +59,7 @@ open class DexMethodCount : DefaultTask() {
|
|||||||
val byPackage = this.groupingBy { it.`package` }.eachCount()
|
val byPackage = this.groupingBy { it.`package` }.eachCount()
|
||||||
val byClass = this.groupingBy { it.declaringType }.eachCount()
|
val byClass = this.groupingBy { it.declaringType }.eachCount()
|
||||||
|
|
||||||
val ownPackages = ownPackages?.map { it + '.' }
|
val ownPackages = ownPackages?.map { "$it." }
|
||||||
val byOwnPackages = if (ownPackages != null) {
|
val byOwnPackages = if (ownPackages != null) {
|
||||||
this.partition { method -> ownPackages.any { method.declaringType.startsWith(it) } }.let {
|
this.partition { method -> ownPackages.any { method.declaringType.startsWith(it) } }.let {
|
||||||
it.first.size to it.second.size
|
it.first.size to it.second.size
|
||||||
@@ -87,26 +75,6 @@ open class DexMethodCount : DefaultTask() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun printTotals(counts: Counts) {
|
|
||||||
logger.lifecycle("Artifact $artifactOrArchiveName, total methods: ${counts.total}")
|
|
||||||
ownPackages?.let { packages ->
|
|
||||||
logger.lifecycle("Artifact $artifactOrArchiveName, total methods from packages ${packages.joinToString { "$it.*" }}: ${counts.totalOwnPackages}")
|
|
||||||
logger.lifecycle("Artifact $artifactOrArchiveName, total methods from other packages: ${counts.totalOtherPackages}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printTCStats(counts: Counts) {
|
|
||||||
if (shouldPrintTeamCityStatistics) {
|
|
||||||
println("##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}' value='${counts.total}']")
|
|
||||||
counts.totalOwnPackages?.let { value ->
|
|
||||||
println("##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}_OwnPackages' value='$value']")
|
|
||||||
}
|
|
||||||
counts.totalOtherPackages?.let { value ->
|
|
||||||
println("##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}_OtherPackages' value='$value']")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun outputDetails(counts: Counts) {
|
private fun outputDetails(counts: Counts) {
|
||||||
detailOutputFile.printWriter().use { writer ->
|
detailOutputFile.printWriter().use { writer ->
|
||||||
writer.println("${counts.total.padRight()}\tTotal methods")
|
writer.println("${counts.total.padRight()}\tTotal methods")
|
||||||
@@ -126,9 +94,67 @@ open class DexMethodCount : DefaultTask() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open class DexMethodCountStats : DefaultTask() {
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
lateinit var from: TaskProvider<DexMethodCount>
|
||||||
|
|
||||||
|
@get:InputFile
|
||||||
|
internal val inputFile
|
||||||
|
get() = from.get().detailOutputFile
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
private fun printStats() {
|
||||||
|
val artifactOrArchiveName = from.get().artifactOrArchiveName
|
||||||
|
inputFile.reader().useLines { lines ->
|
||||||
|
fun String.getStatValue() = substringBefore("\t").trim()
|
||||||
|
|
||||||
|
val ownPackages = from.get().ownPackages
|
||||||
|
val statsLineCount = if (ownPackages == null) 1 else 3
|
||||||
|
val stats = lines.take(statsLineCount).map { it.getStatValue() }.toList()
|
||||||
|
|
||||||
|
val total = stats[0]
|
||||||
|
logger.lifecycle("Artifact $artifactOrArchiveName, total methods: $total")
|
||||||
|
|
||||||
|
if (project.kotlinBuildProperties.isTeamcityBuild) {
|
||||||
|
println("##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}' value='$total']")
|
||||||
|
}
|
||||||
|
|
||||||
|
ownPackages?.let { packages ->
|
||||||
|
val totalOwnPackages = stats[1]
|
||||||
|
val totalOtherPackages = stats[2]
|
||||||
|
|
||||||
|
logger.lifecycle("Artifact $artifactOrArchiveName, total methods from packages ${packages.joinToString { "$it.*" }}: $totalOwnPackages")
|
||||||
|
logger.lifecycle("Artifact $artifactOrArchiveName, total methods from other packages: $totalOtherPackages")
|
||||||
|
|
||||||
|
if (project.kotlinBuildProperties.isTeamcityBuild) {
|
||||||
|
println("##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}_OwnPackages' value='$totalOwnPackages']")
|
||||||
|
println("##teamcity[buildStatisticValue key='DexMethodCount_${artifactOrArchiveName}_OtherPackages' value='$totalOtherPackages']")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Project.printStats(dexMethodCount: TaskProvider<DexMethodCount>) {
|
||||||
|
val dexMethodCountStats = tasks.register("dexMethodCountStats", DexMethodCountStats::class.java) {
|
||||||
|
dependsOn(dexMethodCount)
|
||||||
|
from = dexMethodCount
|
||||||
|
}
|
||||||
|
|
||||||
|
dexMethodCount.configure {
|
||||||
|
finalizedBy(dexMethodCountStats)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Project.dexMethodCount(action: DexMethodCount.() -> Unit): TaskProvider<DexMethodCount> {
|
||||||
|
val dexMethodCount = tasks.register("dexMethodCount", DexMethodCount::class.java, action)
|
||||||
|
printStats(dexMethodCount)
|
||||||
|
tasks.getByName("check").dependsOn(dexMethodCount)
|
||||||
|
return dexMethodCount
|
||||||
|
}
|
||||||
|
|
||||||
private val DexMethod.`package`: String get() = declaringType.substringBeforeLast('.')
|
private val DexMethod.`package`: String get() = declaringType.substringBeforeLast('.')
|
||||||
private fun Int.padRight() = toString().padStart(5, ' ')
|
private fun Int.padRight() = toString().padStart(5, ' ')
|
||||||
|
|||||||
@@ -217,12 +217,11 @@ val modularJar by task<Jar> {
|
|||||||
callGroovy("manifestAttributes", manifest, project, "Main", true)
|
callGroovy("manifestAttributes", manifest, project, "Main", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dexMethodCount by task<DexMethodCount> {
|
dexMethodCount {
|
||||||
dependsOn(result)
|
dependsOn(result)
|
||||||
jarFile = result.get().outputs.files.single()
|
jarFile = result.get().outputs.files.single()
|
||||||
ownPackages = listOf("kotlin.reflect")
|
ownPackages = listOf("kotlin.reflect")
|
||||||
}
|
}
|
||||||
tasks.getByName("check").dependsOn(dexMethodCount)
|
|
||||||
|
|
||||||
artifacts {
|
artifacts {
|
||||||
listOf(mainJar.name, "runtime", "archives").forEach { configurationName ->
|
listOf(mainJar.name, "runtime", "archives").forEach { configurationName ->
|
||||||
|
|||||||
@@ -106,11 +106,10 @@ artifacts {
|
|||||||
|
|
||||||
javadocJar()
|
javadocJar()
|
||||||
|
|
||||||
task dexMethodCount(type: DexMethodCount) {
|
DexMethodCountKt.dexMethodCount(project) { task ->
|
||||||
from jar
|
task.from(jar)
|
||||||
ownPackages = ['kotlin']
|
task.ownPackages = ['kotlin']
|
||||||
}
|
}
|
||||||
check.dependsOn(dexMethodCount)
|
|
||||||
|
|
||||||
compileKotlin {
|
compileKotlin {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
|
|||||||
Reference in New Issue
Block a user