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 3cb487db33953..6f5ebef76c8ac 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java @@ -95,6 +95,7 @@ import io.quarkus.maven.components.MavenVersionEnforcer; import io.quarkus.maven.dependency.GACT; import io.quarkus.maven.dependency.GACTV; +import io.quarkus.runtime.LaunchMode; /** * The dev mojo, that runs a quarkus app in a forked process. A background compilation process is launched and any changes are @@ -512,12 +513,13 @@ private void handleAutoCompile() throws MojoExecutionException { } private void initToolchain() throws MojoExecutionException { - executeIfConfigured(ORG_APACHE_MAVEN_PLUGINS, MAVEN_TOOLCHAINS_PLUGIN, "toolchain"); + executeIfConfigured(ORG_APACHE_MAVEN_PLUGINS, MAVEN_TOOLCHAINS_PLUGIN, "toolchain", Collections.emptyMap()); } private void triggerPrepare() throws MojoExecutionException { final PluginDescriptor pluginDescr = getPluginDescriptor(); - executeIfConfigured(pluginDescr.getGroupId(), pluginDescr.getArtifactId(), QUARKUS_GENERATE_CODE_GOAL); + executeIfConfigured(pluginDescr.getGroupId(), pluginDescr.getArtifactId(), QUARKUS_GENERATE_CODE_GOAL, + Collections.singletonMap("mode", LaunchMode.DEVELOPMENT.name())); } private PluginDescriptor getPluginDescriptor() { @@ -528,10 +530,12 @@ private void triggerCompile(boolean test) throws MojoExecutionException { handleResources(test); // compile the Kotlin sources if needed - executeIfConfigured(ORG_JETBRAINS_KOTLIN, KOTLIN_MAVEN_PLUGIN, test ? "test-compile" : "compile"); + executeIfConfigured(ORG_JETBRAINS_KOTLIN, KOTLIN_MAVEN_PLUGIN, test ? "test-compile" : "compile", + Collections.emptyMap()); // Compile the Java sources if needed - executeIfConfigured(ORG_APACHE_MAVEN_PLUGINS, MAVEN_COMPILER_PLUGIN, test ? "testCompile" : "compile"); + executeIfConfigured(ORG_APACHE_MAVEN_PLUGINS, MAVEN_COMPILER_PLUGIN, test ? "testCompile" : "compile", + Collections.emptyMap()); } /** @@ -542,16 +546,18 @@ private void handleResources(boolean test) throws MojoExecutionException { if (resources.isEmpty()) { return; } - executeIfConfigured(ORG_APACHE_MAVEN_PLUGINS, MAVEN_RESOURCES_PLUGIN, test ? "testResources" : "resources"); + executeIfConfigured(ORG_APACHE_MAVEN_PLUGINS, MAVEN_RESOURCES_PLUGIN, test ? "testResources" : "resources", + Collections.emptyMap()); } - private void executeIfConfigured(String pluginGroupId, String pluginArtifactId, String goal) throws MojoExecutionException { + private void executeIfConfigured(String pluginGroupId, String pluginArtifactId, String goal, Map params) + throws MojoExecutionException { final Plugin plugin = getConfiguredPluginOrNull(pluginGroupId, pluginArtifactId); if (!isGoalConfigured(plugin, goal)) { return; } getLog().info("Invoking " + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":" + plugin.getVersion() + ":" + goal - + " @ " + project.getArtifactId()); + + ") @ " + project.getArtifactId()); executeMojo( plugin( groupId(pluginGroupId), @@ -559,7 +565,7 @@ private void executeIfConfigured(String pluginGroupId, String pluginArtifactId, version(plugin.getVersion()), plugin.getDependencies()), goal(goal), - getPluginConfig(plugin, goal), + getPluginConfig(plugin, goal, params), executionEnvironment( project, session, @@ -578,7 +584,7 @@ public boolean isGoalConfigured(Plugin plugin, String goal) { return false; } - private Xpp3Dom getPluginConfig(Plugin plugin, String goal) throws MojoExecutionException { + private Xpp3Dom getPluginConfig(Plugin plugin, String goal, Map params) throws MojoExecutionException { Xpp3Dom mergedConfig = null; if (!plugin.getExecutions().isEmpty()) { for (PluginExecution exec : plugin.getExecutions()) { @@ -611,6 +617,12 @@ private Xpp3Dom getPluginConfig(Plugin plugin, String goal) throws MojoExecution } } + for (Map.Entry param : params.entrySet()) { + final Xpp3Dom p = new Xpp3Dom(param.getKey()); + p.setValue(param.getValue()); + configuration.addChild(p); + } + return configuration; } @@ -889,28 +901,35 @@ private QuarkusDevModeLauncher newLauncher() throws Exception { setKotlinSpecificFlags(builder); - final MavenArtifactResolver.Builder resolverBuilder = MavenArtifactResolver.builder() - .setRepositorySystem(repoSystem) - .setRemoteRepositories(repos) - .setRemoteRepositoryManager(remoteRepositoryManager) - .setWorkspaceDiscovery(true); - // path to the serialized application model final Path appModelLocation = resolveSerializedModelLocation(); - // 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) { - Files.delete(appModelLocation); + + ApplicationModel appModel = bootstrapProvider + .getResolvedApplicationModel(QuarkusBootstrapProvider.getProjectId(project), LaunchMode.DEVELOPMENT); + if (appModel != null) { + bootstrapProvider.close(); } else { - // we can re-use the original Maven session - resolverBuilder.setRepositorySystemSession(repoSession); - } + final MavenArtifactResolver.Builder resolverBuilder = MavenArtifactResolver.builder() + .setRepositorySystem(repoSystem) + .setRemoteRepositories(repos) + .setRemoteRepositoryManager(remoteRepositoryManager) + .setWorkspaceDiscovery(true); + + // 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) { + Files.delete(appModelLocation); + } else { + // we can re-use the original Maven session + resolverBuilder.setRepositorySystemSession(repoSession); + } - final ApplicationModel appModel = new BootstrapAppModelResolver(resolverBuilder.build()) - .setDevMode(true) - .setCollectReloadableDependencies(!noDeps) - .resolveModel(new GACTV(project.getGroupId(), project.getArtifactId(), null, "jar", project.getVersion())); + appModel = new BootstrapAppModelResolver(resolverBuilder.build()) + .setDevMode(true) + .setCollectReloadableDependencies(!noDeps) + .resolveModel(new GACTV(project.getGroupId(), project.getArtifactId(), null, "jar", project.getVersion())); + } // serialize the app model to avoid re-resolving it in the dev process BootstrapUtils.serializeAppModel(appModel, appModelLocation); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeMojo.java index 72298abdd7975..d233f5881ed5d 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeMojo.java @@ -17,6 +17,7 @@ import io.quarkus.bootstrap.classloading.QuarkusClassLoader; import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.bootstrap.model.PathsCollection; +import io.quarkus.runtime.LaunchMode; @Mojo(name = "generate-code", defaultPhase = LifecyclePhase.GENERATE_SOURCES, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, threadSafe = true) public class GenerateCodeMojo extends QuarkusBootstrapMojo { @@ -27,6 +28,9 @@ public class GenerateCodeMojo extends QuarkusBootstrapMojo { @Parameter(defaultValue = "false", property = "quarkus.generate-code.skip", alias = "quarkus.prepare.skip") private boolean skipSourceGeneration = false; + @Parameter(defaultValue = "NORMAL", property = "launchMode") + String mode; + @Override protected boolean beforeExecute() throws MojoExecutionException, MojoFailureException { if (mavenProject().getPackaging().equals("pom")) { @@ -51,10 +55,15 @@ void generateCode(Path sourcesDir, Consumer sourceRegistrar, boolean test) throws MojoFailureException, MojoExecutionException { + final LaunchMode launchMode = test ? LaunchMode.TEST : LaunchMode.valueOf(mode); + if (getLog().isDebugEnabled()) { + getLog().debug("Bootstrapping Quarkus application in mode " + launchMode); + } + ClassLoader originalTccl = Thread.currentThread().getContextClassLoader(); try { - final CuratedApplication curatedApplication = bootstrapApplication(); + final CuratedApplication curatedApplication = bootstrapApplication(launchMode); QuarkusClassLoader deploymentClassLoader = curatedApplication.createDeploymentClassLoader(); Thread.currentThread().setContextClassLoader(deploymentClassLoader); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapMojo.java index b5a93ef33dc7a..95c36a7715b42 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapMojo.java @@ -20,9 +20,8 @@ import org.eclipse.aether.repository.RemoteRepository; import io.quarkus.bootstrap.app.CuratedApplication; -import io.quarkus.bootstrap.app.QuarkusBootstrap; -import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; -import io.quarkus.maven.dependency.GACT; +import io.quarkus.maven.dependency.ArtifactKey; +import io.quarkus.runtime.LaunchMode; public abstract class QuarkusBootstrapMojo extends AbstractMojo { @@ -114,7 +113,7 @@ public abstract class QuarkusBootstrapMojo extends AbstractMojo { @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true) private MojoExecution mojoExecution; - private GACT projectId; + private ArtifactKey projectId; @Override public void execute() throws MojoExecutionException, MojoFailureException { @@ -199,19 +198,15 @@ protected String executionId() { return mojoExecution.getExecutionId(); } - protected GACT projectId() { - return projectId == null ? projectId = new GACT(project.getGroupId(), project.getArtifactId()) : projectId; + protected ArtifactKey projectId() { + return projectId == null ? projectId = QuarkusBootstrapProvider.getProjectId(project) : projectId; } - protected MavenArtifactResolver artifactResolver() throws MojoExecutionException { - return bootstrapProvider.artifactResolver(this); - } - - protected QuarkusBootstrap bootstrapQuarkus() throws MojoExecutionException { - return bootstrapProvider.bootstrapQuarkus(this); + protected CuratedApplication bootstrapApplication() throws MojoExecutionException { + return bootstrapApplication(LaunchMode.NORMAL); } - protected CuratedApplication bootstrapApplication() throws MojoExecutionException { - return bootstrapProvider.bootstrapApplication(this); + protected CuratedApplication bootstrapApplication(LaunchMode mode) throws MojoExecutionException { + return bootstrapProvider.bootstrapApplication(this, mode); } } 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 6580edc738d49..8e587e88f8808 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java @@ -7,7 +7,11 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Properties; +import java.util.Set; import java.util.concurrent.ExecutionException; import org.apache.maven.artifact.Artifact; @@ -16,7 +20,6 @@ import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.impl.RemoteRepositoryManager; import com.google.common.cache.Cache; @@ -25,13 +28,17 @@ import io.quarkus.bootstrap.BootstrapException; import io.quarkus.bootstrap.app.CuratedApplication; import io.quarkus.bootstrap.app.QuarkusBootstrap; -import io.quarkus.bootstrap.model.AppArtifactKey; +import io.quarkus.bootstrap.model.ApplicationModel; +import io.quarkus.bootstrap.resolver.AppModelResolverException; +import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.maven.dependency.ArtifactCoords; +import io.quarkus.maven.dependency.ArtifactKey; import io.quarkus.maven.dependency.GACT; import io.quarkus.maven.dependency.GACTV; import io.quarkus.maven.dependency.ResolvedArtifactDependency; -import io.quarkus.maven.dependency.ResolvedDependency; +import io.quarkus.runtime.LaunchMode; import io.smallrye.common.expression.Expression; @Component(role = QuarkusBootstrapProvider.class, instantiationStrategy = "singleton") @@ -46,6 +53,10 @@ public class QuarkusBootstrapProvider implements Closeable { private final Cache appBootstrapProviders = CacheBuilder.newBuilder() .concurrencyLevel(4).softValues().initialCapacity(10).build(); + static ArtifactKey getProjectId(MavenProject project) { + return new GACT(project.getGroupId(), project.getArtifactId()); + } + public RepositorySystem repositorySystem() { return repoSystem; } @@ -54,7 +65,7 @@ public RemoteRepositoryManager remoteRepositoryManager() { return remoteRepoManager; } - private QuarkusAppBootstrapProvider provider(GACT projectId, String executionId) { + private QuarkusAppBootstrapProvider provider(ArtifactKey projectId, String executionId) { try { return appBootstrapProviders.get(String.format("%s-%s", projectId, executionId), QuarkusAppBootstrapProvider::new); } catch (ExecutionException e) { @@ -63,19 +74,26 @@ private QuarkusAppBootstrapProvider provider(GACT projectId, String executionId) } } - public MavenArtifactResolver artifactResolver(QuarkusBootstrapMojo mojo) - throws MojoExecutionException { - return provider(mojo.projectId(), mojo.executionId()).artifactResolver(mojo); - } - - public QuarkusBootstrap bootstrapQuarkus(QuarkusBootstrapMojo mojo) + public CuratedApplication bootstrapApplication(QuarkusBootstrapMojo mojo, LaunchMode mode) throws MojoExecutionException { - return provider(mojo.projectId(), mojo.executionId()).bootstrapQuarkus(mojo); + return provider(mojo.projectId(), mojo.executionId()).bootstrapApplication(mojo, mode); } - public CuratedApplication bootstrapApplication(QuarkusBootstrapMojo mojo) - throws MojoExecutionException { - return provider(mojo.projectId(), mojo.executionId()).curateApplication(mojo); + public ApplicationModel getResolvedApplicationModel(ArtifactKey projectId, LaunchMode mode) { + if (appBootstrapProviders.size() == 0) { + return null; + } + final QuarkusAppBootstrapProvider provider = appBootstrapProviders.getIfPresent(projectId + "-null"); + if (provider == null) { + return null; + } + if (mode == LaunchMode.DEVELOPMENT) { + return provider.devApp == null ? null : provider.devApp.getApplicationModel(); + } + if (mode == LaunchMode.TEST) { + return provider.testApp == null ? null : provider.testApp.getApplicationModel(); + } + return provider.prodApp == null ? null : provider.prodApp.getApplicationModel(); } @Override @@ -94,19 +112,16 @@ public void close() throws IOException { private class QuarkusAppBootstrapProvider implements Closeable { - private ResolvedDependency appArtifact; - private MavenArtifactResolver artifactResolver; - private QuarkusBootstrap quarkusBootstrap; - private CuratedApplication curatedApp; + private CuratedApplication prodApp; + private CuratedApplication devApp; + private CuratedApplication testApp; - private MavenArtifactResolver artifactResolver(QuarkusBootstrapMojo mojo) + private MavenArtifactResolver artifactResolver(QuarkusBootstrapMojo mojo, LaunchMode mode) throws MojoExecutionException { - if (artifactResolver != null) { - return artifactResolver; - } try { - return artifactResolver = MavenArtifactResolver.builder() - .setWorkspaceDiscovery(false) + return MavenArtifactResolver.builder() + .setWorkspaceDiscovery(mode == LaunchMode.DEVELOPMENT || mode == LaunchMode.TEST) + .setPreferPomsFromWorkspace(mode == LaunchMode.DEVELOPMENT || mode == LaunchMode.TEST) .setRepositorySystem(repoSystem) .setRepositorySystemSession(mojo.repositorySystemSession()) .setRemoteRepositories(mojo.remoteRepositories()) @@ -117,11 +132,8 @@ private MavenArtifactResolver artifactResolver(QuarkusBootstrapMojo mojo) } } - protected QuarkusBootstrap bootstrapQuarkus(QuarkusBootstrapMojo mojo) throws MojoExecutionException { - if (quarkusBootstrap != null) { - return quarkusBootstrap; - } - + protected CuratedApplication doBootstrap(QuarkusBootstrapMojo mojo, LaunchMode mode) + throws MojoExecutionException { final Properties projectProperties = mojo.mavenProject().getProperties(); final Properties effectiveProperties = new Properties(); // quarkus. properties > ignoredEntries in pom.xml @@ -157,36 +169,52 @@ protected QuarkusBootstrap bootstrapQuarkus(QuarkusBootstrapMojo mojo) throws Mo } } + final BootstrapAppModelResolver modelResolver = new BootstrapAppModelResolver(artifactResolver(mojo, mode)) + .setDevMode(mode == LaunchMode.DEVELOPMENT) + .setTest(mode == LaunchMode.TEST); + + final List localProjects = mojo.mavenProject().getCollectedProjects(); + final Set reloadableModules = new HashSet<>(localProjects.size() + 1); + final ArtifactCoords artifactCoords = appArtifact(mojo); + reloadableModules.add(new GACT(artifactCoords.getGroupId(), artifactCoords.getArtifactId())); + for (MavenProject project : localProjects) { + reloadableModules.add(new GACT(project.getGroupId(), project.getArtifactId())); + } + + final ApplicationModel appModel; + try { + appModel = modelResolver.resolveManagedModel(artifactCoords, Collections.emptyList(), managingProject(mojo), + reloadableModules); + } catch (AppModelResolverException e) { + throw new MojoExecutionException("Failed to bootstrap application in " + mode + " mode", e); + } + QuarkusBootstrap.Builder builder = QuarkusBootstrap.builder() - .setAppArtifact(appArtifact(mojo)) - .setManagingProject(managingProject(mojo)) - .setMavenArtifactResolver(artifactResolver(mojo)) + .setAppArtifact(appModel.getAppArtifact()) + .setExistingModel(appModel) .setIsolateDeployment(true) .setBaseClassLoader(getClass().getClassLoader()) .setBuildSystemProperties(effectiveProperties) - .setLocalProjectDiscovery(false) .setProjectRoot(mojo.baseDir().toPath()) .setBaseName(mojo.finalName()) .setTargetDirectory(mojo.buildDir().toPath()); - for (MavenProject project : mojo.mavenProject().getCollectedProjects()) { - builder.addLocalArtifact(new AppArtifactKey(project.getGroupId(), project.getArtifactId())); + try { + return builder.build().bootstrap(); + } catch (BootstrapException e) { + throw new MojoExecutionException("Failed to bootstrap the application", e); } - - return quarkusBootstrap = builder.build(); } - protected CuratedApplication curateApplication(QuarkusBootstrapMojo mojo) throws MojoExecutionException { - if (curatedApp != null) { - return curatedApp; + protected CuratedApplication bootstrapApplication(QuarkusBootstrapMojo mojo, LaunchMode mode) + throws MojoExecutionException { + if (mode == LaunchMode.DEVELOPMENT) { + return devApp == null ? devApp = doBootstrap(mojo, mode) : devApp; } - try { - return curatedApp = bootstrapQuarkus(mojo).bootstrap(); - } catch (MojoExecutionException e) { - throw e; - } catch (BootstrapException e) { - throw new MojoExecutionException("Failed to bootstrap the application", e); + if (mode == LaunchMode.TEST) { + return testApp == null ? testApp = doBootstrap(mojo, mode) : testApp; } + return prodApp == null ? prodApp = doBootstrap(mojo, mode) : prodApp; } protected GACTV managingProject(QuarkusBootstrapMojo mojo) { @@ -199,11 +227,8 @@ protected GACTV managingProject(QuarkusBootstrapMojo mojo) { artifact.getVersion()); } - private ResolvedDependency appArtifact(QuarkusBootstrapMojo mojo) throws MojoExecutionException { - return appArtifact == null ? appArtifact = initAppArtifact(mojo) : appArtifact; - } - - private ResolvedDependency initAppArtifact(QuarkusBootstrapMojo mojo) throws MojoExecutionException { + private ArtifactCoords appArtifact(QuarkusBootstrapMojo mojo) + throws MojoExecutionException { String appArtifactCoords = mojo.appArtifactCoords(); if (appArtifactCoords == null) { final Artifact projectArtifact = mojo.mavenProject().getArtifact(); @@ -268,27 +293,23 @@ private ResolvedDependency initAppArtifact(QuarkusBootstrapMojo mojo) throws Moj } } - if (path == null) { - try { - path = artifactResolver(mojo).resolve(new DefaultArtifact(groupId, artifactId, classifier, type, version)) - .getArtifact().getFile().toPath(); - } catch (MojoExecutionException e) { - throw e; - } catch (Exception e) { - throw new MojoExecutionException("Failed to resolve " + appArtifact, e); - } - } - return new ResolvedArtifactDependency(groupId, artifactId, classifier, type, version, path); + return new GACTV(groupId, artifactId, classifier, type, version); } @Override public void close() { - if (curatedApp != null) { - curatedApp.close(); - curatedApp = null; + if (prodApp != null) { + prodApp.close(); + prodApp = null; + } + if (devApp != null) { + devApp.close(); + devApp = null; + } + if (testApp != null) { + testApp.close(); + testApp = null; } - appArtifact = null; - quarkusBootstrap = null; } } }