diff --git a/maven-core/src/main/java/org/apache/maven/settings/MavenSettingsBuilder.java b/maven-core/src/main/java/org/apache/maven/settings/MavenSettingsBuilder.java index 896d9b3382..b1d3625a8d 100644 --- a/maven-core/src/main/java/org/apache/maven/settings/MavenSettingsBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/settings/MavenSettingsBuilder.java @@ -30,6 +30,7 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParserException; * @author jdcasey * @author Jason van Zyl */ +@Deprecated public interface MavenSettingsBuilder { String ROLE = MavenSettingsBuilder.class.getName(); diff --git a/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java b/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java new file mode 100644 index 0000000000..f23aacd115 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java @@ -0,0 +1,219 @@ +package org.apache.maven.settings.building; + +/* + * 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. + */ + +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.maven.settings.Settings; +import org.apache.maven.settings.SettingsUtils; +import org.apache.maven.settings.TrackableBase; +import org.apache.maven.settings.io.SettingsParseException; +import org.apache.maven.settings.io.SettingsReader; +import org.apache.maven.settings.io.SettingsWriter; +import org.apache.maven.settings.validation.SettingsValidationResult; +import org.apache.maven.settings.validation.SettingsValidator; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.interpolation.EnvarBasedValueSource; +import org.codehaus.plexus.interpolation.InterpolationException; +import org.codehaus.plexus.interpolation.PropertiesBasedValueSource; +import org.codehaus.plexus.interpolation.RegexBasedInterpolator; + +/** + * Builds the effective settings from a user settings file and/or a global settings file. + * + * @author Benjamin Bentmann + */ +@Component( role = SettingsBuilder.class ) +public class DefaultSettingsBuilder + implements SettingsBuilder +{ + + @Requirement + private SettingsReader settingsReader; + + @Requirement + private SettingsWriter settingsWriter; + + @Requirement + private SettingsValidator settingsValidator; + + public SettingsBuildingResult build( SettingsBuildingRequest request ) + throws SettingsBuildingException + { + List problems = new ArrayList(); + + Settings globalSettings = readSettings( request.getGlobalSettingsFile(), request, problems ); + + Settings userSettings = readSettings( request.getUserSettingsFile(), request, problems ); + + SettingsUtils.merge( userSettings, globalSettings, TrackableBase.GLOBAL_LEVEL ); + + 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 ) + { + File file = new File( localRepository ); + if ( !file.isAbsolute() && file.getPath().startsWith( File.separator ) ) + { + userSettings.setLocalRepository( file.getAbsolutePath() ); + } + } + + if ( hasErrors( problems ) ) + { + throw new SettingsBuildingException( problems ); + } + + return new DefaultSettingsBuildingResult( userSettings, problems ); + } + + private boolean hasErrors( List problems ) + { + if ( problems != null ) + { + for ( SettingsProblem problem : problems ) + { + if ( SettingsProblem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 ) + { + return true; + } + } + } + + return false; + } + + private Settings readSettings( File settingsFile, SettingsBuildingRequest request, List problems ) + { + if ( settingsFile == null || !settingsFile.exists() ) + { + return new Settings(); + } + + Settings settings; + + try + { + boolean strict = true; + + Map options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.valueOf( strict ) ); + + settings = settingsReader.read( settingsFile, options ); + } + catch ( SettingsParseException e ) + { + problems.add( new DefaultSettingsProblem( "Non-parseable settings " + settingsFile, + SettingsProblem.Severity.FATAL, settingsFile.getAbsolutePath(), + e.getLineNumber(), e.getColumnNumber(), e ) ); + return new Settings(); + } + catch ( IOException e ) + { + problems.add( new DefaultSettingsProblem( "Non-readable settings " + settingsFile, + SettingsProblem.Severity.FATAL, settingsFile.getAbsolutePath(), + -1, -1, e ) ); + return new Settings(); + } + + SettingsValidationResult result = settingsValidator.validate( settings ); + + for ( String error : result.getMessages() ) + { + problems.add( new DefaultSettingsProblem( error, SettingsProblem.Severity.ERROR, + settingsFile.getAbsolutePath(), -1, -1, null ) ); + } + + return settings; + } + + private Settings interpolate( Settings settings, SettingsBuildingRequest request, List problems ) + { + List activeProfiles = settings.getActiveProfiles(); + + 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 ); + } + + 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( new DefaultSettingsProblem( "Failed to use environment variables for interpolation: " + + e.getMessage(), SettingsProblem.Severity.WARNING, "", -1, -1, e ) ); + } + + try + { + serializedSettings = interpolator.interpolate( serializedSettings, "settings" ); + } + catch ( InterpolationException e ) + { + problems.add( new DefaultSettingsProblem( "Failed to interpolate settings: " + e.getMessage(), + SettingsProblem.Severity.ERROR, "", -1, -1, e ) ); + + return settings; + } + + Settings result; + try + { + Map options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.FALSE ); + result = settingsReader.read( new StringReader( serializedSettings ), options ); + } + catch ( IOException e ) + { + problems.add( new DefaultSettingsProblem( "Failed to interpolate settings: " + e.getMessage(), + SettingsProblem.Severity.ERROR, "", -1, -1, e ) ); + return settings; + } + + result.setActiveProfiles( activeProfiles ); + + return result; + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingRequest.java b/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingRequest.java new file mode 100644 index 0000000000..92fa6a34bb --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingRequest.java @@ -0,0 +1,116 @@ +package org.apache.maven.settings.building; + +/* + * 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. + */ + +import java.io.File; +import java.util.Properties; + +/** + * Collects settings that control building of effective settings. + * + * @author Benjamin Bentmann + */ +public class DefaultSettingsBuildingRequest + implements SettingsBuildingRequest +{ + + private File globalSettingsFile; + + private File userSettingsFile; + + private Properties systemProperties; + + private Properties userProperties; + + public File getGlobalSettingsFile() + { + return globalSettingsFile; + } + + public DefaultSettingsBuildingRequest setGlobalSettingsFile( File globalSettingsFile ) + { + this.globalSettingsFile = globalSettingsFile; + + return this; + } + + public File getUserSettingsFile() + { + return userSettingsFile; + } + + public DefaultSettingsBuildingRequest setUserSettingsFile( File userSettingsFile ) + { + this.userSettingsFile = userSettingsFile; + + return this; + } + + public Properties getSystemProperties() + { + if ( systemProperties == null ) + { + systemProperties = new Properties(); + } + + return systemProperties; + } + + public DefaultSettingsBuildingRequest setSystemProperties( Properties systemProperties ) + { + if ( systemProperties != null ) + { + this.systemProperties = new Properties(); + this.systemProperties.putAll( systemProperties ); + } + else + { + this.systemProperties = null; + } + + return this; + } + + public Properties getUserProperties() + { + if ( userProperties == null ) + { + userProperties = new Properties(); + } + + return userProperties; + } + + public DefaultSettingsBuildingRequest setUserProperties( Properties userProperties ) + { + if ( userProperties != null ) + { + this.userProperties = new Properties(); + this.userProperties.putAll( userProperties ); + } + else + { + this.userProperties = null; + } + + return this; + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingResult.java b/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingResult.java new file mode 100644 index 0000000000..e04fe025e2 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingResult.java @@ -0,0 +1,55 @@ +package org.apache.maven.settings.building; + +/* + * 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. + */ + +import java.util.List; + +import org.apache.maven.settings.Settings; + +/** + * Collects the output of the settings builder. + * + * @author Benjamin Bentmann + */ +class DefaultSettingsBuildingResult + implements SettingsBuildingResult +{ + + private Settings effectiveSettings; + + private List problems; + + public DefaultSettingsBuildingResult( Settings effectiveSettings, List problems ) + { + this.effectiveSettings = effectiveSettings; + this.problems = problems; + } + + public Settings getEffectiveSettings() + { + return effectiveSettings; + } + + public List getProblems() + { + return problems; + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblem.java b/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblem.java new file mode 100644 index 0000000000..0f54f9098e --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblem.java @@ -0,0 +1,158 @@ +package org.apache.maven.settings.building; + +/* + * 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. + */ + +/** + * Describes a problem that was encountered during settings building. A problem can either be an exception that was + * thrown or a simple string message. In addition, a problem carries a hint about its source, e.g. the settings file + * that exhibits the problem. + * + * @author Benjamin Bentmann + */ +class DefaultSettingsProblem + implements SettingsProblem +{ + + private final String source; + + private final int lineNumber; + + private final int columnNumber; + + private final String message; + + private final Exception exception; + + private final Severity severity; + + /** + * Creates a new problem with the specified message and exception. + * + * @param message The message describing the problem, may be {@code null}. + * @param severity The severity level of the problem, may be {@code null} to default to {@link Severity#ERROR}. + * @param source A hint about the source of the problem like a file path, may be {@code null}. + * @param lineNumber The one-based index of the line containing the problem or {@code -1} if unknown. + * @param columnNumber The one-based index of the column containing the problem or {@code -1} if unknown. + * @param exception The exception that caused this problem, may be {@code null}. + */ + public DefaultSettingsProblem( String message, Severity severity, String source, int lineNumber, int columnNumber, + Exception exception ) + { + this.message = message; + this.severity = ( severity != null ) ? severity : Severity.ERROR; + this.source = ( source != null ) ? source : ""; + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + this.exception = exception; + } + + public String getSource() + { + return source; + } + + public int getLineNumber() + { + return lineNumber; + } + + public int getColumnNumber() + { + return columnNumber; + } + + public String getLocation() + { + StringBuilder buffer = new StringBuilder( 256 ); + + if ( getSource().length() > 0 ) + { + if ( buffer.length() > 0 ) + { + buffer.append( ", " ); + } + buffer.append( getSource() ); + } + + if ( getLineNumber() > 0 ) + { + if ( buffer.length() > 0 ) + { + buffer.append( ", " ); + } + buffer.append( "line " ).append( getLineNumber() ); + } + + if ( getColumnNumber() > 0 ) + { + if ( buffer.length() > 0 ) + { + buffer.append( ", " ); + } + buffer.append( "column " ).append( getColumnNumber() ); + } + + return buffer.toString(); + } + + public Exception getException() + { + return exception; + } + + public String getMessage() + { + String msg; + + if ( message != null && message.length() > 0 ) + { + msg = message; + } + else + { + msg = exception.getMessage(); + + if ( msg == null ) + { + msg = ""; + } + } + + return msg; + } + + public Severity getSeverity() + { + return severity; + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder( 128 ); + + buffer.append( "[" ).append( getSeverity() ).append( "] " ); + buffer.append( getMessage() ); + buffer.append( " @ " ).append( getLocation() ); + + return buffer.toString(); + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuilder.java b/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuilder.java new file mode 100644 index 0000000000..ed9c986a4d --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuilder.java @@ -0,0 +1,40 @@ +package org.apache.maven.settings.building; + +/* + * 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. + */ + +/** + * Builds the effective settings from a user settings file and/or a global settings file. + * + * @author Benjamin Bentmann + */ +public interface SettingsBuilder +{ + + /** + * Builds the effective settings of the specified settings files. + * + * @param request The settings building request that holds the parameters, must not be {@code null}. + * @return The result of the settings building, never {@code null}. + * @throws SettingsBuildingException If the effective settings could not be built. + */ + SettingsBuildingResult build( SettingsBuildingRequest request ) + throws SettingsBuildingException; + +} diff --git a/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuildingException.java b/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuildingException.java new file mode 100644 index 0000000000..73b602ef5e --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuildingException.java @@ -0,0 +1,91 @@ +package org.apache.maven.settings.building; + +/* + * 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. + */ + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +/** + * Signals one ore more errors during settings building. The settings builder tries to collect as many problems as + * possible before eventually failing to provide callers with rich error information. Use {@link #getProblems()} to + * query the details of the failure. + * + * @author Benjamin Bentmann + */ +public class SettingsBuildingException + extends Exception +{ + + private final List problems; + + /** + * Creates a new exception with the specified problems. + * + * @param modelId The identifier of the model that could not be built, may be {@code null}. + * @param problems The problems that causes this exception, may be {@code null}. + */ + public SettingsBuildingException( List problems ) + { + super( toMessage( problems ) ); + + this.problems = new ArrayList(); + if ( problems != null ) + { + this.problems.addAll( problems ); + } + } + + /** + * Gets the problems that caused this exception. + * + * @return The problems that caused this exception, never {@code null}. + */ + public List getProblems() + { + return problems; + } + + private static String toMessage( List problems ) + { + StringWriter buffer = new StringWriter( 1024 ); + + PrintWriter writer = new PrintWriter( buffer ); + + writer.print( problems.size() ); + writer.print( ( problems.size() == 1 ) ? " problem was " : " problems were " ); + writer.print( "encountered while building the effective settings" ); + writer.println(); + + for ( SettingsProblem problem : problems ) + { + writer.print( "[" ); + writer.print( problem.getSeverity() ); + writer.print( "] " ); + writer.print( problem.getMessage() ); + writer.print( " @ " ); + writer.println( problem.getLocation() ); + } + + return buffer.toString(); + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuildingRequest.java b/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuildingRequest.java new file mode 100644 index 0000000000..14c5bb191c --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuildingRequest.java @@ -0,0 +1,99 @@ +package org.apache.maven.settings.building; + +/* + * 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. + */ + +import java.io.File; +import java.util.Properties; + +/** + * Collects settings that control the building of effective settings. + * + * @author Benjamin Bentmann + */ +public interface SettingsBuildingRequest +{ + + /** + * Gets the global settings file. + * + * @return The global settings file or {@code null} if none. + */ + File getGlobalSettingsFile(); + + /** + * Sets the global settings file. A non-existent settings file is equivalent to empty settings. If both a user + * settings file and a global settings file are given, the user settings take precedence. + * + * @param globalSettingsFile The global settings file, may be {@code null} to disable global settings. + * @return This request, never {@code null}. + */ + SettingsBuildingRequest setGlobalSettingsFile( File globalSettingsFile ); + + /** + * Gets the user settings file. + * + * @return The user settings file or {@code null} if none. + */ + File getUserSettingsFile(); + + /** + * Sets the user settings file. A non-existent settings file is equivalent to empty settings. If both a user + * settings file and a global settings file are given, the user settings take precedence. + * + * @param userSettingsFile The user settings file, may be {@code null} to disable user settings. + * @return This request, never {@code null}. + */ + SettingsBuildingRequest setUserSettingsFile( File userSettingsFile ); + + /** + * Gets the system properties to use for interpolation. The system properties are collected from the runtime + * environment like {@link System#getProperties()} and environment variables. + * + * @return The system properties, never {@code null}. + */ + Properties getSystemProperties(); + + /** + * Sets the system properties to use for interpolation. The system properties are collected from the runtime + * environment like {@link System#getProperties()} and environment variables. + * + * @param systemProperties The system properties, may be {@code null}. + * @return This request, never {@code null}. + */ + SettingsBuildingRequest setSystemProperties( Properties systemProperties ); + + /** + * Gets the user properties to use for interpolation. The user properties have been configured directly by the user + * on his discretion, e.g. via the {@code -Dkey=value} parameter on the command line. + * + * @return The user properties, never {@code null}. + */ + Properties getUserProperties(); + + /** + * Sets the user properties to use for interpolation. The user properties have been configured directly by the user + * on his discretion, e.g. via the {@code -Dkey=value} parameter on the command line. + * + * @param userProperties The user properties, may be {@code null}. + * @return This request, never {@code null}. + */ + SettingsBuildingRequest setUserProperties( Properties userProperties ); + +} diff --git a/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuildingResult.java b/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuildingResult.java new file mode 100644 index 0000000000..1873f77a40 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/settings/building/SettingsBuildingResult.java @@ -0,0 +1,50 @@ +package org.apache.maven.settings.building; + +/* + * 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. + */ + +import java.util.List; + +import org.apache.maven.settings.Settings; + +/** + * Collects the output of the settings builder. + * + * @author Benjamin Bentmann + */ +public interface SettingsBuildingResult +{ + + /** + * Gets the assembled settings. + * + * @return The assembled settings, never {@code null}. + */ + Settings getEffectiveSettings(); + + /** + * Gets the problems that were encountered during the settings building. Note that only problems of severity + * {@link SettingsProblem.Severity#WARNING} and below are reported here. Problems with a higher severity level cause + * the settings builder to fail with a {@link SettingsBuildingException}. + * + * @return The problems that were encountered during the model building, can be empty but never {@code null}. + */ + List getProblems(); + +} diff --git a/maven-core/src/main/java/org/apache/maven/settings/building/SettingsProblem.java b/maven-core/src/main/java/org/apache/maven/settings/building/SettingsProblem.java new file mode 100644 index 0000000000..0b399ed05a --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/settings/building/SettingsProblem.java @@ -0,0 +1,100 @@ +package org.apache.maven.settings.building; + +/* + * 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. + */ + +/** + * Describes a problem that was encountered during settings building. A problem can either be an exception that was + * thrown or a simple string message. In addition, a problem carries a hint about its source, e.g. the settings file + * that exhibits the problem. + * + * @author Benjamin Bentmann + */ +public interface SettingsProblem +{ + + /** + * The different severity levels for a problem, in decreasing order. + */ + enum Severity + { + + FATAL, // + ERROR, // + WARNING; // + + } + + /** + * Gets the hint about the source of the problem. While the syntax of this hint is unspecified and depends on the + * creator of the problem, the general expectation is that the hint provides sufficient information to the user to + * track the problem back to its origin. A concrete example for such a source hint can be the file path or URL from + * which the settings were read. + * + * @return The hint about the source of the problem or an empty string if unknown, never {@code null}. + */ + String getSource(); + + /** + * Gets the one-based index of the line containing the problem. The line number should refer to some text file that + * is given by {@link #getSource()}. + * + * @return The one-based index of the line containing the problem or a non-positive value if unknown. + */ + int getLineNumber(); + + /** + * Gets the one-based index of the column containing the problem. The column number should refer to some text file + * that is given by {@link #getSource()}. + * + * @return The one-based index of the column containing the problem or non-positive value if unknown. + */ + int getColumnNumber(); + + /** + * Gets the location of the problem. The location is a user-friendly combination of the values from + * {@link #getSource()}, {@link #getLineNumber()} and {@link #getColumnNumber()}. The exact syntax of the returned + * value is undefined. + * + * @return The location of the problem, never {@code null}. + */ + String getLocation(); + + /** + * Gets the exception that caused this problem (if any). + * + * @return The exception that caused this problem or {@code null} if not applicable. + */ + Exception getException(); + + /** + * Gets the message that describes this problem. + * + * @return The message describing this problem, never {@code null}. + */ + String getMessage(); + + /** + * Gets the severity level of this problem. + * + * @return The severity level of this problem, never {@code null}. + */ + Severity getSeverity(); + +} diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java index 3349cb7192..58a27c1baa 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java @@ -39,8 +39,13 @@ import org.apache.maven.execution.MavenExecutionRequestPopulator; import org.apache.maven.execution.MavenExecutionResult; import org.apache.maven.model.locator.ModelLocator; import org.apache.maven.repository.ArtifactTransferListener; -import org.apache.maven.settings.MavenSettingsBuilder; import org.apache.maven.settings.Settings; +import org.apache.maven.settings.building.DefaultSettingsBuildingRequest; +import org.apache.maven.settings.building.SettingsBuilder; +import org.apache.maven.settings.building.SettingsBuildingException; +import org.apache.maven.settings.building.SettingsBuildingRequest; +import org.apache.maven.settings.building.SettingsBuildingResult; +import org.apache.maven.settings.building.SettingsProblem; import org.apache.maven.settings.io.xpp3.SettingsXpp3Reader; import org.codehaus.plexus.ContainerConfiguration; import org.codehaus.plexus.DefaultContainerConfiguration; @@ -249,11 +254,32 @@ public class MavenCli try { - MavenSettingsBuilder settingsBuilder = container.lookup( MavenSettingsBuilder.class ); + SettingsBuildingRequest settingsRequest = new DefaultSettingsBuildingRequest(); + settingsRequest.setGlobalSettingsFile( configuration.getGlobalSettingsFile() ); + settingsRequest.setUserSettingsFile( configuration.getUserSettingsFile() ); + settingsRequest.setSystemProperties( request.getSystemProperties() ); + settingsRequest.setUserProperties( request.getUserProperties() ); + + SettingsBuilder settingsBuilder = container.lookup( SettingsBuilder.class ); try { - settings = settingsBuilder.buildSettings( request ); + SettingsBuildingResult settingsResult = settingsBuilder.build( settingsRequest ); + + settings = settingsResult.getEffectiveSettings(); + + if ( !settingsResult.getProblems().isEmpty() && logger.isWarnEnabled() ) + { + logger.warn( "" ); + logger.warn( "Some problems were encountered while building the effective settings" ); + + for ( SettingsProblem problem : settingsResult.getProblems() ) + { + logger.warn( problem.getMessage() + " @ " + problem.getLocation() ); + } + + logger.warn( "" ); + } } finally { @@ -273,18 +299,12 @@ public class MavenCli return 1; } - catch ( IOException e ) + catch ( SettingsBuildingException e ) { CLIReportingUtils.showError( logger, "Failed to read settings: ", e, showErrors ); return 1; } - catch ( XmlPullParserException e ) - { - CLIReportingUtils.showError( logger, "Failed to parse settings: ", e, showErrors ); - - return 1; - } try { diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java index 67447ae63c..b0b99f1892 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java @@ -316,7 +316,7 @@ public class DefaultModelBuilder } catch ( IOException e ) { - problems.addFatalError( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage(), -1, -1, e ); + problems.addFatalError( "Non-readable POM " + modelSource.getLocation() + ": " + e.getMessage(), -1, -1, e ); throw new ModelBuildingException( problems.getRootModelId(), problems.getProblems() ); }