Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime artifact's POM repos aren't propagated to resolve the deployment deps #3289

Merged
merged 1 commit into from
Jul 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.graph.DependencyVisitor;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactDescriptorResult;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.VersionRangeResult;
Expand Down Expand Up @@ -134,68 +135,15 @@ public AppModel resolveManagedModel(AppArtifact appArtifact, List<AppDependency>

private AppModel doResolveModel(AppArtifact appArtifact, List<Dependency> directMvnDeps, AppArtifact managingProject) throws AppModelResolverException {
List<Dependency> managedDeps = Collections.emptyList();
List<RemoteRepository> managedRepos = Collections.emptyList();
if(managingProject != null) {
managedDeps = mvn.resolveDescriptor(toAetherArtifact(managingProject)).getManagedDependencies();
final ArtifactDescriptorResult managingDescr = mvn.resolveDescriptor(toAetherArtifact(managingProject));
managedDeps = managingDescr.getManagedDependencies();
managedRepos = mvn.newResolutionRepositories(managingDescr.getRepositories());
}
return injectDeploymentDependencies(appArtifact, mvn.resolveManagedDependencies(toAetherArtifact(appArtifact),
directMvnDeps, managedDeps, devmode ? new String[] { "test" } : new String[0]).getRoot(), managedDeps);
}

@Override
public List<String> listLaterVersions(AppArtifact appArtifact, String upToVersion, boolean inclusive) throws AppModelResolverException {
final VersionRangeResult rangeResult = resolveVersionRangeResult(appArtifact, appArtifact.getVersion(), false, upToVersion, inclusive);
final List<Version> resolvedVersions = rangeResult.getVersions();
final List<String> versions = new ArrayList<>(resolvedVersions.size());
for (Version v : resolvedVersions) {
versions.add(v.toString());
}
return versions;
}

@Override
public String getNextVersion(AppArtifact appArtifact, String fromVersion, boolean fromVersionIncluded, String upToVersion, boolean upToVersionInclusive) throws AppModelResolverException {
final VersionRangeResult rangeResult = resolveVersionRangeResult(appArtifact, fromVersion, fromVersionIncluded, upToVersion, upToVersionInclusive);
final List<Version> versions = rangeResult.getVersions();
if(versions.isEmpty()) {
return null;
}
Version next = versions.get(0);
for(int i = 1; i < versions.size(); ++i) {
final Version candidate = versions.get(i);
if(next.compareTo(candidate) > 0) {
next = candidate;
}
}
return next.toString();
}

@Override
public String getLatestVersion(AppArtifact appArtifact, String upToVersion, boolean inclusive) throws AppModelResolverException {
final VersionRangeResult rangeResult = resolveVersionRangeResult(appArtifact, appArtifact.getVersion(), false, upToVersion, inclusive);
final List<Version> versions = rangeResult.getVersions();
if(versions.isEmpty()) {
return appArtifact.getVersion();
}
Version latest = versions.get(0);
for(int i = 1; i < versions.size(); ++i) {
final Version candidate = versions.get(i);
if(latest.compareTo(candidate) < 0) {
latest = candidate;
}
}
return latest.toString();
}

public List<RemoteRepository> resolveArtifactRepos(AppArtifact appArtifact) throws AppModelResolverException {
return mvn.resolveDescriptor(toAetherArtifact(appArtifact)).getRepositories();
}

public void install(AppArtifact appArtifact, Path localPath) throws AppModelResolverException {
mvn.install(new DefaultArtifact(appArtifact.getGroupId(), appArtifact.getArtifactId(), appArtifact.getClassifier(),
appArtifact.getType(), appArtifact.getVersion(), Collections.emptyMap(), localPath.toFile()));
}

private AppModel injectDeploymentDependencies(AppArtifact appArtifact, DependencyNode root, List<Dependency> managedDeps) throws AppModelResolverException {
DependencyNode resolvedDeps = mvn.resolveManagedDependencies(toAetherArtifact(appArtifact),
directMvnDeps, managedDeps, managedRepos, devmode ? new String[] { "test" } : new String[0]).getRoot();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to bother you with my dumb questions but trying to understand what's going on to make a real review :).

Why exactly do we exclude the test scope when in dev mode and not in the other modes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When an app is compiled, every scope except test is available, which maps to our dev mode and that's how it's reflected in our code.
However, when the application is packaged provided and test scopes are filtered out by default. So, in that case, I am delegating to the default Maven resolver config that is taking care of that.


final Set<AppArtifactKey> appDeps = new HashSet<>();
final List<AppDependency> userDeps = new ArrayList<>();
Expand All @@ -215,31 +163,32 @@ public boolean visitLeave(DependencyNode node) {
}
return true;
}});
for(DependencyNode child : root.getChildren()) {
for(DependencyNode child : resolvedDeps.getChildren()) {
child.accept(visitor);
}

final DeploymentInjectingDependencyVisitor deploymentInjector = new DeploymentInjectingDependencyVisitor(mvn, managedDeps);
final DeploymentInjectingDependencyVisitor deploymentInjector = new DeploymentInjectingDependencyVisitor(mvn,
managedDeps, mvn.aggregateRepositories(managedRepos, mvn.newResolutionRepositories(mvn.resolveDescriptor(toAetherArtifact(appArtifact)).getRepositories())));
try {
root.accept(new TreeDependencyVisitor(deploymentInjector));
resolvedDeps.accept(new TreeDependencyVisitor(deploymentInjector));
} catch (DeploymentInjectionException e) {
throw new AppModelResolverException("Failed to inject extension deployment dependencies for " + root.getArtifact(), e.getCause());
throw new AppModelResolverException("Failed to inject extension deployment dependencies for " + resolvedDeps.getArtifact(), e.getCause());
}

List<AppDependency> deploymentDeps = Collections.emptyList();
if(deploymentInjector.isInjectedDeps()) {
final DependencyGraphTransformationContext context = new SimpleDependencyGraphTransformationContext(mvn.getSession());
try {
// add conflict IDs to the added deployments
root = new ConflictMarker().transformGraph(root, context);
resolvedDeps = new ConflictMarker().transformGraph(resolvedDeps, context);
// resolves version conflicts
root = new ConflictIdSorter().transformGraph(root, context);
root = mvn.getSession().getDependencyGraphTransformer().transformGraph(root, context);
resolvedDeps = new ConflictIdSorter().transformGraph(resolvedDeps, context);
resolvedDeps = mvn.getSession().getDependencyGraphTransformer().transformGraph(resolvedDeps, context);
} catch (RepositoryException e) {
throw new AppModelResolverException("Failed to normalize the dependency graph", e);
}
final BuildDependencyGraphVisitor buildDepsVisitor = new BuildDependencyGraphVisitor(appDeps, buildTreeConsumer);
buildDepsVisitor.visit(root);
buildDepsVisitor.visit(resolvedDeps);
final List<ArtifactRequest> requests = buildDepsVisitor.getArtifactRequests();
if(!requests.isEmpty()) {
final List<ArtifactResult> results = mvn.resolve(requests);
Expand All @@ -262,6 +211,60 @@ public boolean visitLeave(DependencyNode node) {
return new AppModel(appArtifact, userDeps, deploymentDeps);
}

@Override
public List<String> listLaterVersions(AppArtifact appArtifact, String upToVersion, boolean inclusive) throws AppModelResolverException {
final VersionRangeResult rangeResult = resolveVersionRangeResult(appArtifact, appArtifact.getVersion(), false, upToVersion, inclusive);
final List<Version> resolvedVersions = rangeResult.getVersions();
final List<String> versions = new ArrayList<>(resolvedVersions.size());
for (Version v : resolvedVersions) {
versions.add(v.toString());
}
return versions;
}

@Override
public String getNextVersion(AppArtifact appArtifact, String fromVersion, boolean fromVersionIncluded, String upToVersion, boolean upToVersionInclusive) throws AppModelResolverException {
final VersionRangeResult rangeResult = resolveVersionRangeResult(appArtifact, fromVersion, fromVersionIncluded, upToVersion, upToVersionInclusive);
final List<Version> versions = rangeResult.getVersions();
if(versions.isEmpty()) {
return null;
}
Version next = versions.get(0);
for(int i = 1; i < versions.size(); ++i) {
final Version candidate = versions.get(i);
if(next.compareTo(candidate) > 0) {
next = candidate;
}
}
return next.toString();
}

@Override
public String getLatestVersion(AppArtifact appArtifact, String upToVersion, boolean inclusive) throws AppModelResolverException {
final VersionRangeResult rangeResult = resolveVersionRangeResult(appArtifact, appArtifact.getVersion(), false, upToVersion, inclusive);
final List<Version> versions = rangeResult.getVersions();
if(versions.isEmpty()) {
return appArtifact.getVersion();
}
Version latest = versions.get(0);
for(int i = 1; i < versions.size(); ++i) {
final Version candidate = versions.get(i);
if(latest.compareTo(candidate) < 0) {
latest = candidate;
}
}
return latest.toString();
}

public List<RemoteRepository> resolveArtifactRepos(AppArtifact appArtifact) throws AppModelResolverException {
return mvn.resolveDescriptor(toAetherArtifact(appArtifact)).getRepositories();
}

public void install(AppArtifact appArtifact, Path localPath) throws AppModelResolverException {
mvn.install(new DefaultArtifact(appArtifact.getGroupId(), appArtifact.getArtifactId(), appArtifact.getClassifier(),
appArtifact.getType(), appArtifact.getVersion(), Collections.emptyMap(), localPath.toFile()));
}

private VersionRangeResult resolveVersionRangeResult(AppArtifact appArtifact, String fromVersion, boolean fromVersionIncluded, String upToVersion, boolean upToVersionIncluded)
throws AppModelResolverException {
return mvn.resolveVersionRange(new DefaultArtifact(appArtifact.getGroupId(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.graph.DependencyVisitor;
import org.eclipse.aether.repository.RemoteRepository;
import org.jboss.logging.Logger;
import io.quarkus.bootstrap.BootstrapConstants;
import io.quarkus.bootstrap.BootstrapDependencyProcessingException;
Expand All @@ -37,13 +38,15 @@ public static Artifact getInjectedDependency(DependencyNode dep) {

private final MavenArtifactResolver resolver;
private final List<Dependency> managedDeps;
private final List<RemoteRepository> mainRepos;
private DependencyNode node;

boolean injectedDeps;

public DeploymentInjectingDependencyVisitor(MavenArtifactResolver resolver, List<Dependency> managedDeps) {
public DeploymentInjectingDependencyVisitor(MavenArtifactResolver resolver, List<Dependency> managedDeps, List<RemoteRepository> mainRepos) {
this.resolver = resolver;
this.managedDeps = managedDeps;
this.mainRepos = mainRepos;
}

public boolean isInjectedDeps() {
Expand Down Expand Up @@ -124,7 +127,8 @@ private DependencyNode collectDependencies(Artifact artifact) throws BootstrapDe
artifact = artifact.setVersion(node.getArtifact().getVersion());
}
try {
return managedDeps.isEmpty() ? resolver.collectDependencies(artifact).getRoot() : resolver.collectManagedDependencies(artifact, Collections.emptyList(), managedDeps).getRoot();
return managedDeps.isEmpty() ? resolver.collectDependencies(artifact, Collections.emptyList(), mainRepos).getRoot()
: resolver.collectManagedDependencies(artifact, Collections.emptyList(), managedDeps, mainRepos).getRoot();
} catch (AppModelResolverException e) {
throw new DeploymentInjectionException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,11 @@ public DependencyResult resolveDependencies(Artifact artifact) throws AppModelRe
}

public CollectResult collectDependencies(Artifact artifact, List<Dependency> deps) throws AppModelResolverException {
final CollectRequest request = newCollectRequest(artifact);
return collectDependencies(artifact, deps, Collections.emptyList());
}

public CollectResult collectDependencies(Artifact artifact, List<Dependency> deps, List<RemoteRepository> mainRepos) throws AppModelResolverException {
final CollectRequest request = newCollectRequest(artifact, mainRepos);
request.setDependencies(deps);
try {
return repoSystem.collectDependencies(repoSession, request);
Expand All @@ -231,7 +235,11 @@ public CollectResult collectDependencies(Artifact artifact, List<Dependency> dep
}

public DependencyResult resolveDependencies(Artifact artifact, List<Dependency> deps) throws AppModelResolverException {
final CollectRequest request = newCollectRequest(artifact);
return resolveDependencies(artifact, deps, Collections.emptyList());
}

public DependencyResult resolveDependencies(Artifact artifact, List<Dependency> deps, List<RemoteRepository> mainRepos) throws AppModelResolverException {
final CollectRequest request = newCollectRequest(artifact, mainRepos);
request.setDependencies(deps);
try {
return repoSystem.resolveDependencies(repoSession,
Expand All @@ -254,7 +262,7 @@ public DependencyResult resolveDependencies(Artifact artifact, String... exclude
deps.add(dep);
}
}
final List<RemoteRepository> requestRepos = remoteRepoManager.aggregateRepositories(repoSession, remoteRepos, descr.getRepositories(), true);
final List<RemoteRepository> requestRepos = aggregateRepositories(remoteRepos, newResolutionRepositories(descr.getRepositories()));
try {
return repoSystem.resolveDependencies(repoSession,
new DependencyRequest().setCollectRequest(
Expand All @@ -269,24 +277,32 @@ public DependencyResult resolveDependencies(Artifact artifact, String... exclude
}

public DependencyResult resolveManagedDependencies(Artifact artifact, List<Dependency> deps, List<Dependency> managedDeps, String... excludedScopes) throws AppModelResolverException {
return resolveManagedDependencies(artifact, deps, managedDeps, Collections.emptyList(), excludedScopes);
}

public DependencyResult resolveManagedDependencies(Artifact artifact, List<Dependency> deps, List<Dependency> managedDeps, List<RemoteRepository> mainRepos, String... excludedScopes) throws AppModelResolverException {
try {
return repoSystem.resolveDependencies(repoSession,
new DependencyRequest().setCollectRequest(
newCollectManagedRequest(artifact, deps, managedDeps, excludedScopes)));
newCollectManagedRequest(artifact, deps, managedDeps, mainRepos, excludedScopes)));
} catch (DependencyResolutionException e) {
throw new AppModelResolverException("Failed to resolve dependencies for " + artifact, e);
}
}

public CollectResult collectManagedDependencies(Artifact artifact, List<Dependency> deps, List<Dependency> managedDeps, String... excludedScopes) throws AppModelResolverException {
return collectManagedDependencies(artifact, deps, managedDeps, Collections.emptyList(), excludedScopes);
}

public CollectResult collectManagedDependencies(Artifact artifact, List<Dependency> deps, List<Dependency> managedDeps, List<RemoteRepository> mainRepos, String... excludedScopes) throws AppModelResolverException {
try {
return repoSystem.collectDependencies(repoSession, newCollectManagedRequest(artifact, deps, managedDeps, excludedScopes));
return repoSystem.collectDependencies(repoSession, newCollectManagedRequest(artifact, deps, managedDeps, mainRepos, excludedScopes));
} catch (DependencyCollectionException e) {
throw new AppModelResolverException("Failed to collect dependencies for " + artifact, e);
}
}

private CollectRequest newCollectManagedRequest(Artifact artifact, List<Dependency> deps, List<Dependency> managedDeps, String... excludedScopes) throws AppModelResolverException {
private CollectRequest newCollectManagedRequest(Artifact artifact, List<Dependency> deps, List<Dependency> managedDeps, List<RemoteRepository> mainRepos, String... excludedScopes) throws AppModelResolverException {
final ArtifactDescriptorResult descr = resolveDescriptor(artifact);
Collection<String> excluded;
if(excludedScopes.length == 0) {
Expand Down Expand Up @@ -325,11 +341,20 @@ private CollectRequest newCollectManagedRequest(Artifact artifact, List<Dependen
}
}

final List<RemoteRepository> repos = aggregateRepositories(mainRepos, remoteRepos);
return new CollectRequest()
.setRootArtifact(artifact)
.setDependencies(mergeDeps(deps, originalDeps, managedVersions))
.setManagedDependencies(mergedManagedDeps)
.setRepositories(remoteRepoManager.aggregateRepositories(repoSession, remoteRepos, descr.getRepositories(), true));
.setRepositories(aggregateRepositories(repos, newResolutionRepositories(descr.getRepositories())));
}

public List<RemoteRepository> newResolutionRepositories(List<RemoteRepository> repos) {
return repos.isEmpty() ? Collections.emptyList() : repoSystem.newResolutionRepositories(repoSession, repos);
}

public List<RemoteRepository> aggregateRepositories(List<RemoteRepository> dominant, List<RemoteRepository> recessive) {
return dominant.isEmpty() ? recessive : remoteRepoManager.aggregateRepositories(repoSession, dominant, recessive, false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which case do we have dominant and recessive repositories?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That occurs naturally in any Maven project given that there is a hierarchy of POMs each of which may include repositories. Since during tests we, unfortunately, loose the Maven build context, we have to initialize repos the Maven way ourselves, taking the repos from the default settings and then merging them into the target project's repos. Repos from the project's POM will be dominating.
Another use-case is when we test/build an app from an external artifact (integration of external tests, for example). In that case, the project that integrates the external artifact is going to be dominating.

}

public void install(Artifact artifact) throws AppModelResolverException {
Expand All @@ -340,10 +365,10 @@ public void install(Artifact artifact) throws AppModelResolverException {
}
}

private CollectRequest newCollectRequest(Artifact artifact) throws AppModelResolverException {
private CollectRequest newCollectRequest(Artifact artifact, List<RemoteRepository> mainRepos) throws AppModelResolverException {
return new CollectRequest()
.setRoot(new Dependency(artifact, JavaScopes.RUNTIME))
.setRepositories(remoteRepos);
.setRepositories(aggregateRepositories(mainRepos, remoteRepos));
}

private List<Dependency> mergeDeps(List<Dependency> dominant, List<Dependency> recessive, Map<AppArtifactKey, String> managedVersions) {
Expand Down