From ceae922653e7bf4bd1013e01d0f8deae7443744c Mon Sep 17 00:00:00 2001 From: Robert Scholte Date: Thu, 25 Dec 2014 14:55:02 +0100 Subject: [PATCH] [MNG-3891] Modify maven-toolchain to look in ${maven.home}/conf/toolchains.xml and in ${user.home}/.m2/toolchains.xml Also added new cmdline option: -gt / --global-toolchains --- .../org/apache/maven/building/FileSource.java | 2 +- .../DefaultMavenExecutionRequest.java | 16 +++ .../execution/MavenExecutionRequest.java | 16 +++ .../DefaultToolchainManagerPrivate.java | 34 ++++- .../toolchain/DefaultToolchainsBuilder.java | 3 + .../building/DefaultToolchainsBuilder.java | 136 ++++++++++++++++++ .../DefaultToolchainsBuildingRequest.java | 63 ++++++++ .../DefaultToolchainsBuildingResult.java | 59 ++++++++ .../toolchain/building/ToolchainsBuilder.java | 41 ++++++ .../building/ToolchainsBuildingException.java | 88 ++++++++++++ .../building/ToolchainsBuildingRequest.java | 64 +++++++++ .../building/ToolchainsBuildingResult.java | 50 +++++++ .../building/io/DefaultToolchainsReader.java | 115 +++++++++++++++ .../building/io/ToolchainsParseException.java | 94 ++++++++++++ .../building/io/ToolchainsReader.java | 83 +++++++++++ .../java/org/apache/maven/cli/CLIManager.java | 3 + .../java/org/apache/maven/cli/MavenCli.java | 66 ++++++++- 17 files changed, 925 insertions(+), 8 deletions(-) create mode 100644 maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java create mode 100644 maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java create mode 100644 maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java create mode 100644 maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java create mode 100644 maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java create mode 100644 maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java create mode 100644 maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java create mode 100644 maven-core/src/main/java/org/apache/maven/toolchain/building/io/DefaultToolchainsReader.java create mode 100644 maven-core/src/main/java/org/apache/maven/toolchain/building/io/ToolchainsParseException.java create mode 100644 maven-core/src/main/java/org/apache/maven/toolchain/building/io/ToolchainsReader.java diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/FileSource.java b/maven-builder-support/src/main/java/org/apache/maven/building/FileSource.java index b201ee6856..1a6fc2f415 100644 --- a/maven-builder-support/src/main/java/org/apache/maven/building/FileSource.java +++ b/maven-builder-support/src/main/java/org/apache/maven/building/FileSource.java @@ -43,7 +43,7 @@ public class FileSource { if ( file == null ) { - throw new IllegalArgumentException( "no POM file specified" ); + throw new IllegalArgumentException( "no file specified" ); } this.file = file.getAbsoluteFile(); } diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java index df91f828a4..933e1687af 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java +++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java @@ -84,6 +84,8 @@ public class DefaultMavenExecutionRequest private File userToolchainsFile; + private File globalToolchainsFile; + // ---------------------------------------------------------------------------- // Request // ---------------------------------------------------------------------------- @@ -169,6 +171,7 @@ public class DefaultMavenExecutionRequest copy.setUserSettingsFile( original.getUserSettingsFile() ); copy.setGlobalSettingsFile( original.getGlobalSettingsFile() ); copy.setUserToolchainsFile( original.getUserToolchainsFile() ); + copy.setGlobalToolchainsFile( original.getGlobalToolchainsFile() ); copy.setBaseDirectory( ( original.getBaseDirectory() != null ) ? new File( original.getBaseDirectory() ) : null ); copy.setGoals( original.getGoals() ); copy.setRecursive( original.isRecursive() ); @@ -931,6 +934,19 @@ public class DefaultMavenExecutionRequest return this; } + + @Override + public File getGlobalToolchainsFile() + { + return globalToolchainsFile; + } + + @Override + public MavenExecutionRequest setGlobalToolchainsFile( File globalToolchainsFile ) + { + this.globalToolchainsFile = globalToolchainsFile; + return this; + } public MavenExecutionRequest addRemoteRepository( ArtifactRepository repository ) { diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java index 3c99d31083..7daac890b2 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java +++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java @@ -348,6 +348,22 @@ public interface MavenExecutionRequest MavenExecutionRequest setUserToolchainsFile( File userToolchainsFile ); + /** + * + * + * @return the global toolchains file + * @since 3.2.6 + */ + File getGlobalToolchainsFile(); + + /** + * + * @param globalToolchainsFile the global toolchains file + * @return this request + * @since 3.2.6 + */ + MavenExecutionRequest setGlobalToolchainsFile( File globalToolchainsFile ); + ExecutionListener getExecutionListener(); MavenExecutionRequest setExecutionListener( ExecutionListener executionListener ); diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivate.java b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivate.java index 1668a8012b..923db002fe 100644 --- a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivate.java +++ b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivate.java @@ -19,11 +19,16 @@ package org.apache.maven.toolchain; * under the License. */ +import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.apache.maven.building.FileSource; import org.apache.maven.execution.MavenSession; +import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest; +import org.apache.maven.toolchain.building.ToolchainsBuildingException; +import org.apache.maven.toolchain.building.ToolchainsBuildingResult; import org.apache.maven.toolchain.model.PersistedToolchains; import org.apache.maven.toolchain.model.ToolchainModel; import org.codehaus.plexus.component.annotations.Component; @@ -31,6 +36,7 @@ import org.codehaus.plexus.component.annotations.Requirement; /** * @author mkleint + * @author Robert Scholte */ @Component( role = ToolchainManagerPrivate.class ) public class DefaultToolchainManagerPrivate @@ -39,12 +45,36 @@ public class DefaultToolchainManagerPrivate { @Requirement - private ToolchainsBuilder toolchainsBuilder; + private org.apache.maven.toolchain.building.ToolchainsBuilder toolchainsBuilder; public ToolchainPrivate[] getToolchainsForType( String type, MavenSession context ) throws MisconfiguredToolchainException { - PersistedToolchains pers = toolchainsBuilder.build( context.getRequest().getUserToolchainsFile() ); + DefaultToolchainsBuildingRequest buildRequest = new DefaultToolchainsBuildingRequest(); + + File globalToolchainsFile = context.getRequest().getGlobalToolchainsFile(); + if ( globalToolchainsFile != null && globalToolchainsFile.isFile() ) + { + buildRequest.setGlobalToolchainsSource( new FileSource( globalToolchainsFile ) ); + } + + File userToolchainsFile = context.getRequest().getUserToolchainsFile(); + if ( userToolchainsFile != null && userToolchainsFile.isFile() ) + { + buildRequest.setUserToolchainsSource( new FileSource( userToolchainsFile ) ); + } + + ToolchainsBuildingResult buildResult; + try + { + buildResult = toolchainsBuilder.build( buildRequest ); + } + catch ( ToolchainsBuildingException e ) + { + throw new MisconfiguredToolchainException( e.getMessage(), e ); + } + + PersistedToolchains pers = buildResult.getEffectiveToolchains(); List toRet = new ArrayList(); diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainsBuilder.java b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainsBuilder.java index 4e6e24a182..5bd3e82a6a 100644 --- a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainsBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainsBuilder.java @@ -32,7 +32,10 @@ import org.codehaus.plexus.util.ReaderFactory; /** * @author Benjamin Bentmann + * + * @deprecated instead use {@link org.apache.maven.toolchain.building.DefaultToolchainsBuilder} */ +@Deprecated @Component( role = ToolchainsBuilder.class, hint = "default" ) public class DefaultToolchainsBuilder implements ToolchainsBuilder diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java b/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java new file mode 100644 index 0000000000..ad3363c1cd --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java @@ -0,0 +1,136 @@ +package org.apache.maven.toolchain.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.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.apache.maven.building.Problem; +import org.apache.maven.building.ProblemCollector; +import org.apache.maven.building.ProblemCollectorFactory; +import org.apache.maven.building.Source; +import org.apache.maven.toolchain.building.io.ToolchainsParseException; +import org.apache.maven.toolchain.building.io.ToolchainsReader; +import org.apache.maven.toolchain.merge.MavenToolchainMerger; +import org.apache.maven.toolchain.model.PersistedToolchains; +import org.apache.maven.toolchain.model.TrackableBase; + +/** + * + * @author Robert Scholte + * @since 3.2.6 + */ +@Named +public class DefaultToolchainsBuilder + implements ToolchainsBuilder +{ + private MavenToolchainMerger toolchainsMerger = new MavenToolchainMerger(); + + @Inject + private ToolchainsReader toolchainsReader; + + @Override + public ToolchainsBuildingResult build( ToolchainsBuildingRequest request ) + throws ToolchainsBuildingException + { + ProblemCollector problems = ProblemCollectorFactory.newInstance( null ); + + PersistedToolchains globalToolchains = readToolchains( request.getGlobalToolchainsSource() , request, problems ); + + PersistedToolchains userToolchains = readToolchains( request.getUserToolchainsSource(), request, problems ); + + toolchainsMerger.merge( userToolchains, globalToolchains, TrackableBase.GLOBAL_LEVEL ); + + problems.setSource( "" ); + + if ( hasErrors( problems.getProblems() ) ) + { + throw new ToolchainsBuildingException( problems.getProblems() ); + } + + + return new DefaultToolchainsBuildingResult( userToolchains, problems.getProblems() ); + } + + private PersistedToolchains readToolchains( Source toolchainsSource, ToolchainsBuildingRequest request, + ProblemCollector problems ) + { + if ( toolchainsSource == null ) + { + return new PersistedToolchains(); + } + + PersistedToolchains toolchains; + + try + { + Map options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.TRUE ); + + try + { + toolchains = toolchainsReader.read( toolchainsSource.getInputStream(), options ); + } + catch ( ToolchainsParseException e ) + { + options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.FALSE ); + + toolchains = toolchainsReader.read( toolchainsSource.getInputStream(), options ); + + problems.add( Problem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), + e ); + } + } + catch ( ToolchainsParseException e ) + { + problems.add( Problem.Severity.FATAL, "Non-parseable toolchains " + toolchainsSource.getLocation() + + ": " + e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e ); + return new PersistedToolchains(); + } + catch ( IOException e ) + { + problems.add( Problem.Severity.FATAL, "Non-readable toolchains " + toolchainsSource.getLocation() + + ": " + e.getMessage(), -1, -1, e ); + return new PersistedToolchains(); + } + + return toolchains; + } + + private boolean hasErrors( List problems ) + { + if ( problems != null ) + { + for ( Problem problem : problems ) + { + if ( Problem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 ) + { + return true; + } + } + } + + return false; + } +} diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java b/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java new file mode 100644 index 0000000000..7773bb3038 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java @@ -0,0 +1,63 @@ +package org.apache.maven.toolchain.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 org.apache.maven.building.Source; + +/** + * Collects toolchains that control building of effective toolchains. + * + * @author Robert Scholte + * @since 3.2.6 + */ +public class DefaultToolchainsBuildingRequest + implements ToolchainsBuildingRequest +{ + private Source globalToolchainsSource; + + private Source userToolchainsSource; + + @Override + public Source getGlobalToolchainsSource() + { + return globalToolchainsSource; + } + + @Override + public ToolchainsBuildingRequest setGlobalToolchainsSource( Source globalToolchainsSource ) + { + this.globalToolchainsSource = globalToolchainsSource; + return this; + } + + @Override + public Source getUserToolchainsSource() + { + return userToolchainsSource; + } + + @Override + public ToolchainsBuildingRequest setUserToolchainsSource( Source userToolchainsSource ) + { + this.userToolchainsSource = userToolchainsSource; + return this; + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java b/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java new file mode 100644 index 0000000000..b50473fdd7 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java @@ -0,0 +1,59 @@ +package org.apache.maven.toolchain.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.ArrayList; +import java.util.List; + +import org.apache.maven.building.Problem; +import org.apache.maven.toolchain.model.PersistedToolchains; + +/** + * + * @author Robert Scholte + * @since 3.2.6 + */ +public class DefaultToolchainsBuildingResult + implements ToolchainsBuildingResult +{ + + private PersistedToolchains effectiveToolchains; + + private List problems; + + public DefaultToolchainsBuildingResult( PersistedToolchains effectiveToolchains, List problems ) + { + this.effectiveToolchains = effectiveToolchains; + this.problems = ( problems != null ) ? problems : new ArrayList(); + } + + @Override + public PersistedToolchains getEffectiveToolchains() + { + return effectiveToolchains; + } + + @Override + public List getProblems() + { + return problems; + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java b/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java new file mode 100644 index 0000000000..124bd4ad71 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java @@ -0,0 +1,41 @@ +package org.apache.maven.toolchain.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 toolchains from a user toolchains file and/or a global toolchains file. + * + * @author Robert Scholte + * @since 3.2.6 + */ +public interface ToolchainsBuilder +{ + + /** + * Builds the effective toolchains of the specified toolchains files. + * + * @param request The toolchains building request that holds the parameters, must not be {@code null}. + * @return The result of the toolchains building, never {@code null}. + * @throws ToolchainsBuildingException If the effective toolchains could not be built. + */ + ToolchainsBuildingResult build( ToolchainsBuildingRequest request ) + throws ToolchainsBuildingException; + +} diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java b/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java new file mode 100644 index 0000000000..f8108a37cf --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java @@ -0,0 +1,88 @@ +package org.apache.maven.toolchain.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; + +import org.apache.maven.building.Problem; + +/** + * @author Robert Scholte + * @since 3.2.6 + */ +public class ToolchainsBuildingException + extends Exception +{ + + private final List problems; + + /** + * Creates a new exception with the specified problems. + * + * @param problems The problems that causes this exception, may be {@code null}. + */ + public ToolchainsBuildingException( 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 toolchains" ); + writer.println(); + + for ( Problem 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/toolchain/building/ToolchainsBuildingRequest.java b/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java new file mode 100644 index 0000000000..8defdcf08e --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java @@ -0,0 +1,64 @@ +package org.apache.maven.toolchain.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 org.apache.maven.building.Source; + +/** + * Collects toolchains that control the building of effective toolchains. + * + * @author Robert Scholte + * @since 3.2.6 + */ +public interface ToolchainsBuildingRequest +{ + + /** + * Gets the global toolchains source. + * + * @return The global toolchains source or {@code null} if none. + */ + Source getGlobalToolchainsSource(); + + /** + * Sets the global toolchains source. If both user toolchains and a global toolchains are given, the user toolchains take + * precedence. + * + * @param globalToolchainsSource The global toolchains source, may be {@code null} to disable global toolchains. + * @return This request, never {@code null}. + */ + ToolchainsBuildingRequest setGlobalToolchainsSource( Source globalToolchainsSource ); + + /** + * Gets the user toolchains source. + * + * @return The user toolchains source or {@code null} if none. + */ + Source getUserToolchainsSource(); + + /** + * Sets the user toolchains source. If both user toolchains and a global toolchains are given, the user toolchains take + * precedence. + * + * @param userToolchainsSource The user toolchains source, may be {@code null} to disable user toolchains. + * @return This request, never {@code null}. + */ + ToolchainsBuildingRequest setUserToolchainsSource( Source userToolchainsSource ); +} diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java b/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java new file mode 100644 index 0000000000..2aff1deb64 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java @@ -0,0 +1,50 @@ +package org.apache.maven.toolchain.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.building.Problem; +import org.apache.maven.toolchain.model.PersistedToolchains; + +/** + * Collects the output of the toolchains builder. + * + * @author Robert Scholte + * @since 3.2.6 + */ +public interface ToolchainsBuildingResult +{ + + /** + * Gets the assembled toolchains. + * + * @return The assembled toolchains, never {@code null}. + */ + PersistedToolchains getEffectiveToolchains(); + + /** + * Return a list of problems, if any. + * + * @return a list of problems, never {@code null}. + */ + List getProblems(); + +} diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/io/DefaultToolchainsReader.java b/maven-core/src/main/java/org/apache/maven/toolchain/building/io/DefaultToolchainsReader.java new file mode 100644 index 0000000000..616fe60f47 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/toolchain/building/io/DefaultToolchainsReader.java @@ -0,0 +1,115 @@ +package org.apache.maven.toolchain.building.io; + +/* + * 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.InputStream; +import java.io.Reader; +import java.util.Map; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.apache.maven.toolchain.model.PersistedToolchains; +import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Reader; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.ReaderFactory; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +/** + * Handles deserialization of toolchains from the default textual format. + * + * @author Robert Scholte + * @since 3.2.6 + */ +@Named +@Singleton +public class DefaultToolchainsReader + implements ToolchainsReader +{ + + @Override + public PersistedToolchains read( File input, Map options ) + throws IOException + { + if ( input == null ) + { + throw new IllegalArgumentException( "input file missing" ); + } + + return read( ReaderFactory.newXmlReader( input ), options ); + } + + @Override + public PersistedToolchains read( Reader input, Map options ) + throws IOException + { + if ( input == null ) + { + throw new IllegalArgumentException( "input reader missing" ); + } + + try + { + MavenToolchainsXpp3Reader r = new MavenToolchainsXpp3Reader(); + return r.read( input, isStrict( options ) ); + } + catch ( XmlPullParserException e ) + { + throw new ToolchainsParseException( e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e ); + } + finally + { + IOUtil.close( input ); + } + } + + @Override + public PersistedToolchains read( InputStream input, Map options ) + throws IOException + { + if ( input == null ) + { + throw new IllegalArgumentException( "input stream missing" ); + } + + try + { + MavenToolchainsXpp3Reader r = new MavenToolchainsXpp3Reader(); + return r.read( input, isStrict( options ) ); + } + catch ( XmlPullParserException e ) + { + throw new ToolchainsParseException( e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e ); + } + finally + { + IOUtil.close( input ); + } + } + + private boolean isStrict( Map options ) + { + Object value = ( options != null ) ? options.get( IS_STRICT ) : null; + return value == null || Boolean.parseBoolean( value.toString() ); + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/io/ToolchainsParseException.java b/maven-core/src/main/java/org/apache/maven/toolchain/building/io/ToolchainsParseException.java new file mode 100644 index 0000000000..b35b3c7e81 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/toolchain/building/io/ToolchainsParseException.java @@ -0,0 +1,94 @@ +package org.apache.maven.toolchain.building.io; + +/* + * 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.IOException; + +/** + * Signals a failure to parse the toolchains due to invalid syntax (e.g. non-wellformed XML or unknown elements). + * + * @author Robert Scholte + * @since 3.2.6 + */ +public class ToolchainsParseException + extends IOException +{ + + /** + * The one-based index of the line containing the error. + */ + private final int lineNumber; + + /** + * The one-based index of the column containing the error. + */ + private final int columnNumber; + + /** + * Creates a new parser exception with the specified details. + * + * @param message The error message, may be {@code null}. + * @param lineNumber The one-based index of the line containing the error or {@code -1} if unknown. + * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown. + */ + public ToolchainsParseException( String message, int lineNumber, int columnNumber ) + { + super( message ); + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + } + + /** + * Creates a new parser exception with the specified details. + * + * @param message The error message, may be {@code null}. + * @param lineNumber The one-based index of the line containing the error or {@code -1} if unknown. + * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown. + * @param cause The nested cause of this error, may be {@code null}. + */ + public ToolchainsParseException( String message, int lineNumber, int columnNumber, Throwable cause ) + { + super( message ); + initCause( cause ); + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + } + + /** + * Gets the one-based index of the line containing the error. + * + * @return The one-based index of the line containing the error or a non-positive value if unknown. + */ + public int getLineNumber() + { + return lineNumber; + } + + /** + * Gets the one-based index of the column containing the error. + * + * @return The one-based index of the column containing the error or non-positive value if unknown. + */ + public int getColumnNumber() + { + return columnNumber; + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/io/ToolchainsReader.java b/maven-core/src/main/java/org/apache/maven/toolchain/building/io/ToolchainsReader.java new file mode 100644 index 0000000000..850fdd3b94 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/toolchain/building/io/ToolchainsReader.java @@ -0,0 +1,83 @@ +package org.apache.maven.toolchain.building.io; + +/* + * 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.InputStream; +import java.io.Reader; +import java.util.Map; + +import org.apache.maven.toolchain.model.PersistedToolchains; + +/** + * Handles deserialization of toolchains from some kind of textual format like XML. + * + * @author Robert Scholte + * @since 3.2.6 + */ +public interface ToolchainsReader +{ + + /** + * The key for the option to enable strict parsing. This option is of type {@link Boolean} and defaults to {@code + * true}. If {@code false}, unknown elements will be ignored instead of causing a failure. + */ + String IS_STRICT = "org.apache.maven.toolchains.io.isStrict"; + + /** + * Reads the toolchains from the specified file. + * + * @param input The file to deserialize the toolchains from, must not be {@code null}. + * @param options The options to use for deserialization, may be {@code null} to use the default values. + * @return The deserialized toolchains, never {@code null}. + * @throws IOException If the toolchains could not be deserialized. + * @throws ToolchainsParseException If the input format could not be parsed. + */ + PersistedToolchains read( File input, Map options ) + throws IOException, ToolchainsParseException; + + /** + * Reads the toolchains from the specified character reader. The reader will be automatically closed before the method + * returns. + * + * @param input The reader to deserialize the toolchains from, must not be {@code null}. + * @param options The options to use for deserialization, may be {@code null} to use the default values. + * @return The deserialized toolchains, never {@code null}. + * @throws IOException If the toolchains could not be deserialized. + * @throws ToolchainsParseException If the input format could not be parsed. + */ + PersistedToolchains read( Reader input, Map options ) + throws IOException, ToolchainsParseException; + + /** + * Reads the toolchains from the specified byte stream. The stream will be automatically closed before the method + * returns. + * + * @param input The stream to deserialize the toolchains from, must not be {@code null}. + * @param options The options to use for deserialization, may be {@code null} to use the default values. + * @return The deserialized toolchains, never {@code null}. + * @throws IOException If the toolchains could not be deserialized. + * @throws ToolchainsParseException If the input format could not be parsed. + */ + PersistedToolchains read( InputStream input, Map options ) + throws IOException, ToolchainsParseException; + +} diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java index 04e31b30ea..a78e11dcc9 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java @@ -75,6 +75,8 @@ public class CLIManager public static final char ALTERNATE_USER_TOOLCHAINS = 't'; + public static final String ALTERNATE_GLOBAL_TOOLCHAINS = "gt"; + public static final String FAIL_FAST = "ff"; public static final String FAIL_AT_END = "fae"; @@ -125,6 +127,7 @@ public class CLIManager options.addOption( OptionBuilder.withLongOpt( "settings" ).withDescription( "Alternate path for the user settings file" ).hasArg().create( ALTERNATE_USER_SETTINGS ) ); options.addOption( OptionBuilder.withLongOpt( "global-settings" ).withDescription( "Alternate path for the global settings file" ).hasArg().create( ALTERNATE_GLOBAL_SETTINGS ) ); options.addOption( OptionBuilder.withLongOpt( "toolchains" ).withDescription( "Alternate path for the user toolchains file" ).hasArg().create( ALTERNATE_USER_TOOLCHAINS ) ); + options.addOption( OptionBuilder.withLongOpt( "global-toolchains" ).withDescription( "Alternate path for the global toolchains file" ).hasArg().create( ALTERNATE_GLOBAL_TOOLCHAINS ) ); options.addOption( OptionBuilder.withLongOpt( "fail-fast" ).withDescription( "Stop at first failure in reactorized builds" ).create( FAIL_FAST ) ); options.addOption( OptionBuilder.withLongOpt( "fail-at-end" ).withDescription( "Only fail the build afterwards; allow all non-impacted builds to continue" ).create( FAIL_AT_END ) ); options.addOption( OptionBuilder.withLongOpt( "fail-never" ).withDescription( "NEVER fail the build, regardless of project result" ).create( FAIL_NEVER ) ); 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 ef81408e51..c7b048526e 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 @@ -37,6 +37,7 @@ import org.apache.commons.cli.UnrecognizedOptionException; import org.apache.maven.BuildAbort; import org.apache.maven.InternalErrorException; import org.apache.maven.Maven; +import org.apache.maven.building.Source; import org.apache.maven.cli.event.DefaultEventSpyContext; import org.apache.maven.cli.event.ExecutionEventLogger; import org.apache.maven.cli.logging.Slf4jConfiguration; @@ -65,7 +66,7 @@ import org.apache.maven.settings.building.SettingsBuilder; 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.building.SettingsSource; +import org.apache.maven.toolchain.building.ToolchainsBuilder; import org.codehaus.plexus.ContainerConfiguration; import org.codehaus.plexus.DefaultContainerConfiguration; import org.codehaus.plexus.DefaultPlexusContainer; @@ -113,6 +114,9 @@ public class MavenCli public static final File DEFAULT_USER_TOOLCHAINS_FILE = new File( userMavenConfigurationHome, "toolchains.xml" ); + public static final File DEFAULT_GLOBAL_TOOLCHAINS_FILE = + new File( System.getProperty( "maven.home", System.getProperty( "user.dir", "" ) ), "conf/toolchains.xml" ); + private static final String EXT_CLASS_PATH = "maven.ext.class.path"; private ClassWorld classWorld; @@ -133,6 +137,8 @@ public class MavenCli private SettingsBuilder settingsBuilder; + private ToolchainsBuilder toolchainsBuilder; + private DefaultSecDispatcher dispatcher; public MavenCli() @@ -210,6 +216,7 @@ public class MavenCli localContainer = container( cliRequest ); commands( cliRequest ); settings( cliRequest ); + toolchains( cliRequest ); populateRequest( cliRequest ); encryption( cliRequest ); repository( cliRequest ); @@ -761,10 +768,10 @@ public class MavenCli eventSpyDispatcher.onEvent( settingsRequest ); slf4jLogger.debug( "Reading global settings from " - + getSettingsLocation( settingsRequest.getGlobalSettingsSource(), + + getLocation( settingsRequest.getGlobalSettingsSource(), settingsRequest.getGlobalSettingsFile() ) ); slf4jLogger.debug( "Reading user settings from " - + getSettingsLocation( settingsRequest.getUserSettingsSource(), settingsRequest.getUserSettingsFile() ) ); + + getLocation( settingsRequest.getUserSettingsSource(), settingsRequest.getUserSettingsFile() ) ); SettingsBuildingResult settingsResult = settingsBuilder.build( settingsRequest ); @@ -785,8 +792,57 @@ public class MavenCli slf4jLogger.warn( "" ); } } + + @SuppressWarnings( "checkstyle:methodlength" ) + private void toolchains( CliRequest cliRequest ) + throws Exception + { + File userToolchainsFile; - private Object getSettingsLocation( SettingsSource source, File file ) + if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) ) + { + userToolchainsFile = + new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) ); + userToolchainsFile = resolveFile( userToolchainsFile, cliRequest.workingDirectory ); + + if ( !userToolchainsFile.isFile() ) + { + throw new FileNotFoundException( "The specified user toolchains file does not exist: " + + userToolchainsFile ); + } + } + else + { + userToolchainsFile = DEFAULT_USER_TOOLCHAINS_FILE; + } + + File globalToolchainsFile; + + if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) ) + { + globalToolchainsFile = + new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) ); + globalToolchainsFile = resolveFile( globalToolchainsFile, cliRequest.workingDirectory ); + + if ( !globalToolchainsFile.isFile() ) + { + throw new FileNotFoundException( "The specified global toolchains file does not exist: " + + globalToolchainsFile ); + } + } + else + { + globalToolchainsFile = DEFAULT_GLOBAL_TOOLCHAINS_FILE; + } + + cliRequest.request.setGlobalToolchainsFile( globalToolchainsFile ); + cliRequest.request.setUserToolchainsFile( userToolchainsFile ); + + // Unlike settings, the toolchains aren't built here. + // That's done by the maven-toolchains-plugin, by calling it from the project with the proper configuration + } + + private Object getLocation( Source source, File file ) { if ( source != null ) { @@ -974,7 +1030,7 @@ public class MavenCli .setUpdateSnapshots( updateSnapshots ) // default: false .setNoSnapshotUpdates( noSnapshotUpdates ) // default: false .setGlobalChecksumPolicy( globalChecksumPolicy ) // default: warn - .setUserToolchainsFile( userToolchainsFile ); + ; if ( alternatePomFile != null ) {