com.autonomousapps.internal.graph.GraphViewBuilder.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dependency-analysis-gradle-plugin Show documentation
Show all versions of dependency-analysis-gradle-plugin Show documentation
Analyzes dependency usage in Android and JVM projects
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)
}
}
}
}