Skip to content

Commit

Permalink
Make sure parent modules are loaded into workspace before those that …
Browse files Browse the repository at this point in the history
…depend on them

(cherry picked from commit 0c0190e)
  • Loading branch information
aloubyansky authored and gsmet committed May 9, 2023
1 parent 3578c5d commit 6c41122
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package io.quarkus.bootstrap.resolver.maven;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
Expand All @@ -28,23 +26,25 @@
import org.eclipse.aether.impl.RemoteRepositoryManager;
import org.eclipse.aether.impl.VersionRangeResolver;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.WorkspaceReader;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.VersionRangeRequest;
import org.eclipse.aether.resolution.VersionRangeResolutionException;
import org.eclipse.aether.resolution.VersionRangeResult;

import io.quarkus.bootstrap.resolver.maven.workspace.LocalWorkspace;
import io.quarkus.maven.dependency.ArtifactCoords;

public class BootstrapModelResolver implements ModelResolver {

public static ModelResolver newInstance(BootstrapMavenContext ctx, LocalWorkspace workspace)
public static ModelResolver newInstance(BootstrapMavenContext ctx, WorkspaceReader workspace)
throws BootstrapMavenException {
final RepositorySystem repoSystem = ctx.getRepositorySystem();
return new BootstrapModelResolver(
new DefaultRepositorySystemSession(ctx.getRepositorySystemSession()).setWorkspaceReader(workspace), null, null,
final RepositorySystemSession session = workspace == null
? ctx.getRepositorySystemSession()
: new DefaultRepositorySystemSession(ctx.getRepositorySystemSession()).setWorkspaceReader(workspace);
return new BootstrapModelResolver(session, null, null,
new ArtifactResolver() {
@Override
public ArtifactResult resolveArtifact(RepositorySystemSession session, ArtifactRequest request)
Expand Down Expand Up @@ -114,19 +114,14 @@ public void addRepository(final Repository repository, boolean replace)
if (session.isIgnoreArtifactDescriptorRepositories()) {
return;
}

if (!repositoryIds.add(repository.getId())) {
if (!replace) {
return;
}

removeMatchingRepository(repositories, repository.getId());
}

List<RemoteRepository> newRepositories = Collections
.singletonList(ArtifactDescriptorUtils.toRemoteRepository(repository));

this.repositories = remoteRepositoryManager.aggregateRepositories(session, repositories, newRepositories, true);
this.repositories = remoteRepositoryManager.aggregateRepositories(session, repositories,
List.of(ArtifactDescriptorUtils.toRemoteRepository(repository)), true);
}

private static void removeMatchingRepository(Iterable<RemoteRepository> repositories, final String id) {
Expand All @@ -147,26 +142,24 @@ public ModelResolver newCopy() {
@Override
public ModelSource resolveModel(String groupId, String artifactId, String version)
throws UnresolvableModelException {
Artifact pomArtifact = new DefaultArtifact(groupId, artifactId, "", "pom", version);

Artifact pomArtifact = new DefaultArtifact(groupId, artifactId, ArtifactCoords.DEFAULT_CLASSIFIER,
ArtifactCoords.TYPE_POM, version);
try {
ArtifactRequest request = new ArtifactRequest(pomArtifact, repositories, context);
request.setTrace(trace);
pomArtifact = resolver.resolveArtifact(session, request).getArtifact();
} catch (ArtifactResolutionException e) {
throw new UnresolvableModelException(e.getMessage(), groupId, artifactId, version, e);
}

File pomFile = pomArtifact.getFile();

return new FileModelSource(pomFile);
return new FileModelSource(pomArtifact.getFile());
}

@Override
public ModelSource resolveModel(final Parent parent)
throws UnresolvableModelException {
try {
final Artifact artifact = new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(), "", "pom",
final Artifact artifact = new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(),
ArtifactCoords.DEFAULT_CLASSIFIER, ArtifactCoords.TYPE_POM,
parent.getVersion());

final VersionRangeRequest versionRangeRequest = new VersionRangeRequest(artifact, repositories, context);
Expand Down Expand Up @@ -195,7 +188,7 @@ public ModelSource resolveModel(final Parent parent)
parent.setVersion(versionRangeResult.getHighestVersion().toString());

return resolveModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
} catch (final VersionRangeResolutionException e) {
} catch (VersionRangeResolutionException e) {
throw new UnresolvableModelException(e.getMessage(), parent.getGroupId(), parent.getArtifactId(),
parent.getVersion(), e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,23 @@ private Model getModel(ModelBuildingRequest request) {
}

private void completeWorkspaceProjectBuildRequest(ModelBuildingRequest request) throws BootstrapMavenException {
final Set<String> addedProfiles = new HashSet<>();
final Set<String> addedProfiles;
final List<Profile> profiles = request.getProfiles();
profiles.forEach(p -> addedProfiles.add(p.getId()));
if (profiles.isEmpty()) {
addedProfiles = Set.of();
} else {
addedProfiles = new HashSet<>(profiles.size());
for (Profile p : profiles) {
addedProfiles.add(p.getId());
}
}

final List<Profile> activeSettingsProfiles = ctx.getActiveSettingsProfiles();
activeSettingsProfiles.forEach(p -> {
for (Profile p : ctx.getActiveSettingsProfiles()) {
if (!addedProfiles.contains(p.getId())) {
profiles.add(p);
request.getActiveProfileIds().add(p.getId());
}
});
}

final BootstrapMavenOptions cliOptions = ctx.getCliOptions();
request.getActiveProfileIds().addAll(cliOptions.getActiveProfileIds());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -23,7 +22,6 @@
import io.quarkus.bootstrap.workspace.WorkspaceModule;
import io.quarkus.maven.dependency.ArtifactCoords;
import io.quarkus.maven.dependency.ArtifactKey;
import io.quarkus.maven.dependency.GACT;

/**
*
Expand Down Expand Up @@ -56,7 +54,7 @@ protected void addProject(LocalProject project, long lastModified) {
}

public LocalProject getProject(String groupId, String artifactId) {
return getProject(new GACT(groupId, artifactId));
return getProject(ArtifactKey.ga(groupId, artifactId));
}

public LocalProject getProject(ArtifactKey key) {
Expand All @@ -74,7 +72,7 @@ public int getId() {
@Override
public Model resolveRawModel(String groupId, String artifactId, String versionConstraint)
throws UnresolvableModelException {
if (findArtifact(new DefaultArtifact(groupId, artifactId, null, "pom", versionConstraint)) != null) {
if (findArtifact(new DefaultArtifact(groupId, artifactId, null, ArtifactCoords.TYPE_POM, versionConstraint)) != null) {
return getProject(groupId, artifactId).getRawModel();
}
return null;
Expand Down Expand Up @@ -217,7 +215,7 @@ public List<String> findVersions(Artifact artifact) {
return lastFindVersions;
}
if (findArtifact(artifact) == null) {
return Collections.emptyList();
return List.of();
}
lastFindVersionsKey = ArtifactKey.ga(artifact.getGroupId(), artifact.getArtifactId());
return lastFindVersions = List.of(artifact.getVersion());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.bootstrap.resolver.maven.workspace;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
Expand All @@ -20,6 +21,9 @@
import org.apache.maven.model.resolution.ModelResolver;
import org.apache.maven.model.resolution.UnresolvableModelException;
import org.apache.maven.model.resolution.WorkspaceModelResolver;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.repository.WorkspaceReader;
import org.eclipse.aether.repository.WorkspaceRepository;
import org.jboss.logging.Logger;

import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext;
Expand All @@ -28,7 +32,7 @@
import io.quarkus.bootstrap.resolver.maven.BootstrapModelResolver;
import io.quarkus.bootstrap.resolver.maven.options.BootstrapMavenOptions;

public class WorkspaceLoader implements WorkspaceModelResolver {
public class WorkspaceLoader implements WorkspaceModelResolver, WorkspaceReader {

private static final Logger log = Logger.getLogger(WorkspaceLoader.class);

Expand Down Expand Up @@ -84,7 +88,7 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra
this.modelProvider = modelProvider;
if (ctx != null && ctx.isEffectiveModelBuilder()) {
modelBuilder = BootstrapModelBuilderFactory.getDefaultModelBuilder();
modelResolver = BootstrapModelResolver.newInstance(ctx, workspace);
modelResolver = BootstrapModelResolver.newInstance(ctx, this);
modelCache = new BootstrapModelCache(ctx.getRepositorySystemSession());

profiles = ctx.getActiveSettingsProfiles();
Expand Down Expand Up @@ -119,8 +123,10 @@ private LocalProject project(Path pomFile) throws BootstrapMavenException {
}

private LocalProject loadAndCacheProject(Path pomFile) throws BootstrapMavenException {
Model cachedRawModel = rawModelCache.getOrDefault(pomFile.getParent(),
modelProvider == null ? null : modelProvider.apply(pomFile.getParent()));
final Model rawModel = rawModel(pomFile);
if (rawModel == null) {
return null;
}
final LocalProject project;
if (modelBuilder != null) {
ModelBuildingRequest req = new DefaultModelBuildingRequest();
Expand All @@ -132,21 +138,15 @@ private LocalProject loadAndCacheProject(Path pomFile) throws BootstrapMavenExce
req.setActiveProfileIds(activeProfileIds);
req.setInactiveProfileIds(inactiveProfileIds);
req.setProfiles(profiles);
req.setRawModel(cachedRawModel);
req.setRawModel(rawModel);
req.setWorkspaceModelResolver(this);
try {
project = new LocalProject(modelBuilder.build(req), workspace);
} catch (Exception e) {
throw new BootstrapMavenException("Failed to resolve the effective model for " + pomFile, e);
}
} else if (cachedRawModel != null) {
project = new LocalProject(cachedRawModel, workspace);
} else {
Model model = readModel(pomFile);
if (model == null) {
return null;
}
project = new LocalProject(model, workspace);
project = new LocalProject(rawModel, workspace);
}
projectCache.put(pomFile.getParent(), project);
return project;
Expand All @@ -170,13 +170,9 @@ void setWorkspaceRootPom(Path rootPom) {
this.workspaceRootPom = rootPom;
}

private LocalProject loadProject(final Path projectPom, String skipModule) throws BootstrapMavenException {
private LocalProject loadProject(Path projectPom, String skipModule) throws BootstrapMavenException {
final Model rawModel = rawModel(projectPom);

final Path parentPom = getParentPom(projectPom, rawModel);
final LocalProject parentProject = parentPom == null || rawModelCache.containsKey(parentPom.getParent()) ? null
: loadProject(parentPom, parentPom.getParent().relativize(projectPom.getParent()).toString());

final LocalProject parentProject = loadParentProject(projectPom, rawModel);
final LocalProject project = project(projectPom);
if (project == null) {
return null;
Expand All @@ -188,6 +184,12 @@ private LocalProject loadProject(final Path projectPom, String skipModule) throw
return project;
}

private LocalProject loadParentProject(Path projectPom, final Model rawModel) throws BootstrapMavenException {
final Path parentPom = getParentPom(projectPom, rawModel);
return parentPom == null || rawModelCache.containsKey(parentPom.getParent()) ? null
: loadProject(parentPom, parentPom.getParent().relativize(projectPom.getParent()).toString());
}

private Path getParentPom(Path projectPom, Model rawModel) {
Path parentPom = null;
final Path projectDir = projectPom.getParent();
Expand All @@ -214,7 +216,11 @@ private LocalProject loadProjectModules(LocalProject project, String skipModule)
if (module.equals(skipModule)) {
continue;
}
final LocalProject childProject = project(project.getDir().resolve(module).resolve(POM_XML));
final Path modulePom = project.getDir().resolve(module).resolve(POM_XML);
// some modules use different parent POMs than those that referred to them as their modules
// so make sure the parent project has been loaded, before resolving the effective model of the module
loadParentProject(modulePom, rawModel(modulePom));
final LocalProject childProject = project(modulePom);
if (childProject != null) {
project.modules.add(loadProjectModules(childProject, null));
}
Expand Down Expand Up @@ -255,4 +261,19 @@ public Model resolveEffectiveModel(String groupId, String artifactId, String ver
? project.getModelBuildingResult().getEffectiveModel()
: null;
}

@Override
public WorkspaceRepository getRepository() {
return workspace.getRepository();
}

@Override
public File findArtifact(Artifact artifact) {
return workspace.findArtifact(artifact);
}

@Override
public List<String> findVersions(Artifact artifact) {
return workspace.findVersions(artifact);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,45 @@ public static void cleanup() {
IoUtils.recursiveDelete(workDir);
}

@Test
public void moduleWithDifferentParentPomRawModel() throws Exception {
final URL moduleUrl = Thread.currentThread().getContextClassLoader()
.getResource("workspace-module-with-different-parent");
assertNotNull(moduleUrl);
final Path moduleDir = Path.of(moduleUrl.toURI());
assertNotNull(moduleUrl);

final LocalWorkspace ws = LocalProject.loadWorkspace(moduleDir).getWorkspace();

assertNotNull(ws.getProject("org.acme", "acme-runtimes"));
assertNotNull(ws.getProject("org.acme", "acme-parent"));
assertNotNull(ws.getProject("org.acme", "acme-build-no-bom-parent"));
assertNotNull(ws.getProject("org.acme", "acme-build-parent"));
assertNotNull(ws.getProject("org.acme", "acme-dependencies-bom"));
assertEquals(5, ws.getProjects().size());
}

@Test
public void moduleWithDifferentParentPomEffectiveModel() throws Exception {
final URL moduleUrl = Thread.currentThread().getContextClassLoader()
.getResource("workspace-module-with-different-parent");
assertNotNull(moduleUrl);
final Path moduleDir = Path.of(moduleUrl.toURI());
assertNotNull(moduleUrl);

final LocalWorkspace ws = new BootstrapMavenContext(BootstrapMavenContext.config()
.setEffectiveModelBuilder(true)
.setCurrentProject(moduleDir.toString()))
.getWorkspace();

assertNotNull(ws.getProject("org.acme", "acme-runtimes"));
assertNotNull(ws.getProject("org.acme", "acme-parent"));
assertNotNull(ws.getProject("org.acme", "acme-build-no-bom-parent"));
assertNotNull(ws.getProject("org.acme", "acme-build-parent"));
assertNotNull(ws.getProject("org.acme", "acme-dependencies-bom"));
assertEquals(5, ws.getProjects().size());
}

@Test
public void nonParentAggregator() throws Exception {
final URL moduleUrl = Thread.currentThread().getContextClassLoader()
Expand Down Expand Up @@ -260,6 +299,26 @@ public void loadWorkspaceFromRootDirWithParentInChildDir() throws Exception {
assertParents(project, "acme-parent", "acme-dependencies");
}

@Test
public void loadWorkspaceFromRootDirWithParentInChildDirEffectiveModel() throws Exception {
final URL projectUrl = Thread.currentThread().getContextClassLoader().getResource("workspace-parent-is-not-root-dir");
assertNotNull(projectUrl);
final Path projectDir = Paths.get(projectUrl.toURI());
assertTrue(Files.exists(projectDir));

final LocalProject module1 = new BootstrapMavenContext(BootstrapMavenContext.config()
.setEffectiveModelBuilder(true)
.setCurrentProject(projectDir.toString()))
.getCurrentProject();
final LocalWorkspace ws = module1.getWorkspace();
final LocalProject project = ws.getProject("org.acme", "acme");
assertNotNull(project);

assertEquals("acme", project.getArtifactId());
assertWorkspaceWithParentInChildDir(project);
assertParents(project, "acme-parent", "acme-dependencies");
}

@Test
public void loadWorkspaceFromModuleDirWithParentInChildDir() throws Exception {
final URL projectUrl = Thread.currentThread().getContextClassLoader()
Expand Down
Loading

0 comments on commit 6c41122

Please sign in to comment.