Howdy,

:beer: (or any other award you'd like, :wine:?)

Thanks for spotting and reporting this. Yes, there is a problem.

Created issue
https://issues.apache.org/jira/browse/MRESOLVER-357

In short, the problem lies here:
https://github.com/apache/maven-resolver/blob/maven-resolver-1.9.9/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java#L344-L366

The comment even "promises" that it will "leave only 1 loser" but the code
does not fulfil this promise.


Thanks
T

On Fri, Apr 28, 2023 at 9:59 AM Alexey Venderov <avende...@gmail.com> wrote:

> Tamás,
>
> Thank you for the detailed explanation!
>
> One more question regarding the verbose mode in the old implementation vs.
> the new implementation. I have this simple project
> https://github.com/c00ler/simple-maven-project/tree/verbose-graph (all the
> relevant code in the verbose-graph branch) where I override the version of
> the junit-jupiter-params dependency
>
> https://github.com/c00ler/simple-maven-project/blob/verbose-graph/pom.xml#L42
> .
> When I check its dependency tree using Maven 3.9.1 and Maven 4.0.0-SNAPSHOT
> in the verbose mode I get slightly different results.
>
> Maven 3.9.1 (Maven 4.0.0-alpha-5 produces the same result) gives:
>
>  09:18:20 ➜ ./mvnw dependency:tree -D*aether.conflictResolver.verbose=true*
> [INFO] Scanning for projects...
> [INFO]
> [INFO] -------------< com.github.avenderov:simple-maven-project
> >--------------
> [INFO] Building simple-maven-project 1.0-SNAPSHOT
> [INFO]   from pom.xml
> [INFO] --------------------------------[ jar
> ]---------------------------------
> [INFO]
> [INFO] --- dependency:3.5.0:tree (default-cli) @ simple-maven-project ---
> [INFO] com.github.avenderov:simple-maven-project:jar:1.0-SNAPSHOT
> [INFO] +- org.junit.jupiter:junit-jupiter:jar:5.9.1:test
> [INFO] |  +- org.junit.jupiter:junit-jupiter-api:jar:5.9.1:test
> [INFO] |  |  +- org.opentest4j:opentest4j:jar:1.2.0:test
> [INFO] |  |  +- org.junit.platform:junit-platform-commons:jar:1.9.1:test
> [INFO] |  |  |  \- org.apiguardian:apiguardian-api:jar:1.1.2:test
> [INFO] |  |  \- org.apiguardian:apiguardian-api:jar:1.1.2:test
> [INFO] |  +- *org.junit.jupiter:junit-jupiter-params:jar:5.9.1:test*
> [INFO] |  \- org.junit.jupiter:junit-jupiter-engine:jar:5.9.1:test
> [INFO] |     +- org.junit.platform:junit-platform-engine:jar:1.9.1:test
> [INFO] |     |  +- org.opentest4j:opentest4j:jar:1.2.0:test
> [INFO] |     |  +- org.junit.platform:junit-platform-commons:jar:1.9.1:test
> [INFO] |     |  \- org.apiguardian:apiguardian-api:jar:1.1.2:test
> [INFO] |     +- org.junit.jupiter:junit-jupiter-api:jar:5.9.1:test
> [INFO] |     \- org.apiguardian:apiguardian-api:jar:1.1.2:test
> [INFO] \- *org.junit.jupiter:junit-jupiter-params:jar:5.9.3:test*
> [INFO]    +- org.junit.jupiter:junit-jupiter-api:jar:5.9.1:test
> [INFO]    \- org.apiguardian:apiguardian-api:jar:1.1.2:test
> [INFO]
> ------------------------------------------------------------------------
> [INFO] BUILD SUCCESS
> [INFO]
> ------------------------------------------------------------------------
> [INFO] Total time:  0.531 s
> [INFO] Finished at: 2023-04-28T09:18:38+02:00
> [INFO]
> ------------------------------------------------------------------------
>
> Maven 4.0.0-SNAPSHOT gives:
>
> 09:18:38 ➜
> /Users/avenderov/tmp/maven/dist/apache-maven-4.0.0-SNAPSHOT/bin/mvn
> dependency:tree -D*aether.conflictResolver.verbose=true*
> -Dmaven.plugin.validation=disabled
> [INFO] Scanning for projects...
> [INFO]
> [INFO] --------------------------------------<
> com.github.avenderov:simple-maven-project
> >---------------------------------------
> [INFO] Building simple-maven-project 1.0-SNAPSHOT
> [INFO]   from pom.xml
> [INFO] ---------------------------------------------------------[ jar
> ]----------------------------------------------------------
> [INFO]
> [INFO] --- dependency:3.5.0:tree (default-cli) @ simple-maven-project ---
> [INFO] com.github.avenderov:simple-maven-project:jar:1.0-SNAPSHOT
> [INFO] +- org.junit.jupiter:junit-jupiter:jar:5.9.1:test
> [INFO] |  +- org.junit.jupiter:junit-jupiter-api:jar:5.9.1:test
> [INFO] |  |  +- org.opentest4j:opentest4j:jar:1.2.0:test
> [INFO] |  |  +- org.junit.platform:junit-platform-commons:jar:1.9.1:test
> [INFO] |  |  |  \- org.apiguardian:apiguardian-api:jar:1.1.2:test
> [INFO] |  |  \- org.apiguardian:apiguardian-api:jar:1.1.2:test
> [INFO] |  \- org.junit.jupiter:junit-jupiter-engine:jar:5.9.1:test
> [INFO] |     +- org.junit.platform:junit-platform-engine:jar:1.9.1:test
> [INFO] |     |  +- org.opentest4j:opentest4j:jar:1.2.0:test
> [INFO] |     |  +- org.junit.platform:junit-platform-commons:jar:1.9.1:test
> [INFO] |     |  \- org.apiguardian:apiguardian-api:jar:1.1.2:test
> [INFO] |     +- org.junit.jupiter:junit-jupiter-api:jar:5.9.1:test
> [INFO] |     \- org.apiguardian:apiguardian-api:jar:1.1.2:test
> [INFO] \- *org.junit.jupiter:junit-jupiter-params:jar:5.9.3:test*
> [INFO]    +- org.junit.jupiter:junit-jupiter-api:jar:5.9.1:test
> [INFO]    \- org.apiguardian:apiguardian-api:jar:1.1.2:test
> [INFO]
>
> --------------------------------------------------------------------------------------------------------------------------
> [INFO] BUILD SUCCESS
> [INFO]
>
> --------------------------------------------------------------------------------------------------------------------------
> [INFO] Total time:  0.625 s
> [INFO] Finished at: 2023-04-28T09:19:10+02:00
> [INFO]
>
> --------------------------------------------------------------------------------------------------------------------------
> [WARNING]
> [WARNING] Plugin validation issues were detected in 1 plugin(s)
> [WARNING]
>
> As can be seen, the output from the Maven 4.0.0-SNAPSHOT does not include
> the node org.junit.jupiter:junit-jupiter-params:jar:5.9.1:test. This is why
> I assumed the new STANDARD mode doesn't fully match the pre-1.9.8 true
> mode.
>
> Best regards,
> Alexey Venderov
> mailto: avende...@gmail.com
>
>
> On Tue, Apr 25, 2023 at 4:11 PM Tamás Cservenák <ta...@cservenak.net>
> wrote:
>
> > Sorry, series of lapsues:
> > so, verbose modes are: NONE, STANDARD and FULL.
> >
> > Wherever I wrote "DEFAULT" I meant "STANDARD" instead.
> >
> > The enum in question:
> >
> >     /**
> >      * The enum representing verbosity levels of conflict resolver.
> >      *
> >      * @since 1.9.8
> >      */
> >     public enum Verbosity {
> >         /**
> >          * Verbosity level to be used in all "common" resolving use cases
> > (ie. dependencies to build class path). The
> >          * {@link ConflictResolver} in this mode will trim down the graph
> > to the barest minimum: will not leave
> >          * any conflicting node in place, hence no conflicts will be
> > present in transformed graph either.
> >          */
> >         NONE,
> >
> >         /**
> >          * Verbosity level to be used in "analyze" resolving use cases
> (ie.
> > dependency convergence calculations). The
> >          * {@link ConflictResolver} in this mode will remove any
> redundant
> > collected nodes, in turn it will leave one
> >          * with recorded conflicting information. This mode corresponds
> to
> > "classic verbose" mode when
> >          * {@link #CONFIG_PROP_VERBOSE} was set to {@code true}.
> Obviously,
> > the resulting dependency tree is not
> >          * suitable for artifact resolution unless a filter is employed
> to
> > exclude the duplicate dependencies.
> >          */
> >         STANDARD,
> >
> >         /**
> >          * Verbosity level to be used in "analyze" resolving use cases
> (ie.
> > dependency convergence calculations). The
> >          * {@link ConflictResolver} in this mode will not remove any
> > collected node, in turn it will record on all
> >          * eliminated nodes the conflicting information. Obviously, the
> > resulting dependency tree is not suitable
> >          * for artifact resolution unless a filter is employed to exclude
> > the duplicate dependencies.
> >          */
> >         FULL
> >     }
> >
> > On Tue, Apr 25, 2023 at 4:04 PM Tamás Cservenák <ta...@cservenak.net>
> > wrote:
> >
> > > Howdy,
> > >
> > > 1. Historically (and today) users (and client code needing verbose
> tree,
> > > like enforcer convergence rule) sets
> > >
> > > `aether.conflictResolver.verbose=true`
> > >
> > > in config properties of resolver session. Again, as this may happen by
> > > user on CLI, or in code, like plugins, this part is unchanged.
> > > And as you say, `aether.conflictResolver.verbose=true` means
> > > Verbosity.DEFAULT, so "DEFAULT" is what in pre 1.9.8 releaser was
> > > `aether.conflictResolver.verbose=true`. No change here.
> > >
> > > 2. I did not want to change/alter the "surface", so even the doco
> > > https://maven.apache.org/resolver/configuration.html still states:
> > > "aether.conflictResolver.verbose | boolean | Flag controlling the
> > conflict
> > > resolver's verbose mode."
> > >
> > > 3. The difference between Verbosity.DEFAULT and Verbosity.FULL really
> > > matters ONLY when you have version ranges downstream (in the transitive
> > > hull).
> > > Otherwise the output of two Verbosity modes does not differ.
> > > Modes are:
> > > (pre 1.9.8 mode) NONE -- conflicted nodes are removed
> > > (pre 1.9.8 mode) DEFAULT -- GA[V1-Vn]s are made "unique" (one left,
> > others
> > > removed), but GA[V1-Vn] may happen only IF there is version range
> > > downstream (and version ranges are currently implemented in collector
> > where
> > > "one node is exploded into discovered/versionFiltered nodes" -> hence
> you
> > > end up with GA[V1-Vn]).
> > > (new mode in 1.9.8) FULL -- nothing is removed from "ditty tree" (but
> ALL
> > > conflicted nodes are marked as "conflicted")
> > >
> > > Hopefully javadoc explains it
> > >
> >
> https://github.com/apache/maven-resolver/blob/master/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java#L70
> > >
> > > 4. To be frank, the "FULL" mode was handy while fixing
> > > https://issues.apache.org/jira/browse/MRESOLVER-345
> > > but in general I did not mean it as some "new feature" thing (hence the
> > > doco did not change either). I just did not want to "throw away" all
> this
> > > execution path that did come handy to fix MRESOLVER-345 and may come
> > handy
> > > later for some other bug as well.
> > >
> > > 5. Finally, as I could not inspect ALL the code out there asking for
> > > "verbose" graph, I just went on safe side, and did not want to
> introduce
> > > any (potential breaking) change, that existing code could choke on: for
> > > example, existing code so far got one GAV, I could not guarantee it
> would
> > > not choke if the code would get GA[V1-Vn] instead, hence, the "default
> > > verbose mode" is "STANDARD" -- same behaviour as it was before the
> > change.
> > > Basically the commit did not introduce any change, resolver still
> behaves
> > > same as pre-1.9.8 versions regarding `aether.conflictResolver.verbose`
> > > configuration.
> > >
> > > HTH
> > > Tamas
> > >
> > > On Tue, Apr 25, 2023 at 9:52 AM Alexey Venderov <avende...@gmail.com>
> > > wrote:
> > >
> > >> Hi,
> > >>
> > >> I have a couple of questions regarding the recent changes to how
> > >> *aether.conflictResolver.verbose* property is set:
> > >>
> > >>
> >
> https://github.com/apache/maven-resolver/blob/master/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java#L106
> > >> .
> > >>
> > >> 1. To be able to set the verbosity level to *Verbosity.FULL* the
> client
> > >> code needs to have the maven-resolver 1.9.8 in their classpath, to
> have
> > an
> > >> access to the Verbosity enum. Also, that means that it's not possible
> to
> > >> use system properties to set the verbosity level to *Verbosity.FULL*.
> > >> Wouldn't it be better to check if the string property value contains
> any
> > >> Verbosity enum constant? Something along these lines:
> > >>
> > >>     private static Verbosity getVerbosity(RepositorySystemSession
> > >> session) {
> > >>         final Object verbosityValue =
> > >> session.getConfigProperties().get(CONFIG_PROP_VERBOSE);
> > >>         if (verbosityValue instanceof Boolean) {
> > >>             return (Boolean) verbosityValue ? Verbosity.STANDARD :
> > >> Verbosity.NONE;
> > >>         } else if (verbosityValue instanceof String) {
> > >>             String verbosityStringValue = verbosityValue.toString();
> > >>             for (Verbosity verbosity : Verbosity.values()) {
> > >>                 if (verbosity.name
> > >> ().equalsIgnoreCase(verbosityStringValue))
> > >> {
> > >>                     return verbosity;
> > >>                 }
> > >>             }
> > >>             return Boolean.parseBoolean(verbosityStringValue) ?
> > >> Verbosity.STANDARD : Verbosity.NONE;
> > >>         } else if (verbosityValue != null) {
> > >>             throw new IllegalArgumentException("Unsupported Verbosity
> > >> configuration: " + verbosityValue);
> > >>         }
> > >>         return Verbosity.NONE;
> > >>     }
> > >>
> > >> 2. I'm not sure that I fully understand why the old *true* value is
> > mapped
> > >> to the new *Verbosity.STANDARD* value and not *Verbosity.FULL*. Isn't
> > it a
> > >> backward incompatible change? When verbosity was set to *true* the old
> > >> implementation was not doing any deletions of the nodes, while the new
> > >> implementation is doing some cleaning of the graph when verbosity is
> set
> > >> to
> > >> *Verbosity.STANDARD*.
> > >>
> > >> Thank you!
> > >>
> > >> Best regards,
> > >> Alexey Venderov
> > >> mailto: avende...@gmail.com
> > >>
> > >
> >
>

Reply via email to