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

com.autonomousapps.internal.graph.GraphViewBuilder.kt Maven / Gradle / Ivy

There is a newer version: 2.0.2
Show newest version
package com.autonomousapps.internal.graph

import com.autonomousapps.internal.isJavaPlatform
import com.autonomousapps.internal.utils.mapNotNullToSet
import com.autonomousapps.internal.utils.rootCoordinates
import com.autonomousapps.internal.utils.toCoordinates
import com.autonomousapps.model.Coordinates
import com.autonomousapps.model.DependencyGraphView
import com.google.common.graph.Graph
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.FileCollectionDependency
import org.gradle.api.artifacts.result.ResolvedComponentResult
import org.gradle.api.artifacts.result.ResolvedDependencyResult

/** Walks the resolved dependency graph to create a dependency graph rooted on the current project. */
@Suppress("UnstableApiUsage") // Guava Graph
internal class GraphViewBuilder(conf: Configuration) {

  val graph: Graph

  private val graphBuilder = DependencyGraphView.newGraphBuilder()

  private val visited = mutableSetOf()

  init {
    val root = conf
      .incoming
      .resolutionResult
      .root

    val rootId = conf.rootCoordinates()

    walkFileDeps(conf, rootId)
    walk(root, rootId)

    graph = graphBuilder.build()
  }

  private fun walkFileDeps(conf: Configuration, rootId: Coordinates) {
    graphBuilder.addNode(rootId)

    // the only way to get flat jar file dependencies
    conf.allDependencies
      .filterIsInstance()
      .mapNotNullToSet { it.toCoordinates() }
      .forEach { id ->
        graphBuilder.putEdge(rootId, id)
      }
  }

  private fun walk(root: ResolvedComponentResult, rootId: Coordinates) {
    root.dependencies
      .filterIsInstance()
      // AGP adds all runtime dependencies as constraints to the compile classpath, and these show
      // up in the resolution result. Filter them out.
      .filterNot { it.isConstraint }
      // For similar reasons as above
      .filterNot { it.isJavaPlatform() }
      // Sometimes there is a self-dependency?
      .filterNot { it.toCoordinates() == rootId }
      .forEach { dependencyResult ->
        // Might be from an included build, in which case the coordinates reflect the _requested_ dependency instead of
        // the _resolved_ dependency.
        val depId = dependencyResult.toCoordinates()

        // add an edge
        graphBuilder.putEdge(rootId, depId)

        if (!visited.contains(depId)) {
          visited.add(depId)
          // recursively walk the graph in a depth-first pattern
          walk(dependencyResult.selected, depId)
        }
      }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy