diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java index 7108a534536b0..b219f7e4e6745 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java @@ -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); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java index f2172937fda5d..387fcb3a42fe2 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java @@ -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; @@ -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; @@ -759,7 +762,6 @@ private String getSourceEncoding() { } private void addProject(MavenDevModeLauncher.Builder builder, ResolvedDependency module, boolean root) throws Exception { - if (!module.isJar()) { return; } @@ -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 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 diff --git a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java index 7815865536442..f340b2048d46d 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java @@ -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; @@ -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; @@ -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 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); } diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java index b456a5c4b3cbe..22114d0a2b0a4 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java @@ -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; @@ -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) { @@ -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 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); } diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java index efa4ffa77d939..8b645d5b0c2bc 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java @@ -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; @@ -33,6 +35,7 @@ public class BootstrapMavenContextConfig modelProvider; /** * Local repository location @@ -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 modelProvider) { + this.modelProvider = modelProvider; + return (T) this; + } + private BootstrapMavenOptions getInitializedCliOptions() { return cliOptions == null ? cliOptions = BootstrapMavenOptions.newInstance() : cliOptions; } diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java index 29e84613bfb0c..c2fa020ce577d 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java @@ -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}"; @@ -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; @@ -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 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)); @@ -257,11 +266,11 @@ public PathCollection getResourcesSourcesDirs() { final List 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))); } @@ -269,11 +278,11 @@ public PathCollection getTestResourcesSourcesDirs() { final List 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))); } @@ -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); } @@ -521,14 +531,14 @@ private Collection 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 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), @@ -543,14 +553,14 @@ private Collection 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 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), diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/WorkspaceLoader.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/WorkspaceLoader.java index 6a0cd9b562761..a30aad09d2f53 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/WorkspaceLoader.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/WorkspaceLoader.java @@ -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; @@ -69,6 +70,7 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra private final Map projectCache = new HashMap<>(); private final Path currentProjectPom; private Path workspaceRootPom; + private Function modelProvider; private ModelBuilder modelBuilder; private ModelResolver modelResolver; @@ -77,7 +79,9 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra private List inactiveProfileIds; private List profiles; - WorkspaceLoader(BootstrapMavenContext ctx, Path currentProjectPom) throws BootstrapMavenException { + WorkspaceLoader(BootstrapMavenContext ctx, Path currentProjectPom, Function modelProvider) + throws BootstrapMavenException { + this.modelProvider = modelProvider; if (ctx != null && ctx.isEffectiveModelBuilder()) { modelBuilder = BootstrapModelBuilderFactory.getDefaultModelBuilder(); modelResolver = BootstrapModelResolver.newInstance(ctx, workspace); @@ -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 @@ -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(); @@ -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; }