[ https://issues.apache.org/jira/browse/MRESOLVER-345?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Tamas Cservenak updated MRESOLVER-345: -------------------------------------- Description: It all started with MENFORCER-426. In short, if we have layout of dependencies like this below (ranges are key here), *conflict resolution in verbose mode* will misbehave, is sensitive on version ordering in the "dirty tree" (collected graph, output of DependencyCollector). {noformat} A -> B -> C[1..2] \--> C[1..2] {noformat} (explained: A depends on B and C[1..2] range, and B depends on C[1..2] as well) As when "dirty tree" is being collected by DependencyCollector (and we have two, old DF and new BF), the ranges are turned into series of discovered (by VersionRangeResolver) versions, so the input above while collecting A from above would yield some tree like this (in this example {{some-group:c:jar}} has versions 1.0 and 2.0 ): {noformat} some-group:a:jar:1.0 [compile] +- some-group:b:jar:1.0 [compile] | +- some-group:c:jar:1.0 [compile] | \- some-group:c:jar:2.0 [compile] +- some-group:c:jar:1.0 [compile] \- some-group:c:jar:2.0 [compile] {noformat} This "dirty tree" is then transformed using {{ConflictResolver}} into final graph. Conflict resolver in "normal" mode works OK and produces stable outputs, that is not sensitive to ordering, this is OK. But, conflict resolver supports so called "verbose" mode as well, mostly used to perform some "analysis" on graph (like for example "dependency convergence" is). Conflict resolver in "verbose" mode {*}is version ordering sensitive{*}. Conflict resolver in "verbose" mode would transform that dirty tree above into this: {noformat} some-group:a:jar:1.0 [compile] +- some-group:b:jar:1.0 [compile] | \- some-group:c:jar:1.0 [compile] (conflicts 2.0) \- some-group:c:jar:2.0 [compile] {noformat} And for analysis like "dependency convergence", this would mean *divergency is found* (error condition), as there are conflicts. But, if you look more closely on input "dirty tree", you can notice that {{b}} depends on {{c:2.0}} as well (as b depends on range {{{}[1,2]{}}}. Moreover, that dirty tree above is output of resolver standard DF collector. BF on the other hand, produces dirty tree like this: {noformat} some-group:a:jar:1.0 [compile] +- some-group:b:jar:1.0 [compile] | +- some-group:c:jar:2.0 [compile] | \- some-group:c:jar:1.0 [compile] +- some-group:c:jar:2.0 [compile] \- some-group:c:jar:1.0 [compile] {noformat} (the order of c dependencies are sorted descending). In other words, DF produces tree with versions in order as discovered (essentially metadata based), while BF explicitly sorts versions in descending order (to maximize skipper effect). Same conflict resolver in "verbose" mode transforms BF dirty tree into this: {noformat} some-group:a:jar:1.0 [compile] +- some-group:b:jar:1.0 [compile] | \- some-group:c:jar:2.0 [compile] \- some-group:c:jar:2.0 [compile] {noformat} And in this case, {*}there is no divergence found{*}. Again, this is same input, but collected with DF and BF collectors, then applied conflict resolution, and once we have divergence, and once we have no divergence. The difference between two inputs is only the order of versions (produced from discovered versions that were resolved from metadata). Proper solution should be: * insensitive on version ordering * produce "stable" (same) output for same input (so DF vs BF vs something else should not matter) * Good to have: the "verbose" mode we currently have is half-assed, in a way, *it still removes nodes* from tree, and leaves one version that holds conflict information. We may want a "full" verbose mode, where {*}node selection/elimination and mediation is done{*}, but graph still contains all the nodes, as that would give much more precise picture about dependencies, than like today, "randomly" removed nodes with one having conflict information. was: It all started with MENFORCER-426. In short, if we have layout of dependencies like this below (ranges are key here), *conflict resolution in verbose mode* will misbehave, is sensitive on version ordering in the "dirty tree" (collected graph, output of DependencyCollector). {noformat} A -> B -> C[1..2] \--> C[1..2] {noformat} (explained: A depends on B and C[1..2] range, and B depends on C[1..2] as well) As when "dirty tree" is being collected by DependencyCollector (and we have two, old DF and new BF), the ranges are turned into series of discovered (by VersionRangeResolver) versions, so the input above while collecting A from above would yield some tree like this (in this example {{some-group:c:jar}} has versions 1.0 and 2.0 ): {noformat} some-group:a:jar:1.0 [compile] +- some-group:b:jar:1.0 [compile] | +- some-group:c:jar:1.0 [compile] | \- some-group:c:jar:2.0 [compile] +- some-group:c:jar:1.0 [compile] \- some-group:c:jar:2.0 [compile] {noformat} This "dirty tree" is then transformed using {{ConflictResolver}} into final graph. Conflict resolver in "normal" mode works OK and produces stable outputs, that is not sensitive to ordering, this is OK. But, conflict resolver supports so called "verbose" mode as well, mostly used to perform some "analysis" on graph (like for example "dependency convergence" is). Conflict resolver in "verbose" mode {*}is version ordering sensitive{*}. Conflict resolver "verbose" > Conflict resolution in verbose mode is sensitive to version ordering > -------------------------------------------------------------------- > > Key: MRESOLVER-345 > URL: https://issues.apache.org/jira/browse/MRESOLVER-345 > Project: Maven Resolver > Issue Type: Bug > Reporter: Tamas Cservenak > Priority: Major > > It all started with MENFORCER-426. In short, if we have layout of > dependencies like this below (ranges are key here), *conflict resolution in > verbose mode* will misbehave, is sensitive on version ordering in the "dirty > tree" (collected graph, output of DependencyCollector). > {noformat} > A -> B -> C[1..2] > \--> C[1..2] {noformat} > (explained: A depends on B and C[1..2] range, and B depends on C[1..2] as > well) > As when "dirty tree" is being collected by DependencyCollector (and we have > two, old DF and new BF), the ranges are turned into series of discovered (by > VersionRangeResolver) versions, so the input above while collecting A from > above would yield some tree like this (in this example {{some-group:c:jar}} > has versions 1.0 and 2.0 ): > {noformat} > some-group:a:jar:1.0 [compile] > +- some-group:b:jar:1.0 [compile] > | +- some-group:c:jar:1.0 [compile] > | \- some-group:c:jar:2.0 [compile] > +- some-group:c:jar:1.0 [compile] > \- some-group:c:jar:2.0 [compile] {noformat} > This "dirty tree" is then transformed using {{ConflictResolver}} into final > graph. Conflict resolver in "normal" mode works OK and produces stable > outputs, that is not sensitive to ordering, this is OK. > But, conflict resolver supports so called "verbose" mode as well, mostly used > to perform some "analysis" on graph (like for example "dependency > convergence" is). Conflict resolver in "verbose" mode {*}is version ordering > sensitive{*}. > Conflict resolver in "verbose" mode would transform that dirty tree above > into this: > {noformat} > some-group:a:jar:1.0 [compile] > +- some-group:b:jar:1.0 [compile] > | \- some-group:c:jar:1.0 [compile] (conflicts 2.0) > \- some-group:c:jar:2.0 [compile] {noformat} > And for analysis like "dependency convergence", this would mean *divergency > is found* (error condition), as there are conflicts. But, if you look more > closely on input "dirty tree", you can notice that {{b}} depends on {{c:2.0}} > as well (as b depends on range {{{}[1,2]{}}}. > Moreover, that dirty tree above is output of resolver standard DF collector. > BF on the other hand, produces dirty tree like this: > {noformat} > some-group:a:jar:1.0 [compile] > +- some-group:b:jar:1.0 [compile] > | +- some-group:c:jar:2.0 [compile] > | \- some-group:c:jar:1.0 [compile] > +- some-group:c:jar:2.0 [compile] > \- some-group:c:jar:1.0 [compile] {noformat} > (the order of c dependencies are sorted descending). In other words, DF > produces tree with versions in order as discovered (essentially metadata > based), while BF explicitly sorts versions in descending order (to maximize > skipper effect). > Same conflict resolver in "verbose" mode transforms BF dirty tree into this: > {noformat} > some-group:a:jar:1.0 [compile] > +- some-group:b:jar:1.0 [compile] > | \- some-group:c:jar:2.0 [compile] > \- some-group:c:jar:2.0 [compile] {noformat} > And in this case, {*}there is no divergence found{*}. Again, this is same > input, but collected with DF and BF collectors, then applied conflict > resolution, and once we have divergence, and once we have no divergence. The > difference between two inputs is only the order of versions (produced from > discovered versions that were resolved from metadata). > Proper solution should be: > * insensitive on version ordering > * produce "stable" (same) output for same input (so DF vs BF vs something > else should not matter) > * Good to have: the "verbose" mode we currently have is half-assed, in a > way, *it still removes nodes* from tree, and leaves one version that holds > conflict information. We may want a "full" verbose mode, where {*}node > selection/elimination and mediation is done{*}, but graph still contains all > the nodes, as that would give much more precise picture about dependencies, > than like today, "randomly" removed nodes with one having conflict > information. -- This message was sent by Atlassian Jira (v8.20.10#820010)