Skip to content

Commit

Permalink
[MRESOLVER-289][MRESOLVER-526] Reuse relevant bits from Eclipse Aethe…
Browse files Browse the repository at this point in the history
…r wiki contents (#496)

With applied updates for Resolver 2.0.

Reworked side menu:
* Overview (as before)
* Guides (added)
* Reference (added)
* See also (as before)

Content from EOLd Eclipse wiki https://wiki.eclipse.org/Aether The dump is attached to MRESOLVER-526 but is filtered (outdated pages omitted) as explained on issue.

---

https://issues.apache.org/jira/browse/MRESOLVER-526
https://issues.apache.org/jira/browse/MRESOLVER-289
  • Loading branch information
cstamas authored May 23, 2024
1 parent 2505793 commit 0320c86
Show file tree
Hide file tree
Showing 8 changed files with 481 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/site/markdown/about-checksums.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# About Checksums
# Checksums
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
Expand Down
61 changes: 61 additions & 0 deletions src/site/markdown/creating-a-repository-system-session.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Creating a RepositorySystemSession
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

Resolver (former Aether) and its components are designed to be stateless and as such all
configuration/state has to be passed into the methods. When one makes
multiple requests to resolve dependencies, a fair amount of settings
usually remains the same across these method calls, like the proxy
settings or the path to the local repository. Those settings that tend
to be the same for an entire usage session of the repository system are
represented by an instance of
`org.eclipse.aether.RepositorySystemSession`. Using classes from
`maven-resolver-supplier`, creating such a session that mimics Maven's
setup can be done like this:

```java
import org.eclipse.aether.supplier.RepositorySystemSupplier;

...
private static RepositorySystemSession newSession( RepositorySystem system )
{
RepositorySystemSession.SessionBuilder sessionBuilder = SessionBuilderSupplier.get();

LocalRepository localRepo = new LocalRepository( "target/local-repo" );
sessionBuilder.setLocalRepositoryManager( system.newLocalRepositoryManager( session, localRepo ) );

return session.build();
}
```

As you see, the only setting that must be specified is the local
repository, other settings are initialized with default values. Please
have a look at the API docs for `RepositorySystemSession.SessionBuilder` to
learn about all the other things you can configure for a session.

In case of Maven plugin, or when code runs embedded in Maven, the session
is already created for you, but you can still "derive" using copy constructor
of `DefaultRepositorySystemSession` if some session alteration is needed.

If you seek a closer cooperation with [Apache
Maven](http://maven.apache.org/) and want to read configuration from the
user's `settings.xml`, you should have a look at the library
[MIMA](https://github.com/maveniverse/mima) which provides the necessary
bits. Please direct any questions regarding usage of that library to the
Maven mailing list.
82 changes: 82 additions & 0 deletions src/site/markdown/dependency-graph.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Dependency Graph
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

When resolving transitive dependencies, Resolver (former Aether) constructs a *dependency
graph* consisting of `DependencyNode` instances where each node
represents a dependency and its direct dependencies are represented as
child nodes. During early stages of the resolution process, there are
usually duplicate dependencies or even cycles in the graph as sketched
below:

```
root
/ \
/ \
a:1 b:1 <--+
\ / \ |
\ / \ |
c:1 a:2 |
| |
+---------+
```

Once this dependency graph has undergone conflict resolution, i.e.
duplicate dependencies have been removed, one actually has a *dependency
tree*. Taking the previous example, the tree might look like this:

```
root
/ \
/ \
a:1 b:1
|
|
c:1
```

The dependency tree is a handy data structure to get the complete set of
artifacts one would need to form a classpath etc. as a simple recursive
traversal is sufficient to gather the relevant dependencies.

## Troubleshooting a Dependency Graph

The dependency tree provides a compact and basic means to end users to
understand why/how a given artifact ended up among the dependencies. But
as the examples above illustrate, the dependency tree misses some
information compared to the dependency graph. For instance, the tree
does not indicate that `b:1` also depends on `c:1`. To help
troubleshooting complex dependency graphs, some configuration properties
exist to keep useful data in the dependency graph returned by
`RepositorySystem.collectDependencies()`.

For instance, the configuration property
`ConflictResolver.CONFIG_PROP_VERBOSE` can be enabled to produce a graph
similar to m2e's dependency hierarchy view where conflicting nodes are
retained. This gives end users a better understanding of all the paths
that pull in a given dependency.

The configuration property `DependencyManagerUtils.CONFIG_PROP_VERBOSE`
can be enabled to record the attributes of a dependency before they were
updated due to dependency management. This helps end users to understand
why one version of a dependency and not the other is found in the graph
or why a dependency ended up in a given scope.

Please see the API docs for said configuration properties for details
regarding their effects and ways to access the additional data.
62 changes: 62 additions & 0 deletions src/site/markdown/resolving-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Resolving Dependencies
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

Extending the code snippets from [Creating a RepositorySystemSession](creating-a-repository-system-session.html), the snippet below demonstrates
how to actually resolve the transitive dependencies of say
`org.apache.maven:maven-core:3.9.6` and to dump the result as a class
path to the console:

```java
public static void main( String[] args )
throws Exception
{
RepositorySystem repoSystem = newRepositorySystem();

RepositorySystemSession session = newSession( repoSystem );

Dependency dependency =
new Dependency( new DefaultArtifact( "org.apache.maven:maven-core:3.9.6" ), "compile" );
RemoteRepository central = new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2/" ).build();

CollectRequest collectRequest = new CollectRequest();
collectRequest.setRoot( dependency );
collectRequest.addRepository( central );
DependencyNode node = repoSystem.collectDependencies( session, collectRequest ).getRoot();

DependencyRequest dependencyRequest = new DependencyRequest();
dependencyRequest.setRoot( node );

repoSystem.resolveDependencies( session, dependencyRequest );

PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
node.accept( nlg );
System.out.println( nlg.getClassPath() );
}
```

So once you have initialized the repository system and created a
session, the general pattern is to create some request object, call its
setters to configure the request, do the operation and evaluate the
result object.

Since "all theory is grey", we maintain some runnable
[examples and demos](https://github.com/apache/maven-resolver/tree/master/maven-resolver-demos) among
our sources. These examples provide a more extensive demonstration of
Resolver and its use, so what are you waiting for?
88 changes: 88 additions & 0 deletions src/site/markdown/transitive-dependency-resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Transitive Dependency Resolution
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

An important task of Resolver (former Aether) is to resolve transitive dependencies. This
task can be split into two sub-tasks:

1. Determine the coordinates of the artifacts that make up the
transitive dependencies.
2. Resolve the files for the artifacts that have been identified in
step 1.

Artifacts and their dependencies among each other form a *[dependency graph](dependency-graph.html)*. So in other
words, step 1 means to calculate this dependency graph and step 2 is a
simple graph traversal that fetches the file for each artifact in the
dependency graph. In Resolver, this dependency graph can be easily
inspected and extension points are provided to allow for more control
over the construction of the dependency graph. To understand those
extension points, we will have a closer look at the way the dependency
graph is constructed.

Starting from a given root dependency like
`org.eclipse.aether:aether-impl:0.9.0`, the repository system first
reads the corresponding *artifact descriptor* (i.e. the POM when dealing
with Maven repositories). The artifact descriptor tells about direct
dependencies, dependency management and additional remote repositories
to consider during the resolution. For each direct dependency, a
*dependency selector* is given a chance to exclude the dependency from
the graph. If the dependency is included, a *dependency manager* applies
dependency management (if any). Next, the declared dependency version is
expanded to a list of matching versions from the repositories. For a
simple version like "1.0", the resulting list contains only that
version. For a version range like "\[1.0,2.0)", the version list
generally contains multiple versions and is subject to filtering by a
*version filter*. For each matching version of the dependency, a child
node is added to the dependency graph. Recursion of the process for each
child dependency is controlled by a *dependency traverser*.

The above process creates a dependency graph that often contains
duplicate or conflicting dependencies or even cycles and as such is
called a *dirty graph*. A chain of *dependency graph transformers* is
then used to trim this graph down and to form a *resolved graph*.

So more technically, the dependency graph that the repository system
returns to its caller is affected by instances of
`org.eclipse.aether.collection.DependencySelector`,
`org.eclipse.aether.collection.DependencyManager`,
`org.eclipse.aether.collection.VersionFilter`,
`org.eclipse.aether.collection.DependencyTraverser` and
`org.eclipse.aether.collection.DependencyGraphTransformer`. Users of the
repository system can directly control those extension points when
creating the repository system session by providing implementations that
fit their needs.

For example, a dependency selector can process exclusions on child
dependencies, exclude optional dependencies or dependencies with certain
unwanted scopes. A dependency traverser can be used to decide whether
the dependencies of a (fat) WAR should be included in the dependency
graph or not. The version filter can exclude specific versions of an
artifact which are unacceptable in the current context, e.g. ban
snapshots. Dependency graph transformers can identify and mark
conflicting nodes in the dirty tree and resolve conflicting versions or
scopes by pruning unwanted parts from the graph.

Several classes from `maven-resolver-provider` helps to construct a
session that mimics the resolution rules used by Maven. In
case you want to customize the graph construction, feel free to have a
look at the source of that class to learn about the implementation
classes being used there to achieve Maven style behavior, you might want
to reuse some of those for your own repository system session as well.
Maven plugins can easily get access to the current repository system
session via the usual parameter injection, see for the actual code bits.
Loading

0 comments on commit 0320c86

Please sign in to comment.