Skip to content

Commit dd8c95c

Browse files
authored
[MNG-8141][MNG-8147] Restore profile ID invariance but warn if duplicate IDs present (#1568)
Fix and improvement in one PR as they are closely related. First, this PR restores the ability (broken by MNG-8081) to calculate Profile activation for POMs with duplicate Profile ID. Second, this PR improves UX by warning them about invalid models in their build. The reproducer now looks like this: https://gist.github.com/cstamas/165a610b233f4c03e381a0a2697903eb Notice: * WARNs issued about models (all Maven versions are mute about this) * still, property `${javafx.platform}` properly evaluated just like in 3.9.6 (but not in 3.9.7) * build succeeds (fails in 3.9.7) --- https://issues.apache.org/jira/browse/MNG-8147 https://issues.apache.org/jira/browse/MNG-8141
1 parent 758e054 commit dd8c95c

File tree

2 files changed

+53
-44
lines changed

2 files changed

+53
-44
lines changed

maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,15 @@
2828
import java.util.Collection;
2929
import java.util.Collections;
3030
import java.util.HashMap;
31+
import java.util.HashSet;
3132
import java.util.Iterator;
3233
import java.util.LinkedHashSet;
3334
import java.util.List;
3435
import java.util.Map;
3536
import java.util.Objects;
3637
import java.util.Optional;
3738
import java.util.Properties;
38-
import java.util.Set;
3939
import java.util.function.Consumer;
40-
import java.util.stream.Collectors;
4140

4241
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
4342
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
@@ -305,18 +304,17 @@ protected ModelBuildingResult build(ModelBuildingRequest request, Collection<Str
305304

306305
profileActivationContext.setProjectProperties(tmpModel.getProperties());
307306

308-
Map<String, Activation> interpolatedActivations =
309-
getInterpolatedActivations(rawModel, profileActivationContext, problems);
310-
injectProfileActivations(tmpModel, interpolatedActivations);
307+
List<Profile> interpolatedProfiles = getInterpolatedProfiles(rawModel, profileActivationContext, problems);
308+
tmpModel.setProfiles(interpolatedProfiles);
311309

312310
List<Profile> activePomProfiles =
313311
profileSelector.getActiveProfiles(tmpModel.getProfiles(), profileActivationContext, problems);
314312

315-
Set<String> activeProfileIds =
316-
activePomProfiles.stream().map(Profile::getId).collect(Collectors.toSet());
317-
currentData.setActiveProfiles(rawModel.getProfiles().stream()
318-
.filter(p -> activeProfileIds.contains(p.getId()))
319-
.collect(Collectors.toList()));
313+
List<Profile> rawProfiles = new ArrayList<>();
314+
for (Profile activePomProfile : activePomProfiles) {
315+
rawProfiles.add(rawModel.getProfiles().get(interpolatedProfiles.indexOf(activePomProfile)));
316+
}
317+
currentData.setActiveProfiles(rawProfiles);
320318

321319
// profile injection
322320
for (Profile activeProfile : activePomProfiles) {
@@ -429,12 +427,12 @@ private interface InterpolateString {
429427
String apply(String s) throws InterpolationException;
430428
}
431429

432-
private Map<String, Activation> getInterpolatedActivations(
430+
private List<Profile> getInterpolatedProfiles(
433431
Model rawModel, DefaultProfileActivationContext context, DefaultModelProblemCollector problems) {
434-
Map<String, Activation> interpolatedActivations = getProfileActivations(rawModel, true);
432+
List<Profile> interpolatedActivations = getProfiles(rawModel, true);
435433

436434
if (interpolatedActivations.isEmpty()) {
437-
return Collections.emptyMap();
435+
return Collections.emptyList();
438436
}
439437
RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
440438

@@ -466,8 +464,14 @@ void performFor(String value, String locationKey, Consumer<String> mutator) {
466464
}
467465
}
468466
}
469-
for (Activation activation : interpolatedActivations.values()) {
470-
Optional<Activation> a = Optional.of(activation);
467+
HashSet<String> profileIds = new HashSet<>();
468+
for (Profile profile : interpolatedActivations) {
469+
if (!profileIds.add(profile.getId())) {
470+
problems.add(new ModelProblemCollectorRequest(Severity.WARNING, ModelProblem.Version.BASE)
471+
.setMessage("Duplicate activation for profile " + profile.getId()));
472+
}
473+
Activation activation = profile.getActivation();
474+
Optional<Activation> a = Optional.ofNullable(activation);
471475
a.map(Activation::getFile).ifPresent(fa -> {
472476
Interpolation nt =
473477
new Interpolation(fa, s -> profileActivationFilePathInterpolator.interpolate(s, context));
@@ -753,41 +757,20 @@ private void assembleInheritance(
753757
}
754758
}
755759

756-
private Map<String, Activation> getProfileActivations(Model model, boolean clone) {
757-
Map<String, Activation> activations = new HashMap<>();
760+
private List<Profile> getProfiles(Model model, boolean clone) {
761+
ArrayList<Profile> profiles = new ArrayList<>();
758762
for (Profile profile : model.getProfiles()) {
759-
Activation activation = profile.getActivation();
760-
761-
if (activation == null) {
762-
continue;
763-
}
764-
765763
if (clone) {
766-
activation = activation.clone();
764+
profile = profile.clone();
767765
}
768-
769-
activations.put(profile.getId(), activation);
770-
}
771-
772-
return activations;
773-
}
774-
775-
private void injectProfileActivations(Model model, Map<String, Activation> activations) {
776-
for (Profile profile : model.getProfiles()) {
777-
Activation activation = profile.getActivation();
778-
779-
if (activation == null) {
780-
continue;
781-
}
782-
783-
// restore activation
784-
profile.setActivation(activations.get(profile.getId()));
766+
profiles.add(profile);
785767
}
768+
return profiles;
786769
}
787770

788771
private Model interpolateModel(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
789772
// save profile activations before interpolation, since they are evaluated with limited scope
790-
Map<String, Activation> originalActivations = getProfileActivations(model, true);
773+
List<Profile> originalActivations = getProfiles(model, true);
791774

792775
Model interpolatedModel =
793776
modelInterpolator.interpolateModel(model, model.getProjectDirectory(), request, problems);
@@ -815,7 +798,7 @@ private Model interpolateModel(Model model, ModelBuildingRequest request, ModelP
815798
interpolatedModel.setPomFile(model.getPomFile());
816799

817800
// restore profiles with file activation to their value before full interpolation
818-
injectProfileActivations(model, originalActivations);
801+
model.setProfiles(originalActivations);
819802

820803
return interpolatedModel;
821804
}

maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import javax.inject.Singleton;
2424

2525
import java.util.LinkedHashSet;
26+
import java.util.List;
2627
import java.util.Map;
2728
import java.util.Objects;
2829
import java.util.Properties;
@@ -37,7 +38,9 @@
3738
import org.apache.maven.model.building.ModelBuilder;
3839
import org.apache.maven.model.building.ModelBuildingException;
3940
import org.apache.maven.model.building.ModelBuildingRequest;
41+
import org.apache.maven.model.building.ModelBuildingResult;
4042
import org.apache.maven.model.building.ModelProblem;
43+
import org.apache.maven.model.building.ModelProblemUtils;
4144
import org.apache.maven.model.resolution.UnresolvableModelException;
4245
import org.eclipse.aether.RepositoryEvent;
4346
import org.eclipse.aether.RepositoryEvent.EventType;
@@ -67,6 +70,8 @@
6770
import org.eclipse.aether.spi.locator.Service;
6871
import org.eclipse.aether.spi.locator.ServiceLocator;
6972
import org.eclipse.aether.transfer.ArtifactNotFoundException;
73+
import org.slf4j.Logger;
74+
import org.slf4j.LoggerFactory;
7075

7176
/**
7277
* @author Benjamin Bentmann
@@ -91,6 +96,8 @@ public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader
9196
private final ArtifactDescriptorReaderDelegate artifactDescriptorReaderDelegate =
9297
new ArtifactDescriptorReaderDelegate();
9398

99+
private final Logger logger = LoggerFactory.getLogger(getClass());
100+
94101
@Deprecated
95102
public DefaultArtifactDescriptorReader() {
96103
// enable no-arg constructor
@@ -281,7 +288,26 @@ private Model loadPom(
281288
modelRequest.setModelSource(new FileModelSource(pomArtifact.getFile()));
282289
}
283290

284-
model = modelBuilder.build(modelRequest).getEffectiveModel();
291+
ModelBuildingResult modelResult = modelBuilder.build(modelRequest);
292+
// ModelBuildingEx is thrown only on FATAL and ERROR severities, but we still can have WARNs
293+
// that may lead to unexpected build failure, log them
294+
if (!modelResult.getProblems().isEmpty()) {
295+
List<ModelProblem> problems = modelResult.getProblems();
296+
logger.warn(
297+
"{} {} encountered while building the effective model for {}",
298+
problems.size(),
299+
(problems.size() == 1) ? "problem was" : "problems were",
300+
request.getArtifact());
301+
if (logger.isDebugEnabled()) {
302+
for (ModelProblem problem : problems) {
303+
logger.warn(
304+
"{} @ {}",
305+
problem.getMessage(),
306+
ModelProblemUtils.formatLocation(problem, null));
307+
}
308+
}
309+
}
310+
model = modelResult.getEffectiveModel();
285311
} catch (ModelBuildingException e) {
286312
for (ModelProblem problem : e.getProblems()) {
287313
if (problem.getException() instanceof UnresolvableModelException) {

0 commit comments

Comments
 (0)