Skip to content

Commit f36d41c

Browse files
committed
[MNG-5235] interpolate available properties during default profile selection
1 parent a137cc6 commit f36d41c

File tree

3 files changed

+161
-1
lines changed

3 files changed

+161
-1
lines changed

maven-model-builder/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ under the License.
8787
<artifactId>xmlunit-matchers</artifactId>
8888
<scope>test</scope>
8989
</dependency>
90+
<dependency>
91+
<groupId>org.mockito</groupId>
92+
<artifactId>mockito-core</artifactId>
93+
<scope>test</scope>
94+
</dependency>
9095
<dependency>
9196
<groupId>org.powermock</groupId>
9297
<artifactId>powermock-reflect</artifactId>

maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,27 @@
2222
import javax.inject.Named;
2323
import javax.inject.Singleton;
2424

25+
import java.io.File;
2526
import java.util.ArrayList;
2627
import java.util.Collection;
28+
import java.util.Collections;
2729
import java.util.HashSet;
2830
import java.util.List;
31+
import java.util.Map;
32+
import java.util.Properties;
33+
import java.util.function.UnaryOperator;
34+
import java.util.stream.Collectors;
2935

3036
import org.apache.maven.model.Activation;
37+
import org.apache.maven.model.Model;
3138
import org.apache.maven.model.Profile;
39+
import org.apache.maven.model.building.DefaultModelBuildingRequest;
40+
import org.apache.maven.model.building.ModelBuildingRequest;
3241
import org.apache.maven.model.building.ModelProblem.Severity;
3342
import org.apache.maven.model.building.ModelProblem.Version;
3443
import org.apache.maven.model.building.ModelProblemCollector;
3544
import org.apache.maven.model.building.ModelProblemCollectorRequest;
45+
import org.apache.maven.model.interpolation.ModelInterpolator;
3646
import org.apache.maven.model.profile.activation.ProfileActivator;
3747

