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

[2.16] Make sure parent modules are loaded into workspace before those that depend on them #31471

Merged
merged 1 commit into from
Mar 2, 2023
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
@@ -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