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

com.autonomousapps.tasks.ComputeDominatorTreeTask.kt Maven / Gradle / Ivy

There is a newer version: 2.0.2
Show newest version
@file:Suppress("SpellCheckingInspection")

package com.autonomousapps.tasks

import com.autonomousapps.TASK_GROUP_DEP_INTERNAL
import com.autonomousapps.graph.DominanceTree
import com.autonomousapps.graph.DominanceTreeWriter
import com.autonomousapps.graph.Graphs.reachableNodes
import com.autonomousapps.internal.graph.GraphWriter
import com.autonomousapps.internal.utils.FileUtils
import com.autonomousapps.internal.utils.fromJson
import com.autonomousapps.internal.utils.fromJsonSet
import com.autonomousapps.internal.utils.getAndDelete
import com.autonomousapps.model.*
import com.autonomousapps.model.PhysicalArtifact
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import java.io.File

@CacheableTask
abstract class ComputeDominatorTreeTask : DefaultTask() {

  init {
    group = TASK_GROUP_DEP_INTERNAL
    description = "Computes a dominator view of the dependency graph"
  }

  @get:Input
  abstract val projectPath: Property

  @get:PathSensitive(PathSensitivity.NONE)
  @get:InputFile
  abstract val physicalArtifacts: RegularFileProperty

  @get:PathSensitive(PathSensitivity.NONE)
  @get:InputFile
  abstract val graphView: RegularFileProperty

  @get:OutputFile
  abstract val outputTxt: RegularFileProperty

  @get:OutputFile
  abstract val outputDot: RegularFileProperty

  @TaskAction fun action() {
    val outputTxt = outputTxt.getAndDelete()
    val outputDot = outputDot.getAndDelete()

    val artifactMap = physicalArtifacts.fromJsonSet().associate { (coord, file) ->
      coord to file
    }
    val graphView = graphView.fromJson()
    val project = ProjectCoordinates(projectPath.get(), GradleVariantIdentification(setOf("ROOT"), emptyMap()), ":")

    val tree = DominanceTree(graphView.graph, project)
    val nodeWriter = BySize(
      files = artifactMap,
      tree = tree,
      root = project
    )
    val writer: DominanceTreeWriter = DominanceTreeWriter(
      root = project,
      tree = tree,
      nodeWriter = nodeWriter,
    )

    outputTxt.writeText(writer.string)
    outputDot.writeText(GraphWriter.toDot(tree.dominanceGraph))
  }

  private class BySize(
    private val files: Map,
    private val tree: DominanceTree,
    root: Coordinates
  ) : DominanceTreeWriter.NodeWriter {

    private val sizes = mutableMapOf()
    private val reachableNodes = mutableMapOf>()

    private fun getSize(node: Coordinates): Long = sizes.computeIfAbsent(node) { treeSizeOf(it) }

    private fun reachableNodes(node: Coordinates) = reachableNodes.computeIfAbsent(node) {
      tree.dominanceGraph.reachableNodes(node, excludeSelf = false)
    }

    private fun treeSizeOf(node: Coordinates): Long = reachableNodes(node)
      .mapNotNull { files[it] }
      .sumOf { it.length() }

    // Get the scale (bytes, KB, MB, ...) for printing.
    private val scale = reachableNodes(root)
      .mapNotNull { files[it] }
      .sumOf { it.length() }
      .let { FileUtils.getScale(it) }

    private val comparator = Comparator { left, right ->
      // nb: right.compareTo(left) is intentional. Sorted descending.
      getSize(right).compareTo(getSize(left))
    }

    override fun comparator(): Comparator = comparator

    override fun toString(node: Coordinates): String {
      val builder = StringBuilder()

      var printedTotalSize = false
      val subs = reachableNodes(node)
      if ((subs - node).isNotEmpty()) {
        val totalSize = subs
          .mapNotNull { files[it] }
          .sumOf { it.length() }

        printedTotalSize = true
        builder.append(FileUtils.byteCountToDisplaySize(totalSize, scale)).append(' ')
      }

      files[node]
        ?.length()
        ?.let {
          if (printedTotalSize) builder.append('(')
          builder.append(FileUtils.byteCountToDisplaySize(it, scale))
          if (printedTotalSize) builder.append(')')
          builder.append(' ')
        }

      val preferredCoordinatesNotation = if (node is IncludedBuildCoordinates) {
        node.resolvedProject
      } else {
        node
      }
      builder.append(preferredCoordinatesNotation.gav())
      return builder.toString()
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy