in compat/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/DefaultLegacyArtifactCollector.java [229:563]
private void recurse(
ArtifactResolutionResult result,
ResolutionNode node,
Map<Object, List<ResolutionNode>> resolvedArtifacts,
ManagedVersionMap managedVersions,
ArtifactResolutionRequest request,
ArtifactMetadataSource source,
ArtifactFilter filter,
List<ResolutionListener> listeners,
List<ConflictResolver> conflictResolvers)
throws ArtifactResolutionException {
fireEvent(ResolutionListener.TEST_ARTIFACT, listeners, node);
Object key = node.getKey();
// TODO Does this check need to happen here? Had to add the same call
// below when we iterate on child nodes -- will that suffice?
if (managedVersions.containsKey(key)) {
manageArtifact(node, managedVersions, listeners);
}
List<ResolutionNode> previousNodes = resolvedArtifacts.get(key);
if (previousNodes != null) {
for (ResolutionNode previous : previousNodes) {
try {
if (previous.isActive()) {
// Version mediation
VersionRange previousRange = previous.getArtifact().getVersionRange();
VersionRange currentRange = node.getArtifact().getVersionRange();
if ((previousRange != null) && (currentRange != null)) {
// TODO shouldn't need to double up on this work, only done for simplicity of handling
// recommended
// version but the restriction is identical
VersionRange newRange = previousRange.restrict(currentRange);
// TODO ick. this forces the OCE that should have come from the previous call. It is still
// correct
if (newRange.isSelectedVersionKnown(previous.getArtifact())) {
fireEvent(
ResolutionListener.RESTRICT_RANGE,
listeners,
node,
previous.getArtifact(),
newRange);
}
previous.getArtifact().setVersionRange(newRange);
node.getArtifact().setVersionRange(currentRange.restrict(previousRange));
// Select an appropriate available version from the (now restricted) range
// Note this version was selected before to get the appropriate POM
// But it was reset by the call to setVersionRange on restricting the version
ResolutionNode[] resetNodes = {previous, node};
for (int j = 0; j < 2; j++) {
Artifact resetArtifact = resetNodes[j].getArtifact();
// MNG-2123: if the previous node was not a range, then it wouldn't have any available
// versions. We just clobbered the selected version above. (why? I have no idea.)
// So since we are here and this is ranges we must go figure out the version (for a
// third time...)
if (resetArtifact.getVersion() == null && resetArtifact.getVersionRange() != null) {
// go find the version. This is a total hack. See previous comment.
List<ArtifactVersion> versions = resetArtifact.getAvailableVersions();
if (versions == null) {
try {
MetadataResolutionRequest metadataRequest =
new DefaultMetadataResolutionRequest(request);
metadataRequest.setArtifact(resetArtifact);
versions = source.retrieveAvailableVersions(metadataRequest);
resetArtifact.setAvailableVersions(versions);
} catch (ArtifactMetadataRetrievalException e) {
resetArtifact.setDependencyTrail(node.getDependencyTrail());
throw new ArtifactResolutionException(
"Unable to get dependency information: " + e.getMessage(),
resetArtifact,
request.getRemoteRepositories(),
e);
}
}
// end hack
// MNG-2861: match version can return null
ArtifactVersion selectedVersion = resetArtifact
.getVersionRange()
.matchVersion(resetArtifact.getAvailableVersions());
if (selectedVersion != null) {
resetArtifact.selectVersion(selectedVersion.toString());
} else {
throw new OverConstrainedVersionException(
"Unable to find a version in " + resetArtifact.getAvailableVersions()
+ " to match the range " + resetArtifact.getVersionRange(),
resetArtifact);
}
fireEvent(ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, resetNodes[j]);
}
}
}
// Conflict Resolution
ResolutionNode resolved = null;
for (Iterator<ConflictResolver> j = conflictResolvers.iterator();
resolved == null && j.hasNext(); ) {
ConflictResolver conflictResolver = j.next();
resolved = conflictResolver.resolveConflict(previous, node);
}
if (resolved == null) {
// TODO add better exception that can detail the two conflicting artifacts
ArtifactResolutionException are = new ArtifactResolutionException(
"Cannot resolve artifact version conflict between "
+ previous.getArtifact().getVersion() + " and "
+ node.getArtifact().getVersion(),
previous.getArtifact());
result.addVersionRangeViolation(are);
}
if ((resolved != previous) && (resolved != node)) {
// TODO add better exception
result.addVersionRangeViolation(new ArtifactResolutionException(
"Conflict resolver returned unknown resolution node: ", resolved.getArtifact()));
}
// TODO should this be part of mediation?
// previous one is more dominant
ResolutionNode nearest;
ResolutionNode farthest;
if (resolved == previous) {
nearest = previous;
farthest = node;
} else {
nearest = node;
farthest = previous;
}
if (checkScopeUpdate(farthest, nearest, listeners)) {
// if we need to update artifactScope of nearest to use farthest artifactScope, use the
// nearest version, but farthest artifactScope
nearest.disable();
farthest.getArtifact()
.setVersion(nearest.getArtifact().getVersion());
fireEvent(ResolutionListener.OMIT_FOR_NEARER, listeners, nearest, farthest.getArtifact());
} else {
farthest.disable();
fireEvent(ResolutionListener.OMIT_FOR_NEARER, listeners, farthest, nearest.getArtifact());
}
}
} catch (OverConstrainedVersionException e) {
result.addVersionRangeViolation(e);
}
}
} else {
previousNodes = new ArrayList<>();
resolvedArtifacts.put(key, previousNodes);
}
previousNodes.add(node);
if (node.isActive()) {
fireEvent(ResolutionListener.INCLUDE_ARTIFACT, listeners, node);
}
// don't pull in the transitive deps of a system-scoped dependency.
if (node.isActive() && !Artifact.SCOPE_SYSTEM.equals(node.getArtifact().getScope())) {
fireEvent(ResolutionListener.PROCESS_CHILDREN, listeners, node);
Artifact parentArtifact = node.getArtifact();
for (Iterator<ResolutionNode> i = node.getChildrenIterator(); i.hasNext(); ) {
ResolutionNode child = i.next();
try {
// We leave in optional ones, but don't pick up its dependencies
if (!child.isResolved() && (!child.getArtifact().isOptional() || child.isChildOfRootNode())) {
Artifact artifact = child.getArtifact();
artifact.setDependencyTrail(node.getDependencyTrail());
List<ArtifactRepository> childRemoteRepositories = child.getRemoteRepositories();
MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest(request);
metadataRequest.setArtifact(artifact);
metadataRequest.setRemoteRepositories(childRemoteRepositories);
try {
ResolutionGroup rGroup;
Object childKey;
do {
childKey = child.getKey();
if (managedVersions.containsKey(childKey)) {
// If this child node is a managed dependency, ensure
// we are using the dependency management version
// of this child if applicable b/c we want to use the
// managed version's POM, *not* any other version's POM.
// We retrieve the POM below in the retrieval step.
manageArtifact(child, managedVersions, listeners);
// Also, we need to ensure that any exclusions it presents are
// added to the artifact before we retrieve the metadata
// for the artifact; otherwise we may end up with unwanted
// dependencies.
Artifact ma = managedVersions.get(childKey);
ArtifactFilter managedExclusionFilter = ma.getDependencyFilter();
if (null != managedExclusionFilter) {
if (null != artifact.getDependencyFilter()) {
AndArtifactFilter aaf = new AndArtifactFilter();
aaf.add(artifact.getDependencyFilter());
aaf.add(managedExclusionFilter);
artifact.setDependencyFilter(aaf);
} else {
artifact.setDependencyFilter(managedExclusionFilter);
}
}
}
if (artifact.getVersion() == null) {
// set the recommended version
// TODO maybe its better to just pass the range through to retrieval and use a
// transformation?
ArtifactVersion version;
if (!artifact.isSelectedVersionKnown()) {
List<ArtifactVersion> versions = artifact.getAvailableVersions();
if (versions == null) {
versions = source.retrieveAvailableVersions(metadataRequest);
artifact.setAvailableVersions(versions);
}
Collections.sort(versions);
VersionRange versionRange = artifact.getVersionRange();
version = versionRange.matchVersion(versions);
if (version == null) {
if (versions.isEmpty()) {
throw new OverConstrainedVersionException(
"No versions are present in the repository for the artifact"
+ " with a range " + versionRange,
artifact,
childRemoteRepositories);
}
throw new OverConstrainedVersionException(
"Couldn't find a version in " + versions + " to match range "
+ versionRange,
artifact,
childRemoteRepositories);
}
} else {
version = artifact.getSelectedVersion();
}
artifact.selectVersion(version.toString());
fireEvent(ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, child);
}
rGroup = source.retrieve(metadataRequest);
if (rGroup == null) {
break;
}
} while (!childKey.equals(child.getKey()));
if (parentArtifact != null
&& parentArtifact.getDependencyFilter() != null
&& !parentArtifact.getDependencyFilter().include(artifact)) {
// MNG-3769: the [probably relocated] artifact is excluded.
// We could process exclusions on relocated artifact details in the
// MavenMetadataSource.createArtifacts(..) step, BUT that would
// require resolving the POM from the repository very early on in
// the build.
continue;
}
// TODO might be better to have source.retrieve() throw a specific exception for this
// situation
// and catch here rather than have it return null
if (rGroup == null) {
// relocated dependency artifact is declared excluded, no need to add and recurse
// further
continue;
}
child.addDependencies(rGroup.getArtifacts(), rGroup.getResolutionRepositories(), filter);
} catch (CyclicDependencyException e) {
// would like to throw this, but we have crappy stuff in the repo
fireEvent(
ResolutionListener.OMIT_FOR_CYCLE,
listeners,
new ResolutionNode(e.getArtifact(), childRemoteRepositories, child));
} catch (ArtifactMetadataRetrievalException e) {
artifact.setDependencyTrail(node.getDependencyTrail());
throw new ArtifactResolutionException(
"Unable to get dependency information for " + artifact.getId() + ": "
+ e.getMessage(),
artifact,
childRemoteRepositories,
e);
}
ArtifactResolutionRequest subRequest = new ArtifactResolutionRequest(metadataRequest);
subRequest.setServers(request.getServers());
subRequest.setMirrors(request.getMirrors());
subRequest.setProxies(request.getProxies());
recurse(
result,
child,
resolvedArtifacts,
managedVersions,
subRequest,
source,
filter,
listeners,
conflictResolvers);
}
} catch (OverConstrainedVersionException e) {
result.addVersionRangeViolation(e);
} catch (ArtifactResolutionException e) {
result.addMetadataResolutionException(e);
}
}
fireEvent(ResolutionListener.FINISH_PROCESSING_CHILDREN, listeners, node);
}
}