| 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.Problem; |
| import org.apache.maven.building.ProblemCollector; |
| import org.apache.maven.building.ProblemCollectorFactory; |
| import org.apache.maven.building.Source; |
| import org.apache.maven.toolchain.io.ToolchainsParseException; |
| import org.apache.maven.toolchain.io.ToolchainsReader; |
| import org.apache.maven.toolchain.io.ToolchainsWriter; |
| import org.apache.maven.toolchain.merge.MavenToolchainMerger; |
| import org.apache.maven.toolchain.model.PersistedToolchains; |
| import org.apache.maven.toolchain.model.TrackableBase; |
| import org.codehaus.plexus.interpolation.EnvarBasedValueSource; |
| import org.codehaus.plexus.interpolation.InterpolationException; |
| import org.codehaus.plexus.interpolation.RegexBasedInterpolator; |
| |
| import javax.inject.Inject; |
| import javax.inject.Named; |
| import javax.inject.Singleton; |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * |
| * @author Robert Scholte |
| * @since 3.3.0 |
| */ |
| @Named |
| @Singleton |
| public class DefaultToolchainsBuilder |
| implements ToolchainsBuilder |
| { |
| private final MavenToolchainMerger toolchainsMerger = new MavenToolchainMerger(); |
| private final ToolchainsWriter toolchainsWriter; |
| private final ToolchainsReader toolchainsReader; |
| |
| @Inject |
| public DefaultToolchainsBuilder( |
| ToolchainsWriter toolchainsWriter, |
| ToolchainsReader toolchainsReader ) |
| { |
| this.toolchainsWriter = toolchainsWriter; |
| this.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( "" ); |
| |
| userToolchains = interpolate( userToolchains, problems ); |
| |
| if ( hasErrors( problems.getProblems() ) ) |
| { |
| throw new ToolchainsBuildingException( problems.getProblems() ); |
| } |
| |
| |
| return new DefaultToolchainsBuildingResult( userToolchains, problems.getProblems() ); |
| } |
| |
| private PersistedToolchains interpolate( PersistedToolchains toolchains, ProblemCollector problems ) |
| { |
| |
| StringWriter stringWriter = new StringWriter( 1024 * 4 ); |
| try |
| { |
| toolchainsWriter.write( stringWriter, null, toolchains ); |
| } |
| catch ( IOException e ) |
| { |
| throw new IllegalStateException( "Failed to serialize toolchains to memory", e ); |
| } |
| |
| String serializedToolchains = stringWriter.toString(); |
| |
| RegexBasedInterpolator interpolator = new RegexBasedInterpolator(); |
| |
| try |
| { |
| interpolator.addValueSource( new EnvarBasedValueSource() ); |
| } |
| catch ( IOException e ) |
| { |
| problems.add( Problem.Severity.WARNING, "Failed to use environment variables for interpolation: " |
| + e.getMessage(), -1, -1, e ); |
| } |
| |
| interpolator.addPostProcessor( ( expression, 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 |
| { |
| serializedToolchains = interpolator.interpolate( serializedToolchains ); |
| } |
| catch ( InterpolationException e ) |
| { |
| problems.add( Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e ); |
| return toolchains; |
| } |
| |
| PersistedToolchains result; |
| try |
| { |
| Map<String, ?> options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.FALSE ); |
| |
| result = toolchainsReader.read( new StringReader( serializedToolchains ), options ); |
| } |
| catch ( IOException e ) |
| { |
| problems.add( Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e ); |
| return toolchains; |
| } |
| |
| return result; |
| } |
| |
| private PersistedToolchains readToolchains( Source toolchainsSource, ToolchainsBuildingRequest request, |
| ProblemCollector problems ) |
| { |
| if ( toolchainsSource == null ) |
| { |
| return new PersistedToolchains(); |
| } |
| |
| PersistedToolchains toolchains; |
| |
| try |
| { |
| Map<String, ?> 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<Problem> problems ) |
| { |
| if ( problems != null ) |
| { |
| for ( Problem problem : problems ) |
| { |
| if ( Problem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 ) |
| { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| } |