Skip to content

Commit

Permalink
Make sure the app model is initialized from the POMs provided by the
Browse files Browse the repository at this point in the history
Maven plugin that could be manipulated by Maven extensions
  • Loading branch information
aloubyansky committed Oct 6, 2022
1 parent 97324a1 commit a426f6a
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 34 deletions.
Expand Up @@ -419,7 +419,6 @@ protected void prepare() throws Exception {
devModeContext.setReleaseJavaVersion(releaseJavaVersion);
devModeContext.setSourceJavaVersion(sourceJavaVersion);
devModeContext.setTargetJvmVersion(targetJavaVersion);

devModeContext.getLocalArtifacts().addAll(localArtifacts);
devModeContext.setApplicationRoot(main);
devModeContext.getAdditionalModules().addAll(dependencies);
Expand Down
29 changes: 19 additions & 10 deletions devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
Expand Up @@ -43,6 +43,7 @@
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.BuildBase;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.model.Profile;
Expand Down Expand Up @@ -90,6 +91,8 @@
import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.bootstrap.model.PathsCollection;
import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver;
import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext;
import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContextConfig;
import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver;
import io.quarkus.bootstrap.resolver.maven.options.BootstrapMavenOptions;
import io.quarkus.bootstrap.util.BootstrapUtils;
Expand Down Expand Up @@ -759,7 +762,6 @@ private String getSourceEncoding() {
}

private void addProject(MavenDevModeLauncher.Builder builder, ResolvedDependency module, boolean root) throws Exception {

if (!module.isJar()) {
return;
}
Expand Down Expand Up @@ -1084,30 +1086,37 @@ private QuarkusDevModeLauncher newLauncher() throws Exception {
if (appModel != null) {
bootstrapProvider.close();
} else {
final MavenArtifactResolver.Builder resolverBuilder = MavenArtifactResolver.builder()
final BootstrapMavenContextConfig<?> mvnConfig = BootstrapMavenContext.config()
.setRemoteRepositories(repos)
.setRemoteRepositoryManager(remoteRepositoryManager)
.setWorkspaceDiscovery(true)
.setPreferPomsFromWorkspace(true)
.setCurrentProject(project.getFile().toString());

// if it already exists, it may be a reload triggered by a change in a POM
// in which case we should not be using the original Maven session
boolean reinitializeMavenSession = Files.exists(appModelLocation);
if (reinitializeMavenSession) {
// if a serialized model is found, it may be a reload triggered by a change in a POM
// in which case we should not be using the original Maven session initialized with the previous POM version
if (Files.exists(appModelLocation)) {
Files.delete(appModelLocation);
// we can't re-use the repo system because we want to use our interpolating model builder
// a use-case where it fails with the original repo system is when dev mode is launched with -Dquarkus.platform.version=xxx
// overriding the version of the quarkus-bom in the pom.xml
} else {
// we can re-use the original Maven session
resolverBuilder.setRepositorySystemSession(repoSession).setRepositorySystem(repoSystem);
// we can re-use the original Maven session and the system
mvnConfig.setRepositorySystemSession(repoSession).setRepositorySystem(repoSystem);
// there could be Maven extensions manipulating the project versions and models
// the ones returned from the Maven API could be different from the original pom.xml files
final Map<Path, Model> projectModels = new HashMap<>(session.getAllProjects().size());
for (MavenProject mp : session.getAllProjects()) {
projectModels.put(mp.getBasedir().toPath(), mp.getOriginalModel());
}
mvnConfig.setProjectModelProvider(projectModels::get);
}

appModel = new BootstrapAppModelResolver(resolverBuilder.build())
final BootstrapMavenContext mvnCtx = new BootstrapMavenContext(mvnConfig);
appModel = new BootstrapAppModelResolver(new MavenArtifactResolver(mvnCtx))
.setDevMode(true)
.setCollectReloadableDependencies(!noDeps)
.resolveModel(ArtifactCoords.jar(project.getGroupId(), project.getArtifactId(), project.getVersion()));
.resolveModel(mvnCtx.getCurrentProject().getAppArtifact());
}

// serialize the app model to avoid re-resolving it in the dev process
Expand Down
Expand Up @@ -6,6 +6,8 @@
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand All @@ -14,6 +16,7 @@
import java.util.concurrent.ExecutionException;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Model;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;
Expand Down Expand Up @@ -132,16 +135,21 @@ private MavenArtifactResolver artifactResolver(QuarkusBootstrapMojo mojo, Launch
throws MojoExecutionException {
isWorkspaceDiscovery(mojo);
try {
return MavenArtifactResolver.builder()
.setWorkspaceDiscovery(
mode == LaunchMode.DEVELOPMENT || mode == LaunchMode.TEST || isWorkspaceDiscovery(mojo))
final MavenArtifactResolver.Builder builder = MavenArtifactResolver.builder()
.setCurrentProject(mojo.mavenProject().getFile().toString())
.setPreferPomsFromWorkspace(mode == LaunchMode.DEVELOPMENT || mode == LaunchMode.TEST)
.setRepositorySystem(repoSystem)
.setRepositorySystemSession(mojo.repositorySystemSession())
.setRemoteRepositories(mojo.remoteRepositories())
.setRemoteRepositoryManager(remoteRepoManager)
.build();
.setRemoteRepositoryManager(remoteRepoManager);
if (mode == LaunchMode.DEVELOPMENT || mode == LaunchMode.TEST || isWorkspaceDiscovery(mojo)) {
final Map<Path, Model> projectModels = new HashMap<>(mojo.mavenSession().getAllProjects().size());
for (MavenProject mp : mojo.mavenSession().getAllProjects()) {
projectModels.put(mp.getBasedir().toPath(), mp.getOriginalModel());
}
builder.setWorkspaceDiscovery(true).setProjectModelProvider(projectModels::get);
}
return builder.build();
} catch (BootstrapMavenException e) {
throw new MojoExecutionException("Failed to initialize Quarkus bootstrap Maven artifact resolver", e);
}
Expand Down
Expand Up @@ -12,6 +12,7 @@
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.function.Function;
import java.util.function.Supplier;

import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -169,7 +170,7 @@ public BootstrapMavenContext(BootstrapMavenContextConfig<?> config)
this.currentPom = currentProject.getRawModel().getPomFile().toPath();
this.workspace = config.currentProject.getWorkspace();
} else if (config.workspaceDiscovery) {
currentProject = resolveCurrentProject();
currentProject = resolveCurrentProject(config.modelProvider);
this.workspace = currentProject == null ? null : currentProject.getWorkspace();
if (workspace != null) {
if (config.repoSession == null && repoSession != null && repoSession.getWorkspaceReader() == null) {
Expand Down Expand Up @@ -315,9 +316,9 @@ public String getLocalRepo() throws BootstrapMavenException {
return localRepo == null ? localRepo = resolveLocalRepo(getEffectiveSettings()) : localRepo;
}

private LocalProject resolveCurrentProject() throws BootstrapMavenException {
private LocalProject resolveCurrentProject(Function<Path, Model> modelProvider) throws BootstrapMavenException {
try {
return LocalProject.loadWorkspace(this);
return LocalProject.loadWorkspace(this, modelProvider);
} catch (Exception e) {
throw new BootstrapMavenException("Failed to load current project at " + getCurrentProjectPomOrNull(), e);
}
Expand Down
Expand Up @@ -5,7 +5,9 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Function;

import org.apache.maven.model.Model;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.impl.RemoteRepositoryManager;
Expand Down Expand Up @@ -33,6 +35,7 @@ public class BootstrapMavenContextConfig<T extends BootstrapMavenContextConfig<?
protected boolean preferPomsFromWorkspace;
protected Boolean effectiveModelBuilder;
protected Boolean wsModuleParentHierarchy;
protected Function<Path, Model> modelProvider;

/**
* Local repository location
Expand Down Expand Up @@ -264,6 +267,20 @@ public T setWorkspaceModuleParentHierarchy(boolean wsModuleParentHierarchy) {
return (T) this;
}

/**
* When workspace discovery is enabled, this method allows to set a POM
* provider that would return a {@link org.apache.maven.model.Model} for
* a given workspace module directory.
*
* @param modelProvider POM provider
* @return this instance
*/
@SuppressWarnings("unchecked")
public T setProjectModelProvider(Function<Path, Model> modelProvider) {
this.modelProvider = modelProvider;
return (T) this;
}

private BootstrapMavenOptions getInitializedCliOptions() {
return cliOptions == null ? cliOptions = BootstrapMavenOptions.newInstance() : cliOptions;
}
Expand Down
Expand Up @@ -47,6 +47,10 @@
*/
public class LocalProject {

private static final String SRC_TEST_RESOURCES = "src/test/resources";

private static final String SRC_MAIN_RESOURCES = "src/main/resources";

public static final String PROJECT_GROUPID = "${project.groupId}";

private static final String PROJECT_BASEDIR = "${project.basedir}";
Expand Down Expand Up @@ -78,7 +82,7 @@ public static LocalProject loadWorkspace(Path path) throws BootstrapMavenExcepti

public static LocalProject loadWorkspace(Path path, boolean required) throws BootstrapMavenException {
try {
return new WorkspaceLoader(null, path.normalize().toAbsolutePath()).load();
return new WorkspaceLoader(null, path.normalize().toAbsolutePath(), null).load();
} catch (Exception e) {
if (required) {
throw e;
Expand All @@ -96,12 +100,17 @@ public static LocalProject loadWorkspace(Path path, boolean required) throws Boo
* @throws BootstrapMavenException in case of an error
*/
public static LocalProject loadWorkspace(BootstrapMavenContext ctx) throws BootstrapMavenException {
return loadWorkspace(ctx, null);
}

public static LocalProject loadWorkspace(BootstrapMavenContext ctx, Function<Path, Model> modelProvider)
throws BootstrapMavenException {
final Path currentProjectPom = ctx.getCurrentProjectPomOrNull();
if (currentProjectPom == null) {
return null;
}
final Path rootProjectBaseDir = ctx.getRootProjectBaseDir();
final WorkspaceLoader wsLoader = new WorkspaceLoader(ctx, currentProjectPom);
final WorkspaceLoader wsLoader = new WorkspaceLoader(ctx, currentProjectPom, modelProvider);

if (rootProjectBaseDir != null && !rootProjectBaseDir.equals(currentProjectPom.getParent())) {
wsLoader.setWorkspaceRootPom(rootProjectBaseDir.resolve(POM_XML));
Expand Down Expand Up @@ -257,23 +266,23 @@ public PathCollection getResourcesSourcesDirs() {
final List<Resource> resources = rawModel.getBuild() == null ? List.of()
: rawModel.getBuild().getResources();
if (resources.isEmpty()) {
return PathList.of(resolveRelativeToBaseDir(null, "src/main/resources"));
return PathList.of(resolveRelativeToBaseDir(null, SRC_MAIN_RESOURCES));
}
return PathList.from(resources.stream()
.map(Resource::getDirectory)
.map(resourcesDir -> resolveRelativeToBaseDir(resourcesDir, "src/main/resources"))
.map(resourcesDir -> resolveRelativeToBaseDir(resourcesDir, SRC_MAIN_RESOURCES))
.collect(Collectors.toCollection(LinkedHashSet::new)));
}

public PathCollection getTestResourcesSourcesDirs() {
final List<Resource> resources = rawModel.getBuild() == null ? List.of()
: rawModel.getBuild().getTestResources();
if (resources.isEmpty()) {
return PathList.of(resolveRelativeToBaseDir(null, "src/test/resources"));
return PathList.of(resolveRelativeToBaseDir(null, SRC_TEST_RESOURCES));
}
return PathList.from(resources.stream()
.map(Resource::getDirectory)
.map(resourcesDir -> resolveRelativeToBaseDir(resourcesDir, "src/test/resources"))
.map(resourcesDir -> resolveRelativeToBaseDir(resourcesDir, SRC_TEST_RESOURCES))
.collect(Collectors.toCollection(LinkedHashSet::new)));
}

Expand Down Expand Up @@ -302,7 +311,8 @@ public ResolvedDependency getAppArtifact() {
}

public ResolvedDependency getAppArtifact(String extension) {
return new ResolvedArtifactDependency(key.getGroupId(), key.getArtifactId(), "", extension, getVersion(),
return new ResolvedArtifactDependency(key.getGroupId(), key.getArtifactId(), ArtifactCoords.DEFAULT_CLASSIFIER,
extension, getVersion(),
(PathCollection) null);
}

Expand Down Expand Up @@ -521,14 +531,14 @@ private Collection<SourceDir> collectMainResources(PathFilter filter) {
final Path classesDir = getClassesDir();
if (resources.isEmpty()) {
return List.of(new DefaultSourceDir(
new DirectoryPathTree(resolveRelativeToBaseDir(null, "src/main/resources")),
new DirectoryPathTree(resolveRelativeToBaseDir(null, SRC_MAIN_RESOURCES)),
new DirectoryPathTree(classesDir, filter), Map.of()));
}
final List<SourceDir> sourceDirs = new ArrayList<>(resources.size());
for (Resource r : resources) {
sourceDirs.add(
new DefaultSourceDir(
new DirectoryPathTree(resolveRelativeToBaseDir(r.getDirectory(), "src/main/resources")),
new DirectoryPathTree(resolveRelativeToBaseDir(r.getDirectory(), SRC_MAIN_RESOURCES)),
new DirectoryPathTree((r.getTargetPath() == null ? classesDir
: classesDir.resolve(stripProjectBasedirPrefix(r.getTargetPath(), PROJECT_OUTPUT_DIR))),
filter),
Expand All @@ -543,14 +553,14 @@ private Collection<SourceDir> collectTestResources(PathFilter filter) {
final Path testClassesDir = getTestClassesDir();
if (resources.isEmpty()) {
return List.of(new DefaultSourceDir(
new DirectoryPathTree(resolveRelativeToBaseDir(null, "src/test/resources")),
new DirectoryPathTree(resolveRelativeToBaseDir(null, SRC_TEST_RESOURCES)),
new DirectoryPathTree(testClassesDir, filter), Map.of()));
}
final List<SourceDir> sourceDirs = new ArrayList<>(resources.size());
for (Resource r : resources) {
sourceDirs.add(
new DefaultSourceDir(
new DirectoryPathTree(resolveRelativeToBaseDir(r.getDirectory(), "src/test/resources")),
new DirectoryPathTree(resolveRelativeToBaseDir(r.getDirectory(), SRC_TEST_RESOURCES)),
new DirectoryPathTree((r.getTargetPath() == null ? testClassesDir
: testClassesDir.resolve(stripProjectBasedirPrefix(r.getTargetPath(), PROJECT_OUTPUT_DIR))),
filter),
Expand Down
Expand Up @@ -8,6 +8,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
Expand Down Expand Up @@ -69,6 +70,7 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra
private final Map<Path, LocalProject> projectCache = new HashMap<>();
private final Path currentProjectPom;
private Path workspaceRootPom;
private Function<Path, Model> modelProvider;

private ModelBuilder modelBuilder;
private ModelResolver modelResolver;
Expand All @@ -77,7 +79,9 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra
private List<String> inactiveProfileIds;
private List<Profile> profiles;

WorkspaceLoader(BootstrapMavenContext ctx, Path currentProjectPom) throws BootstrapMavenException {
WorkspaceLoader(BootstrapMavenContext ctx, Path currentProjectPom, Function<Path, Model> modelProvider)
throws BootstrapMavenException {
this.modelProvider = modelProvider;
if (ctx != null && ctx.isEffectiveModelBuilder()) {
modelBuilder = BootstrapModelBuilderFactory.getDefaultModelBuilder();
modelResolver = BootstrapModelResolver.newInstance(ctx, workspace);
Expand All @@ -100,7 +104,7 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra
private boolean isPom(Path p) {
if (Files.exists(p) && !Files.isDirectory(p)) {
try {
loadAndCacheRawModel(p);
rawModel(p);
return true;
} catch (BootstrapMavenException e) {
// not a POM file
Expand All @@ -115,7 +119,8 @@ private LocalProject project(Path pomFile) throws BootstrapMavenException {
}

private LocalProject loadAndCacheProject(Path pomFile) throws BootstrapMavenException {
final Model cachedRawModel = rawModelCache.get(pomFile.getParent());
Model cachedRawModel = rawModelCache.getOrDefault(pomFile.getParent(),
modelProvider == null ? null : modelProvider.apply(pomFile.getParent()));
final LocalProject project;
if (modelBuilder != null) {
ModelBuildingRequest req = new DefaultModelBuildingRequest();
Expand Down Expand Up @@ -148,7 +153,8 @@ private LocalProject loadAndCacheProject(Path pomFile) throws BootstrapMavenExce
}

private Model rawModel(Path pomFile) throws BootstrapMavenException {
final Model rawModel = rawModelCache.get(pomFile.getParent());
final Model rawModel = rawModelCache.getOrDefault(pomFile.getParent(),
modelProvider == null ? null : modelProvider.apply(pomFile.getParent()));
return rawModel == null ? loadAndCacheRawModel(pomFile) : rawModel;
}

Expand Down

0 comments on commit a426f6a

Please sign in to comment.