diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml index 97347635c981..314f41d31a62 100644 --- a/maven-model-builder/pom.xml +++ b/maven-model-builder/pom.xml @@ -87,6 +87,11 @@ under the License. xmlunit-matchers test + + org.mockito + mockito-core + test + org.powermock powermock-reflect diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java index 2d713b563d77..e05cd5f54d34 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java @@ -22,17 +22,27 @@ import javax.inject.Named; import javax.inject.Singleton; +import java.io.File; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; import org.apache.maven.model.Activation; +import org.apache.maven.model.Model; import org.apache.maven.model.Profile; +import org.apache.maven.model.building.DefaultModelBuildingRequest; +import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelProblem.Severity; import org.apache.maven.model.building.ModelProblem.Version; import org.apache.maven.model.building.ModelProblemCollector; import org.apache.maven.model.building.ModelProblemCollectorRequest; +import org.apache.maven.model.interpolation.ModelInterpolator; import org.apache.maven.model.profile.activation.ProfileActivator; /** @@ -44,9 +54,24 @@ @Singleton public class DefaultProfileSelector implements ProfileSelector { + private static Properties asProperties(Map m) { + return m.entrySet().stream() + .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue(), (l, r) -> r, Properties::new)); + } + @Inject private List activators = new ArrayList<>(); + @Inject + private ModelInterpolator interpolator = new ModelInterpolator() { + + @Override + public Model interpolateModel( + Model model, File projectDir, ModelBuildingRequest request, ModelProblemCollector problems) { + return model; + } + }; + public DefaultProfileSelector addProfileActivator(ProfileActivator profileActivator) { if (profileActivator != null) { activators.add(profileActivator); @@ -54,9 +79,18 @@ public DefaultProfileSelector addProfileActivator(ProfileActivator profileActiva return this; } + public void setInterpolator(ModelInterpolator interpolator) { + this.interpolator = interpolator; + } + @Override public List getActiveProfiles( Collection profiles, ProfileActivationContext context, ModelProblemCollector problems) { + + if (profiles.stream().map(Profile::getId).distinct().count() < profiles.size()) { + // invalid profile specification + return Collections.emptyList(); + } Collection activatedIds = new HashSet<>(context.getActiveProfileIds()); Collection deactivatedIds = new HashSet<>(context.getInactiveProfileIds()); @@ -64,9 +98,12 @@ public List getActiveProfiles( List activePomProfilesByDefault = new ArrayList<>(); boolean activatedPomProfileNotByDefault = false; + Map activation = earlyInterpolateProfileActivations(profiles, context); + for (Profile profile : profiles) { if (!deactivatedIds.contains(profile.getId())) { - if (activatedIds.contains(profile.getId()) || isActive(profile, context, problems)) { + if (activatedIds.contains(profile.getId()) + || isActive(activation.get(profile.getId()), context, problems)) { activeProfiles.add(profile); if (Profile.SOURCE_POM.equals(profile.getSource())) { @@ -89,6 +126,35 @@ public List getActiveProfiles( return activeProfiles; } + private Map earlyInterpolateProfileActivations( + Collection original, ProfileActivationContext context) { + + Model model = new Model(); + + UnaryOperator activatableProfile = p -> { + Profile result = new Profile(); + result.setId(p.getId()); + result.setActivation(p.getActivation()); + return result; + }; + model.setProfiles(original.stream().map(activatableProfile).collect(Collectors.toList())); + + ModelBuildingRequest mbr = new DefaultModelBuildingRequest() + .setActiveProfileIds(context.getActiveProfileIds()) + .setInactiveProfileIds(context.getInactiveProfileIds()) + .setRawModel(model) + .setSystemProperties(asProperties(context.getSystemProperties())) + .setUserProperties(asProperties(context.getUserProperties())) + .setTwoPhaseBuilding(true) + .setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL); + + interpolator + .interpolateModel(model, context.getProjectDirectory(), mbr, problem -> {}) + .getProfiles(); + + return model.getProfiles().stream().collect(Collectors.toMap(Profile::getId, UnaryOperator.identity())); + } + private boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) { boolean isActive = false; for (ProfileActivator activator : activators) { diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/profile/DefaultProfileSelectorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/profile/DefaultProfileSelectorTest.java new file mode 100644 index 000000000000..8f9de0434c33 --- /dev/null +++ b/maven-model-builder/src/test/java/org/apache/maven/model/profile/DefaultProfileSelectorTest.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.model.profile; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apache.maven.model.Activation; +import org.apache.maven.model.ActivationProperty; +import org.apache.maven.model.Model; +import org.apache.maven.model.Profile; +import org.apache.maven.model.interpolation.ModelInterpolator; +import org.apache.maven.model.profile.activation.PropertyProfileActivator; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +public class DefaultProfileSelectorTest { + private DefaultProfileSelector selector; + private ModelInterpolator interpolator; + + @Before + public void setup() { + interpolator = Mockito.mock(ModelInterpolator.class); + + selector = new DefaultProfileSelector(); + selector.addProfileActivator(new PropertyProfileActivator()); + selector.setInterpolator(interpolator); + } + + @Test + public void testProfileActivationInterpolation() { + Map userProperties = Collections.singletonMap("foo", "bar"); + + Mockito.when(interpolator.interpolateModel(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + .thenAnswer(invocation -> { + Model m = invocation.getArgument(0); + + m.getProfiles().forEach(p -> { + Optional.ofNullable(p.getActivation()) + .map(Activation::getProperty) + .ifPresent(ap -> { + String name = ap.getName(); + if (name != null) { + ap.setValue(userProperties.get(name)); + } + }); + }); + return m; + }); + + ActivationProperty ap = new ActivationProperty(); + ap.setName("foo"); + + Activation act = new Activation(); + act.setProperty(ap); + Profile profile = new Profile(); + profile.setId("foo"); + profile.setActivation(act); + + DefaultProfileActivationContext context = new DefaultProfileActivationContext(); + context.setUserProperties(userProperties); + + List activeProfiles = selector.getActiveProfiles(Collections.singleton(profile), context, p -> {}); + + assertEquals(1, activeProfiles.size()); + assertSame(profile, activeProfiles.get(0)); + } +}