Skip to content
Open
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
Expand Up @@ -193,7 +193,9 @@ protected QuarkusBootstrap.Builder initBootstrapBuilder() throws Exception {
break;
}
}
boolean addProfileToParent = false;
if (profile == null) {
addProfileToParent = true;
for (Profile p : appPom.getProfiles()) {
if (p.getId().equals(profileModules.getKey())) {
profile = p;
Expand All @@ -205,13 +207,13 @@ protected QuarkusBootstrap.Builder initBootstrapBuilder() throws Exception {
"Failed to locate profile " + profileModules.getKey() + " in the application POM");
}
final Profile tmp = new Profile();
tmp.setId(profileModules.getKey());
tmp.setActivation(profile.getActivation());
profile = tmp;
parentPom.getProfiles().add(profile);
}

for (TsArtifact a : profileModules.getValue()) {
profile.getModules().add(a.getArtifactId());
profile.addModule(a.getArtifactId());
Model modulePom = a.getPomModel();
modulePom.setParent(parent);
final Path moduleDir = IoUtils.mkdirs(ws.resolve(modulePom.getArtifactId()));
Expand All @@ -226,6 +228,10 @@ protected QuarkusBootstrap.Builder initBootstrapBuilder() throws Exception {
IoUtils.copy(resolvedJar,
moduleTargetDir.resolve(modulePom.getArtifactId() + "-" + modulePom.getVersion() + ".jar"));
}

if (addProfileToParent) {
parentPom.addProfile(profile);
}
}

ModelUtils.persistModel(ws.resolve("pom.xml"), parentPom);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ protected TsArtifact composeApplication() {

appJar.addProfile(profile);

createWorkspace();

return appJar;
}

Expand Down
2 changes: 1 addition & 1 deletion devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,7 @@ private DevModeCommandLine newLauncher(String actualDebugPort, String bootstrapI
.setEffectiveModelBuilder(BootstrapMavenContextConfig.getEffectiveModelBuilderProperty(projectProperties))
.setRootProjectDir(rootProjectDir);
// to support Maven plugins and extensions manipulating POM files
QuarkusBootstrapProvider.setProjectModels(mvnConfig, session.getAllProjects(), toFiles(reloadPoms));
QuarkusBootstrapProvider.setProvidedModules(mvnConfig, session, toFiles(reloadPoms));

// There are a couple of reasons we don't want to use the original Maven session:
// 1) a reload could be triggered by a change in a pom.xml, in which case the Maven session might not be in sync anymore with the effective POM;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand All @@ -19,6 +20,7 @@

import org.apache.maven.SessionScoped;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Model;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
Expand Down Expand Up @@ -77,26 +79,46 @@ static ArtifactKey getProjectId(MavenProject project) {
return ArtifactKey.ga(project.getGroupId(), project.getArtifactId());
}

static void setProjectModels(BootstrapMavenContextConfig<?> config, List<MavenProject> allProjects, Set<File> reloadPoms) {
if (allProjects != null) {
for (MavenProject mp : allProjects) {
if (reloadPoms.contains(mp.getFile())) {
continue;
}
final Model model = getRawModel(mp);
config.addProvidedModule(mp.getFile().toPath(), model, mp.getModel());
// The Maven Model API determines the project directory as the directory containing the POM file.
// However, in case when plugins manipulating POMs store their results elsewhere
// (such as the flatten plugin storing the flattened POM under the target directory),
// both the base directory and the directory containing the POM file should be added to the map.
var pomDir = mp.getFile().getParentFile();
if (!pomDir.equals(mp.getBasedir())) {
config.addProvidedModule(mp.getBasedir().toPath().resolve("pom.xml"), model, mp.getModel());
}
static void setProvidedModules(BootstrapMavenContextConfig<?> config, MavenSession session, Set<File> reloadPoms) {
// sorting projects at this point is an optimization, not a requirement
for (MavenProject mp : getSortedProjects(session)) {
if (reloadPoms.contains(mp.getFile())) {
continue;
}
final Model model = getRawModel(mp);
config.addProvidedModule(mp.getFile().toPath(), model, mp.getModel());
// The Maven Model API determines the project directory as the directory containing the POM file.
// However, in case when plugins manipulating POMs store their results elsewhere
// (such as the flatten plugin storing the flattened POM under the target directory),
// both the base directory and the directory containing the POM file should be added to the map.
var pomDir = mp.getFile().getParentFile();
if (!pomDir.equals(mp.getBasedir())) {
config.addProvidedModule(mp.getBasedir().toPath().resolve("pom.xml"), model, mp.getModel());
}
}
}

private static List<MavenProject> getSortedProjects(MavenSession session) {
if (session.getAllProjects().size() == session.getProjects().size()) {
// these are supposed to be sorted already
return session.getProjects();
}
final List<MavenProject> sorted = new ArrayList<>(session.getAllProjects().size());
addAfterParent(session.getTopLevelProject(), new HashSet<>(session.getAllProjects().size()), sorted);
return sorted;
}

private static void addAfterParent(MavenProject project, Set<File> added, List<MavenProject> sorted) {
if (!added.add(project.getFile())) {
return;
}
MavenProject parent = project.getParent();
if (parent != null) {
addAfterParent(parent, added, sorted);
}
sorted.add(project);
}

/**
* This method is meant to return the "raw" model, i.e. the one that would be obtained
* by reading a {@code pom.xml} file, w/o interpolation, flattening, etc.
Expand Down Expand Up @@ -234,7 +256,7 @@ private MavenArtifactResolver artifactResolver(QuarkusBootstrapMojo mojo, Launch
.setRemoteRepositories(mojo.remoteRepositories())
.setEffectiveModelBuilder(BootstrapMavenContextConfig
.getEffectiveModelBuilderProperty(mojo.mavenProject().getProperties()));
setProjectModels(config, mojo.mavenSession().getAllProjects(), mojo.reloadPoms);
setProvidedModules(config, mojo.mavenSession(), mojo.reloadPoms);
var resolver = workspaceProvider.createArtifactResolver(config);
final LocalProject currentProject = resolver.getMavenContext().getCurrentProject();
if (currentProject != null && workspaceId == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,6 @@ public class ApplicationDependencyResolver {
private static final byte COLLECT_DEPLOYMENT_INJECTION_POINTS = 0b1000;
/* @formatter:on */

/**
* Whether to use a blocking or non-blocking dependency resolution and processing task runner
*/
private static final boolean BLOCKING_TASK_RUNNER = Boolean.getBoolean("quarkus.bootstrap.blocking-task-runner");

public static ApplicationDependencyResolver newInstance() {
return new ApplicationDependencyResolver();
}
Expand All @@ -89,8 +84,7 @@ public static ApplicationDependencyResolver newInstance() {
* @return task runner
*/
private static ModelResolutionTaskRunner getTaskRunner() {
return BLOCKING_TASK_RUNNER ? ModelResolutionTaskRunner.getBlockingTaskRunner()
: ModelResolutionTaskRunner.getNonBlockingTaskRunner();
return ModelResolutionTaskRunnerFactory.newTaskRunner();
}

private final ExtensionInfo EXT_INFO_NONE = new ExtensionInfo();
Expand Down Expand Up @@ -371,12 +365,12 @@ private void injectDeploymentDeps() {
private Collection<AppDep> collectDeploymentDeps() {
final ConcurrentLinkedDeque<AppDep> injectQueue = new ConcurrentLinkedDeque<>();
final ModelResolutionTaskRunner taskRunner;
if (deploymentInjectionPoints.size() == 1 || BLOCKING_TASK_RUNNER) {
taskRunner = ModelResolutionTaskRunner.getBlockingTaskRunner();
if (deploymentInjectionPoints.size() == 1 || ModelResolutionTaskRunnerFactory.isDefaultRunnerBlocking()) {
taskRunner = ModelResolutionTaskRunnerFactory.getBlockingTaskRunner();
} else {
// We've been running into Maven resolver failures to acquire a lock to a local fail when resolving dependencies lately.
// This error handler will catch those errors and will re-try the corresponding tasks with the blocking task runner.
taskRunner = ModelResolutionTaskRunner.getNonBlockingTaskRunner(new RetryLockAcquisitionErrorHandler());
taskRunner = ModelResolutionTaskRunnerFactory.getNonBlockingTaskRunner(new RetryLockAcquisitionErrorHandler());
}
for (AppDep extDep : deploymentInjectionPoints) {
extDep.scheduleCollectDeploymentDeps(taskRunner, injectQueue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,56 @@
public interface ModelResolutionTaskRunner {

/**
* Returns an instance of a non-blocking task runner with an error handler
* that collects all task execution errors and throws a single error when all the tasks
* have finished.
* @deprecated in favor of {@link ModelResolutionTaskRunnerFactory#getNonBlockingTaskRunner()}
*
* Returns an instance of a non-blocking task runner with an error handler
* that collects all task execution errors and throws a single error when all the tasks
* have finished.
*
* @return an instance of a non-blocking task runner
*/
@Deprecated(forRemoval = true)
static ModelResolutionTaskRunner getNonBlockingTaskRunner() {
return getNonBlockingTaskRunner(new FailAtCompletionErrorHandler());
return ModelResolutionTaskRunnerFactory.getNonBlockingTaskRunner();
}

/**
* Returns an instance of a non-blocking task runner with a custom error handler.
* @deprecated in favor of
* {@link ModelResolutionTaskRunnerFactory#getNonBlockingTaskRunner(ModelResolutionTaskErrorHandler)}
*
* Returns an instance of a non-blocking task runner with a custom error handler.
*
* @param errorHandler error handler
* @return an instance of non-blocking task runner
*/
@Deprecated(forRemoval = true)
static ModelResolutionTaskRunner getNonBlockingTaskRunner(ModelResolutionTaskErrorHandler errorHandler) {
return new NonBlockingModelResolutionTaskRunner(errorHandler);
return ModelResolutionTaskRunnerFactory.getNonBlockingTaskRunner(errorHandler);
}

/**
* Returns an instance of a blocking task runner with no error handler.
* Exceptions thrown from tasks will be immediately propagated to the caller.
* @deprecated in favor of {@link ModelResolutionTaskRunnerFactory#getBlockingTaskRunner()}
*
* Returns an instance of a blocking task runner with no error handler.
* Exceptions thrown from tasks will be immediately propagated to the caller.
*
* @return an instance of a blocking task runner
*/
@Deprecated(forRemoval = true)
static ModelResolutionTaskRunner getBlockingTaskRunner() {
return BlockingModelResolutionTaskRunner.getInstance();
return ModelResolutionTaskRunnerFactory.getBlockingTaskRunner();
}

/**
* Returns an instance of a blocking task runner with a custom error handler.
* @deprecated in favor of {@link ModelResolutionTaskRunnerFactory#getBlockingTaskRunner(ModelResolutionTaskErrorHandler)}
*
* Returns an instance of a blocking task runner with a custom error handler.
*
* @return an instance of a blocking task runner
*/
@Deprecated(forRemoval = true)
static ModelResolutionTaskRunner getBlockingTaskRunner(ModelResolutionTaskErrorHandler errorHandler) {
return BlockingModelResolutionTaskRunner.getInstance(errorHandler);
return ModelResolutionTaskRunnerFactory.getBlockingTaskRunner(errorHandler);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.quarkus.bootstrap.resolver.maven;

public class ModelResolutionTaskRunnerFactory {

/**
* Whether to use a blocking or non-blocking dependency resolution and processing task runner
*/
private static final boolean BLOCKING_TASK_RUNNER = Boolean.getBoolean("quarkus.bootstrap.blocking-task-runner");

public static boolean isDefaultRunnerBlocking() {
return BLOCKING_TASK_RUNNER;
}

/**
* New instance of {@link ModelResolutionTaskRunner}. Unless system property {@code quarkus.bootstrap.blocking-task-runner}
* is set to {@code true}, the returned runner will not be blocking.
*
* @return new task runner instance
*/
public static ModelResolutionTaskRunner newTaskRunner() {
return BLOCKING_TASK_RUNNER ? getBlockingTaskRunner() : getNonBlockingTaskRunner();
}

/**
* Returns an instance of a non-blocking task runner with an error handler
* that collects all task execution errors and throws a single error when all the tasks
* have finished.
*
* @return an instance of a non-blocking task runner
*/
public static ModelResolutionTaskRunner getNonBlockingTaskRunner() {
return getNonBlockingTaskRunner(new FailAtCompletionErrorHandler());
}

/**
* Returns an instance of a non-blocking task runner with a custom error handler.
*
* @param errorHandler error handler
* @return an instance of non-blocking task runner
*/
public static ModelResolutionTaskRunner getNonBlockingTaskRunner(ModelResolutionTaskErrorHandler errorHandler) {
return new NonBlockingModelResolutionTaskRunner(errorHandler);
}

/**
* Returns an instance of a blocking task runner with no error handler.
* Exceptions thrown from tasks will be immediately propagated to the caller.
*
* @return an instance of a blocking task runner
*/
public static ModelResolutionTaskRunner getBlockingTaskRunner() {
return BlockingModelResolutionTaskRunner.getInstance();
}

/**
* Returns an instance of a blocking task runner with a custom error handler.
*
* @return an instance of a blocking task runner
*/
public static ModelResolutionTaskRunner getBlockingTaskRunner(ModelResolutionTaskErrorHandler errorHandler) {
return BlockingModelResolutionTaskRunner.getInstance(errorHandler);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,21 +176,22 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra
}

LocalProject(Model rawModel, LocalWorkspace workspace) {
this(rawModel, null, workspace);
this(ModelUtils.getGroupId(rawModel), ModelUtils.getVersion(rawModel), rawModel, null, workspace);
}

LocalProject(Model rawModel, Model effectiveModel, LocalWorkspace workspace) {
LocalProject(String resolvedGroupId, String resolvedVersion, Model rawModel, Model effectiveModel,
LocalWorkspace workspace) {
this.rawModel = rawModel;
this.effectiveModel = effectiveModel;
this.modelBuildingResult = null;
// Maven does not guarantee the projectDirectory will be normalized
this.dir = rawModel.getProjectDirectory().toPath().normalize().toAbsolutePath();
this.workspace = workspace;
this.key = ArtifactKey.ga(ModelUtils.getGroupId(rawModel), rawModel.getArtifactId());
this.key = ArtifactKey.ga(resolvedGroupId, rawModel.getArtifactId());

final String rawVersion = ModelUtils.getRawVersion(rawModel);
final boolean rawVersionIsUnresolved = ModelUtils.isUnresolvedVersion(rawVersion);
version = rawVersionIsUnresolved ? ModelUtils.resolveVersion(rawVersion, rawModel) : rawVersion;
final String rawVersion = ModelUtils.getRawVersionOrNull(rawModel);
final boolean rawVersionIsUnresolved = rawVersion == null || ModelUtils.isUnresolvedVersion(rawVersion);
version = resolvedVersion;

if (workspace != null) {
workspace.addProject(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,33 @@ public static String getGroupId(Model model) {
throw new IllegalStateException("Failed to determine groupId for project model");
}

/**
* Returns the raw version of the model. This method returns the result of {@link #getRawVersionOrNull(Model)}
* except if it's null, it throws an exception.
*
* @param model POM
* @return raw model
*/
public static String getRawVersion(Model model) {
String version = getRawVersionOrNull(model);
if (version != null) {
return version;
}
throw new IllegalStateException("Failed to determine version for project model");
}

/**
* Returns the raw version of the model. If the model does not include
* the version directly, it will return the version of the parent.
* the version directly and the coordinates of the parent artifact are configured,
* the parent version will be returned.
* If the parent coordinates are not configured, the method will return null.
* The version is raw in a sense if it's a property expression, the
* expression will not be resolved.
*
* @param model POM
* @return raw model
*/
public static String getRawVersion(Model model) {
public static String getRawVersionOrNull(Model model) {
String version = model.getVersion();
if (version != null) {
return version;
Expand All @@ -163,7 +180,7 @@ public static String getRawVersion(Model model) {
return version;
}
}
throw new IllegalStateException("Failed to determine version for project model");
return null;
}

public static String getVersion(Model model) {
Expand Down Expand Up @@ -239,7 +256,7 @@ public static Model readModel(final Path pomXml) throws IOException {

public static Model readModel(InputStream stream) throws IOException {
try (InputStream is = stream) {
return new MavenXpp3Reader().read(stream);
return new MavenXpp3Reader().read(is);
} catch (XmlPullParserException e) {
throw new IOException("Failed to parse POM", e);
}
Expand Down
Loading
Loading