Skip to content

Commit

Permalink
[MNG-5235] interpolate available properties during default profile se…
Browse files Browse the repository at this point in the history
…lection
  • Loading branch information
mbenson committed Mar 19, 2024
1 parent a137cc6 commit 4c93af5
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 1 deletion.
5 changes: 5 additions & 0 deletions maven-model-builder/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ under the License.
<artifactId>xmlunit-matchers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-reflect</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -44,29 +54,56 @@
@Singleton
public class DefaultProfileSelector implements ProfileSelector {

private static Properties asProperties(Map<String, String> m) {
return m.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue(), (l, r) -> r, Properties::new));
}

@Inject
private List<ProfileActivator> 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);
}
return this;
}

public void setInterpolator(ModelInterpolator interpolator) {
this.interpolator = interpolator;
}

@Override
public List<Profile> getActiveProfiles(
Collection<Profile> profiles, ProfileActivationContext context, ModelProblemCollector problems) {

if (profiles.stream().map(Profile::getId).distinct().count() < profiles.size()) {
// invalid profile specification
return Collections.emptyList();
}
Collection<String> activatedIds = new HashSet<>(context.getActiveProfileIds());
Collection<String> deactivatedIds = new HashSet<>(context.getInactiveProfileIds());

List<Profile> activeProfiles = new ArrayList<>(profiles.size());
List<Profile> activePomProfilesByDefault = new ArrayList<>();
boolean activatedPomProfileNotByDefault = false;

Map<String, Profile> 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())) {
Expand All @@ -89,6 +126,35 @@ public List<Profile> getActiveProfiles(
return activeProfiles;
}

private Map<String, Profile> earlyInterpolateProfileActivations(
Collection<Profile> original, ProfileActivationContext context) {

Model model = new Model();

UnaryOperator<Profile> 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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String, String> 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<Profile> activeProfiles = selector.getActiveProfiles(Collections.singleton(profile), context, p -> {});

assertEquals(1, activeProfiles.size());
assertSame(profile, activeProfiles.get(0));
}
}

0 comments on commit 4c93af5

Please sign in to comment.