diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java index 3addf78ea56a..95d411604779 100644 --- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java +++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java @@ -24,8 +24,9 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.StringReader; -import java.io.StringWriter; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; import java.util.Map; @@ -44,6 +45,7 @@ import org.codehaus.plexus.interpolation.InterpolationPostProcessor; import org.codehaus.plexus.interpolation.PropertiesBasedValueSource; import org.codehaus.plexus.interpolation.RegexBasedInterpolator; +import org.codehaus.plexus.util.IOUtil; /** * Builds the effective settings from a user settings file and/or a global settings file. @@ -53,6 +55,7 @@ @Named @Singleton public class DefaultSettingsBuilder implements SettingsBuilder { + private static final String MAVEN_SETTINGS_STRICT = "maven.settings.strictParsing"; private SettingsReader settingsReader; @@ -89,22 +92,35 @@ public DefaultSettingsBuilder setSettingsValidator(SettingsValidator settingsVal public SettingsBuildingResult build(SettingsBuildingRequest request) throws SettingsBuildingException { DefaultSettingsProblemCollector problems = new DefaultSettingsProblemCollector(null); + boolean strict = Boolean.parseBoolean(request.getUserProperties() + .getProperty( + MAVEN_SETTINGS_STRICT, + request.getSystemProperties().getProperty(MAVEN_SETTINGS_STRICT, Boolean.FALSE.toString()))); + Source globalSettingsSource = getSettingsSource(request.getGlobalSettingsFile(), request.getGlobalSettingsSource()); - Settings globalSettings = readSettings(globalSettingsSource, request, problems); + Settings globalSettings = readSettingsFromString( + globalSettingsSource, + interpolateFromSourceToString(globalSettingsSource, request, problems), + request, + problems, + strict); Source userSettingsSource = getSettingsSource(request.getUserSettingsFile(), request.getUserSettingsSource()); - Settings userSettings = readSettings(userSettingsSource, request, problems); + Settings userSettings = readSettingsFromString( + userSettingsSource, + interpolateFromSourceToString(userSettingsSource, request, problems), + request, + problems, + strict); settingsMerger.merge(userSettings, globalSettings, TrackableBase.GLOBAL_LEVEL); problems.setSource(""); - userSettings = interpolate(userSettings, request, problems); - // for the special case of a drive-relative Windows path, make sure it's absolute to save plugins from trouble String localRepository = userSettings.getLocalRepository(); - if (localRepository != null && localRepository.length() > 0) { + if (localRepository != null && !localRepository.isEmpty()) { File file = new File(localRepository); if (!file.isAbsolute() && file.getPath().startsWith(File.separator)) { userSettings.setLocalRepository(file.getAbsolutePath()); @@ -139,8 +155,12 @@ private Source getSettingsSource(File settingsFile, Source settingsSource) { return null; } - private Settings readSettings( - Source settingsSource, SettingsBuildingRequest request, DefaultSettingsProblemCollector problems) { + private Settings readSettingsFromString( + Source settingsSource, + String settingsString, + SettingsBuildingRequest request, + DefaultSettingsProblemCollector problems, + boolean strict) { if (settingsSource == null) { return new Settings(); } @@ -153,14 +173,22 @@ private Settings readSettings( Map options = Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.TRUE); try { - settings = settingsReader.read(settingsSource.getInputStream(), options); + settings = settingsReader.read(new StringReader(settingsString), options); } catch (SettingsParseException e) { - options = Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.FALSE); - - settings = settingsReader.read(settingsSource.getInputStream(), options); - - problems.add( - SettingsProblem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e); + if (strict) { + problems.add( + SettingsProblem.Severity.FATAL, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e); + return new Settings(); + } else { + options = Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.FALSE); + settings = settingsReader.read(new StringReader(settingsString), options); + problems.add( + SettingsProblem.Severity.WARNING, + e.getMessage(), + e.getLineNumber(), + e.getColumnNumber(), + e); + } } } catch (SettingsParseException e) { problems.add( @@ -185,69 +213,60 @@ private Settings readSettings( return settings; } - private Settings interpolate( - Settings settings, SettingsBuildingRequest request, SettingsProblemCollector problems) { - StringWriter writer = new StringWriter(1024 * 4); - - try { - settingsWriter.write(writer, null, settings); - } catch (IOException e) { - throw new IllegalStateException("Failed to serialize settings to memory", e); + private String interpolateFromSourceToString( + Source settingsSource, SettingsBuildingRequest request, SettingsProblemCollector problems) { + String serializedSettings = null; + if (settingsSource == null) { + return ""; } - - String serializedSettings = writer.toString(); - - RegexBasedInterpolator interpolator = new RegexBasedInterpolator(); - - interpolator.addValueSource(new PropertiesBasedValueSource(request.getUserProperties())); - - interpolator.addValueSource(new PropertiesBasedValueSource(request.getSystemProperties())); - try { - interpolator.addValueSource(new EnvarBasedValueSource()); - } catch (IOException e) { - problems.add( - SettingsProblem.Severity.WARNING, - "Failed to use environment variables for interpolation: " + e.getMessage(), - -1, - -1, - e); - } + try (InputStream inputStream = settingsSource.getInputStream()) { + serializedSettings = IOUtil.toString(inputStream, StandardCharsets.UTF_8.name()); + } + RegexBasedInterpolator interpolator = new RegexBasedInterpolator(); + interpolator.addValueSource(new PropertiesBasedValueSource(request.getUserProperties())); + interpolator.addValueSource(new PropertiesBasedValueSource(request.getSystemProperties())); - interpolator.addPostProcessor(new InterpolationPostProcessor() { - @Override - public Object execute(String expression, Object value) { - if (value != null) { - // we're going to parse this back in as XML so we need to escape XML markup - value = value.toString() - .replace("&", "&") - .replace("<", "<") - .replace(">", ">"); - return value; - } - return null; + try { + interpolator.addValueSource(new EnvarBasedValueSource()); + } catch (IOException e) { + problems.add( + SettingsProblem.Severity.WARNING, + "Failed to use environment variables for interpolation: " + e.getMessage(), + -1, + -1, + e); } - }); - try { - serializedSettings = interpolator.interpolate(serializedSettings, "settings"); - } catch (InterpolationException e) { - problems.add( - SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1, e); + interpolator.addPostProcessor(new InterpolationPostProcessor() { + @Override + public Object execute(String expression, Object value) { + if (value != null) { + // we're going to parse this back in as XML so we need to escape XML markup + value = value.toString() + .replace("&", "&") + .replace("<", "<") + .replace(">", ">"); + return value; + } + return null; + } + }); - return settings; - } + try { + serializedSettings = interpolator.interpolate(serializedSettings, "settings"); + } catch (InterpolationException e) { + problems.add( + SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1, e); - Settings result; - try { - Map options = Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.FALSE); - result = settingsReader.read(new StringReader(serializedSettings), options); + return serializedSettings; + } + + return serializedSettings; } catch (IOException e) { problems.add( SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1, e); - return settings; + return serializedSettings; } - - return result; } } diff --git a/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java b/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java index 7aadfcb070ac..2c51001228b5 100644 --- a/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java +++ b/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java @@ -19,10 +19,13 @@ package org.apache.maven.settings.building; import java.io.File; +import java.util.Properties; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * @author Benjamin Bentmann @@ -46,4 +49,63 @@ public void testCompleteWiring() throws Exception { assertNotNull(result); assertNotNull(result.getEffectiveSettings()); } + + @Test + public void testNonStringInterpolationHappyPath() throws Exception { + SettingsBuilder builder = new DefaultSettingsBuilderFactory().newInstance(); + assertNotNull(builder); + + boolean testActive = true; + int testPort = 2026; + Properties userProperties = new Properties(); + userProperties.setProperty("test.active", Boolean.toString(testActive)); + userProperties.setProperty("test.port", Integer.toString(testPort)); + userProperties.setProperty("maven.settings.strictParsing", Boolean.TRUE.toString()); + + DefaultSettingsBuildingRequest request = new DefaultSettingsBuildingRequest(); + request.setUserProperties(userProperties); + request.setSystemProperties(System.getProperties()); + request.setUserSettingsFile(getSettings("proxy")); + + SettingsBuildingResult result = builder.build(request); + assertNotNull(result); + assertNotNull(result.getEffectiveSettings()); + assertEquals( + testActive, result.getEffectiveSettings().getProxies().get(0).isActive()); + assertEquals(testPort, result.getEffectiveSettings().getProxies().get(0).getPort()); + } + + @Test + public void testNonStringInterpolationNonHappyPath() { + SettingsBuilder builder = new DefaultSettingsBuilderFactory().newInstance(); + assertNotNull(builder); + + Properties userProperties = new Properties(); + userProperties.setProperty("test.active", "yes"); + userProperties.setProperty("test.port", "foo"); + userProperties.setProperty("maven.settings.strictParsing", Boolean.TRUE.toString()); + + DefaultSettingsBuildingRequest request = new DefaultSettingsBuildingRequest(); + request.setUserProperties(userProperties); + request.setSystemProperties(System.getProperties()); + request.setUserSettingsFile(getSettings("proxy")); + + assertThrows(SettingsBuildingException.class, () -> builder.build(request)); + } + + @Test + public void testNonStringInterpolationMissingProperties() { + SettingsBuilder builder = new DefaultSettingsBuilderFactory().newInstance(); + assertNotNull(builder); + + Properties userProperties = new Properties(); + userProperties.setProperty("maven.settings.strictParsing", Boolean.TRUE.toString()); + + DefaultSettingsBuildingRequest request = new DefaultSettingsBuildingRequest(); + request.setUserProperties(userProperties); + request.setSystemProperties(System.getProperties()); + request.setUserSettingsFile(getSettings("proxy")); + + assertThrows(SettingsBuildingException.class, () -> builder.build(request)); + } } diff --git a/maven-settings-builder/src/test/resources/settings/factory/proxy.xml b/maven-settings-builder/src/test/resources/settings/factory/proxy.xml new file mode 100644 index 000000000000..0503cb567786 --- /dev/null +++ b/maven-settings-builder/src/test/resources/settings/factory/proxy.xml @@ -0,0 +1,32 @@ + + + + + + ${user.home}/.m2/repository + + + test + ${test.active} + somehost.org + ${test.port} + + +