3848
/**
@@ -44,16 +54,35 @@
4454
@Singleton
4555
public class DefaultProfileSelector implements ProfileSelector {
4656

57+
private static Properties asProperties(Map<String, String> m) {
58+
return m.entrySet().stream()
59+
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue(), (l, r) -> r, Properties::new));
60+
}
61+
4762
@Inject
4863
private List<ProfileActivator> activators = new ArrayList<>();
4964

65+
@Inject
66+
private ModelInterpolator interpolator = new ModelInterpolator() {
67+
68+
@Override
69+
public Model interpolateModel(
70+
Model model, File projectDir, ModelBuildingRequest request, ModelProblemCollector problems) {
71+
return model;
72+
}
73+
};
74+
5075
public DefaultProfileSelector addProfileActivator(ProfileActivator profileActivator) {
5176
if (profileActivator != null) {
5277
activators.add(profileActivator);
5378
}
5479
return this;
5580
}
5681

82+
public void setInterpolator(ModelInterpolator interpolator) {
83+
this.interpolator = interpolator;
84+
}
85+
5786
@Override
5887
public List<Profile> getActiveProfiles(
5988
Collection<Profile> profiles, ProfileActivationContext context, ModelProblemCollector problems) {
@@ -64,9 +93,12 @@ public List<Profile> getActiveProfiles(
6493
List<Profile> activePomProfilesByDefault = new ArrayList<>();
6594
boolean activatedPomProfileNotByDefault = false;
6695

96+
Map<String, Profile> activation = earlyInterpolateProfileActivations(profiles, context);
97+
6798
for (Profile profile : profiles) {
6899
if (!deactivatedIds.contains(profile.getId())) {
69-
if (activatedIds.contains(profile.getId()) || isActive(profile, context, problems)) {
100+
if (activatedIds.contains(profile.getId())
101+
|| isActive(activation.get(profile.getId()), context, problems)) {
70102
activeProfiles.add(profile);
71103

72104
if (Profile.SOURCE_POM.equals(profile.getSource())) {
@@ -89,6 +121,39 @@ public List<Profile> getActiveProfiles(
89121
return activeProfiles;
90122
}
91123

124+
private Map<String, Profile> earlyInterpolateProfileActivations(
125+
Collection<Profile> original, ProfileActivationContext context) {
126+
127+
if (original.stream().map(Profile::getId).distinct().count() < original.size()) {
128+
// invalid profile specification
129+
return Collections.emptyMap();
130+
}
131+
Model model = new Model();
132+
133+
UnaryOperator<Profile> activatableProfile = p -> {
134+
Profile result = new Profile();
135+
result.setId(p.getId());
136+
result.setActivation(p.getActivation());
137+
return result;
138+
};
139+
model.setProfiles(original.stream().map(activatableProfile).collect(Collectors.toList()));
140+
141+
ModelBuildingRequest mbr = new DefaultModelBuildingRequest()
142+
.setActiveProfileIds(context.getActiveProfileIds())
143+
.setInactiveProfileIds(context.getInactiveProfileIds())
144+
.setRawModel(model)
145+
.setSystemProperties(asProperties(context.getSystemProperties()))
146+
.setUserProperties(asProperties(context.getUserProperties()))
147+
.setTwoPhaseBuilding(true)
148+
.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
149+
150+
interpolator
151+
.interpolateModel(model, context.getProjectDirectory(), mbr, problem -> {})
152+
.getProfiles();
153+
154+
return model.getProfiles().stream().collect(Collectors.toMap(Profile::getId, UnaryOperator.identity()));
155+
}
156+
92157
private boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
93158
boolean isActive = false;
94159
for (ProfileActivator activator : activators) {
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.maven.model.profile;
20+
21+
import java.util.Collections;
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.Optional;
25+
26+
import org.apache.maven.model.Activation;
27+
import org.apache.maven.model.ActivationProperty;
28+
import org.apache.maven.model.Model;
29+
import org.apache.maven.model.Profile;
30+
import org.apache.maven.model.interpolation.ModelInterpolator;
31+
import org.apache.maven.model.profile.activation.PropertyProfileActivator;
32+
import org.junit.Before;
33+
import org.junit.Test;
34+
import org.mockito.Mockito;
35+
36+
import static org.junit.Assert.assertEquals;
37+
import static org.junit.Assert.assertSame;
38+
39+
public class DefaultProfileSelectorTest {
40+
private DefaultProfileSelector selector;
41+
private ModelInterpolator interpolator;
42+
43+
@Before
44+
public void setup() {
45+
interpolator = Mockito.mock(ModelInterpolator.class);
46+
47+
selector = new DefaultProfileSelector();
48+
selector.addProfileActivator(new PropertyProfileActivator());
49+
selector.setInterpolator(interpolator);
50+
}
51+
52+
@Test
53+
public void testProfileActivationInterpolation() {
54+
Map<String, String> userProperties = Collections.singletonMap("foo", "bar");
55+
56+
Mockito.when(interpolator.interpolateModel(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))
57+
.thenAnswer(invocation -> {
58+
Model m = invocation.getArgument(0);
59+
60+
m.getProfiles().forEach(p -> {
61+
Optional.ofNullable(p.getActivation())
62+
.map(Activation::getProperty)
63+
.ifPresent(ap -> {
64+
String name = ap.getName();
65+
if (name != null) {
66+
ap.setValue(userProperties.get(name));
67+
}
68+
});
69+
});
70+
return m;
71+
});
72+
73+
ActivationProperty ap = new ActivationProperty();
74+
ap.setName("foo");
75+
76+
Activation act = new Activation();
77+
act.setProperty(ap);
78+
Profile profile = new Profile();
79+
profile.setId("foo");
80+
profile.setActivation(act);
81+
82+
DefaultProfileActivationContext context = new DefaultProfileActivationContext();
83+
context.setUserProperties(userProperties);
84+
85+
List<Profile> activeProfiles = selector.getActiveProfiles(Collections.singleton(profile), context, p -> {});
86+
87+
assertEquals(1, activeProfiles.size());
88+
assertSame(profile, activeProfiles.get(0));
89+
}
90+
}

0 commit comments

Comments
 (0)