Skip to content

Commit 30b1b05

Browse files
jjohannessschuberth
authored andcommitted
fix(DependencyGraphBuilder): Skip deep comparison for Gradle projects
This can be avoided as it leads to a long runtime (and possible an infinite loop / recursion) for large dependency graphs. In order to be able to skip the deep comparison, the selected variants need to be tracked in the Identifier. In the DependencyGraphBuilder all 'scopes' (runtimeClasspath, compileClasspath, ...) are thrown together. Gradle may have selected different variants of the components in different 'scopes'. Signed-off-by: Jendrik Johannes <[email protected]>
1 parent ad2ae20 commit 30b1b05

File tree

8 files changed

+34
-3
lines changed

8 files changed

+34
-3
lines changed

model/src/main/kotlin/Identifier.kt

+6-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ data class Identifier(
4949
/**
5050
* The version of the component.
5151
*/
52-
val version: String
52+
val version: String,
53+
54+
/**
55+
* The selected variants of the component.
56+
*/
57+
val variants: Set<String> = emptySet()
5358
) : Comparable<Identifier> {
5459
companion object {
5560
/**

model/src/main/kotlin/utils/DependencyGraphBuilder.kt

+8-1
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,14 @@ class DependencyGraphBuilder<D>(
328328

329329
val dependencies1 = ref.dependencies.mapTo(mutableSetOf()) { dependencyIds[it.pkg] }
330330
val dependencies2 = dependencies.associateBy { dependencyHandler.identifierFor(it) }
331-
if (dependencies1 != dependencies2.keys) return false
331+
332+
if (dependencies1 == dependencies2.keys) {
333+
if (!dependencyHandler.requiresDeepDependencyTreeComparison()) {
334+
return true
335+
}
336+
} else {
337+
return false
338+
}
332339

333340
return ref.dependencies.all { refDep ->
334341
dependencies2[dependencyIds[refDep.pkg]]?.let { dependencyTreeEquals(refDep, it) } == true

model/src/main/kotlin/utils/DependencyHandler.kt

+7
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,11 @@ interface DependencyHandler<D> {
6565
* implementation returns an empty collection.
6666
*/
6767
fun issuesForDependency(dependency: D): List<Issue> = emptyList()
68+
69+
/**
70+
* Does node comparison require a deep comparison of the whole dependency subtree or not? If the underlying
71+
* dependency management system, gives the guarantee for the latter, a costly comparison can be avoided and
72+
* speed up the analysis process.
73+
*/
74+
fun requiresDeepDependencyTreeComparison() = true
6875
}

plugins/package-managers/gradle-inspector/src/main/kotlin/GradleDependencyHandler.kt

+6
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ internal class GradleDependencyHandler(
125125
isMetadataOnly = hasNoArtifacts
126126
)
127127
}
128+
129+
/*
130+
* In case of Gradle, the costly deep comparison can be skipped, because if the direct dependencies are the same,
131+
* their children are also the same.
132+
*/
133+
override fun requiresDeepDependencyTreeComparison() = false
128134
}
129135

130136
// See http://maven.apache.org/pom.html#SCM.

plugins/package-managers/gradle-model/src/main/kotlin/GradleModel.kt

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ interface OrtDependency {
4141
val groupId: String
4242
val artifactId: String
4343
val version: String
44+
val variants: Set<String>
4445
val classifier: String
4546
val extension: String
4647
val dependencies: List<OrtDependency>

plugins/package-managers/gradle-plugin/src/main/kotlin/OrtModelBuilder.kt

+2
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ internal class OrtModelBuilder : ToolingModelBuilder {
223223
groupId = id.group,
224224
artifactId = id.module,
225225
version = id.version,
226+
variants = selectedComponent.variants.map { it.displayName }.toSet(),
226227
classifier = "",
227228
extension = modelBuildingResult?.effectiveModel?.packaging.orEmpty(),
228229
dependencies = dependencies,
@@ -252,6 +253,7 @@ internal class OrtModelBuilder : ToolingModelBuilder {
252253
groupId = moduleId.group,
253254
artifactId = moduleId.name,
254255
version = moduleId.version.takeUnless { it == "unspecified" }.orEmpty(),
256+
variants = selectedComponent.variants.map { it.displayName }.toSet(),
255257
classifier = "",
256258
extension = "",
257259
dependencies = dependencies,

plugins/package-managers/gradle-plugin/src/main/kotlin/OrtModelImpl.kt

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ internal class OrtDependencyImpl(
5050
override val artifactId: String,
5151
override val version: String,
5252
override val classifier: String,
53+
override val variants: Set<String>,
5354
override val extension: String,
5455
override val dependencies: List<OrtDependency>,
5556
override val error: String?,

plugins/package-managers/gradle/src/main/resources/init.gradle

+3-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ interface OrtDependency {
7171
String getArtifactId()
7272
String getVersion()
7373
String getClassifier()
74+
Set<String> getVariants()
7475
String getExtension()
7576
List<OrtDependency> getDependencies()
7677
String getError()
@@ -104,6 +105,7 @@ class OrtDependencyImpl implements OrtDependency, Serializable {
104105
String groupId = ''
105106
String artifactId = ''
106107
String version = ''
108+
Set<String> variants = []
107109
String classifier = ''
108110
String extension = ''
109111
List<OrtDependency> dependencies = []
@@ -369,7 +371,7 @@ class AbstractOrtDependencyTreePlugin<T> implements Plugin<T> {
369371
def classifier = artifact?.classifier ?: ''
370372
def extension = artifact?.extension ?: ''
371373

372-
return new OrtDependencyImpl(id.group, id.module, id.version, classifier, extension, dependencies,
374+
return new OrtDependencyImpl(id.group, id.module, id.version, [] as Set, classifier, extension, dependencies,
373375
error, warning, pomFile, null)
374376
} else if (id instanceof ProjectComponentIdentifier) {
375377
if (id.build.isCurrentBuild() || !project.gradle.gradleVersion.isAtLeastVersion(7, 2)) {

0 commit comments

Comments
 (0)