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

com.didiglobal.booster.task.analyser.reference.ReferenceAnalysisTask.kt Maven / Gradle / Ivy

There is a newer version: 5.0.0-alpha3
Show newest version
package com.didiglobal.booster.task.analyser.reference

import com.didiglobal.booster.cha.asm.Reference
import com.didiglobal.booster.cha.asm.ReferenceAnalyser
import com.didiglobal.booster.cha.fold
import com.didiglobal.booster.gradle.getJars
import com.didiglobal.booster.gradle.getResolvedArtifactResults
import com.didiglobal.booster.graph.Graph
import com.didiglobal.booster.graph.dot.DotGraph
import com.didiglobal.booster.graph.json.JsonGraphRender
import com.didiglobal.booster.kotlinx.green
import com.didiglobal.booster.kotlinx.yellow
import com.didiglobal.booster.task.analyser.AnalysisTask
import com.didiglobal.booster.task.analyser.report
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.tasks.TaskAction
import org.gradle.reporting.HtmlReportRenderer
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

/**
 * Analysing the class reference for current variant to determine each class in this module is referenced by which class in which module
 *
 * @author johnsonlee
 */
open class ReferenceAnalysisTask : AnalysisTask() {

    override fun getDescription(): String = "Analysing class reference for Android/Java projects"

    @TaskAction
    override fun analyse() {
        val upstream = project.getResolvedArtifactResults(true, variant).associate {
            it.id.componentIdentifier.displayName to when (val id = it.id.componentIdentifier) {
                is ProjectComponentIdentifier -> project.rootProject.project(id.projectPath).getJars(variant).map { file ->
                    classSetCache[file.toURI().toURL()]
                }.fold()
                else -> classSetCache[it.file.toURI().toURL()]
            }
        }

        val origin = project.name to project.getJars(variant).map {
            classSetCache[it.toURI().toURL()]
        }.fold()
        val graph = ReferenceAnalyser().analyse(origin, upstream) { klass, progress, duration ->
            project.logger.info("${green(String.format("%3f%%", progress * 100))} Analyse class ${klass.name} in ${yellow(duration.toMillis())} ms")
        }
        val executor = Executors.newFixedThreadPool(3)

        try {
            arrayOf(::generateHtmlReport, ::generateDotReport, ::generateJsonReport).map { render ->
                executor.submit {
                    render(graph)
                }
            }.forEach {
                it.get()
            }
        } finally {
            executor.shutdown()
            executor.awaitTermination(1, TimeUnit.MINUTES)
        }
    }

    private fun generateDotReport(graph: Graph) {
        try {
            val options = DotGraph.DotOptions(rankdir = "LR", format = "svg")
            DotGraph.DIGRAPH.visualize(graph, report("dot"), options)
        } catch (e: Exception) {
            logger.error(e.message)
        }
    }

    private fun generateHtmlReport(graph: Graph) {
        HtmlReportRenderer().renderSinglePage(graph, ReferencePageRenderer(project, variant), report("html"))
    }

    private fun generateJsonReport(graph: Graph) {
        val json = JsonGraphRender.render(graph) { node ->
            """{"component": "${node.component}", "class": "${node.klass}"}"""
        }.toString()
        report("json").writeText(json)
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy