[ 
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 artifacts with 
versions discovered (by VersionRangeResolver), 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), the BF explicitly sorts versions in descending 
order (to maximize skipper effect, but that is BF internal detail).

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, but new BF explicitly 
sorts versions in descending order to better utilize it's own internals).

Proper solution should be:
 * insensitive on version ordering
 * produce "stable" (same) output for same input (version order should not 
matter, and this is not only about DF vs BF)
 * 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 (the first in order, 
this is the problem) that holds conflict information.
 * Better to have: We may want a "full" verbose mode, where {*}node 
selection/elimination and mediation is done{*}, but *no node was removed* graph 
still contains all the nodes, as that would give much more precise picture 
about dependencies, than like today, "randomly" (first) nodes marked for 
conflict, rest removed.

  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 artifacts with 
versions discovered (by VersionRangeResolver), 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), the BF explicitly sorts versions in descending 
order (to maximize skipper effect, but that is BF internal detail).

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, but new BF explicitly 
sorts versions in descending order to better utilize it's own internals).

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.


> 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 artifacts with 
> versions discovered (by VersionRangeResolver), 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), the BF explicitly sorts versions in descending 
> order (to maximize skipper effect, but that is BF internal detail).
> 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, but new BF explicitly 
> sorts versions in descending order to better utilize it's own internals).
> Proper solution should be:
>  * insensitive on version ordering
>  * produce "stable" (same) output for same input (version order should not 
> matter, and this is not only about DF vs BF)
>  * 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 (the first in 
> order, this is the problem) that holds conflict information.
>  * Better to have: We may want a "full" verbose mode, where {*}node 
> selection/elimination and mediation is done{*}, but *no node was removed* 
> graph still contains all the nodes, as that would give much more precise 
> picture about dependencies, than like today, "randomly" (first) nodes marked 
> for conflict, rest removed.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to