1 package org.apache.maven.toolchain.building;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.building.Problem;
23 import org.apache.maven.building.ProblemCollector;
24 import org.apache.maven.building.ProblemCollectorFactory;
25 import org.apache.maven.building.Source;
26 import org.apache.maven.toolchain.io.ToolchainsParseException;
27 import org.apache.maven.toolchain.io.ToolchainsReader;
28 import org.apache.maven.toolchain.io.ToolchainsWriter;
29 import org.apache.maven.toolchain.merge.MavenToolchainMerger;
30 import org.apache.maven.api.toolchain.PersistedToolchains;
31 import org.apache.maven.api.toolchain.TrackableBase;
32 import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
33 import org.codehaus.plexus.interpolation.InterpolationException;
34 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
35
36 import javax.inject.Inject;
37 import javax.inject.Named;
38 import javax.inject.Singleton;
39 import java.io.IOException;
40 import java.io.StringReader;
41 import java.io.StringWriter;
42 import java.util.Collections;
43 import java.util.List;
44 import java.util.Map;
45
46
47
48
49
50
51 @Named
52 @Singleton
53 public class DefaultToolchainsBuilder
54 implements ToolchainsBuilder
55 {
56 private final MavenToolchainMerger toolchainsMerger = new MavenToolchainMerger();
57 private final ToolchainsWriter toolchainsWriter;
58 private final ToolchainsReader toolchainsReader;
59
60 @Inject
61 public DefaultToolchainsBuilder(
62 ToolchainsWriter toolchainsWriter,
63 ToolchainsReader toolchainsReader )
64 {
65 this.toolchainsWriter = toolchainsWriter;
66 this.toolchainsReader = toolchainsReader;
67 }
68
69 @Override
70 public ToolchainsBuildingResult build( ToolchainsBuildingRequest request )
71 throws ToolchainsBuildingException
72 {
73 ProblemCollector problems = ProblemCollectorFactory.newInstance( null );
74
75 PersistedToolchains globalToolchains = readToolchains( request.getGlobalToolchainsSource(), request, problems );
76
77 PersistedToolchains userToolchains = readToolchains( request.getUserToolchainsSource(), request, problems );
78
79 PersistedToolchains merged = toolchainsMerger.merge(
80 userToolchains, globalToolchains, TrackableBase.GLOBAL_LEVEL );
81
82 problems.setSource( "" );
83
84 merged = interpolate( merged, problems );
85
86 if ( hasErrors( problems.getProblems() ) )
87 {
88 throw new ToolchainsBuildingException( problems.getProblems() );
89 }
90
91 return new DefaultToolchainsBuildingResult(
92 new org.apache.maven.toolchain.model.PersistedToolchains( merged ), problems.getProblems() );
93 }
94
95 private PersistedToolchains interpolate( PersistedToolchains toolchains, ProblemCollector problems )
96 {
97
98 StringWriter stringWriter = new StringWriter( 1024 * 4 );
99 try
100 {
101 toolchainsWriter.write( stringWriter, null, toolchains );
102 }
103 catch ( IOException e )
104 {
105 throw new IllegalStateException( "Failed to serialize toolchains to memory", e );
106 }
107
108 String serializedToolchains = stringWriter.toString();
109
110 RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
111
112 try
113 {
114 interpolator.addValueSource( new EnvarBasedValueSource() );
115 }
116 catch ( IOException e )
117 {
118 problems.add( Problem.Severity.WARNING, "Failed to use environment variables for interpolation: "
119 + e.getMessage(), -1, -1, e );
120 }
121
122 interpolator.addPostProcessor( ( expression, value ) ->
123 {
124 if ( value != null )
125 {
126
127 value = value.toString().replace( "&", "&" ).replace( "<", "<" ).replace( ">", ">" );
128 return value;
129 }
130 return null;
131 } );
132
133 try
134 {
135 serializedToolchains = interpolator.interpolate( serializedToolchains );
136 }
137 catch ( InterpolationException e )
138 {
139 problems.add( Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e );
140 return toolchains;
141 }
142
143 PersistedToolchains result;
144 try
145 {
146 Map<String, ?> options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.FALSE );
147
148 result = toolchainsReader.read( new StringReader( serializedToolchains ), options );
149 }
150 catch ( IOException e )
151 {
152 problems.add( Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e );
153 return toolchains;
154 }
155
156 return result;
157 }
158
159 private PersistedToolchains readToolchains( Source toolchainsSource, ToolchainsBuildingRequest request,
160 ProblemCollector problems )
161 {
162 if ( toolchainsSource == null )
163 {
164 return PersistedToolchains.newInstance();
165 }
166
167 PersistedToolchains toolchains;
168
169 try
170 {
171 Map<String, ?> options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.TRUE );
172
173 try
174 {
175 toolchains = toolchainsReader.read( toolchainsSource.getInputStream(), options );
176 }
177 catch ( ToolchainsParseException e )
178 {
179 options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.FALSE );
180
181 toolchains = toolchainsReader.read( toolchainsSource.getInputStream(), options );
182
183 problems.add( Problem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(),
184 e );
185 }
186 }
187 catch ( ToolchainsParseException e )
188 {
189 problems.add( Problem.Severity.FATAL, "Non-parseable toolchains " + toolchainsSource.getLocation()
190 + ": " + e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
191 return PersistedToolchains.newInstance();
192 }
193 catch ( IOException e )
194 {
195 problems.add( Problem.Severity.FATAL, "Non-readable toolchains " + toolchainsSource.getLocation()
196 + ": " + e.getMessage(), -1, -1, e );
197 return PersistedToolchains.newInstance();
198 }
199
200 return toolchains;
201 }
202
203 private boolean hasErrors( List<Problem> problems )
204 {
205 if ( problems != null )
206 {
207 for ( Problem problem : problems )
208 {
209 if ( Problem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 )
210 {
211 return true;
212 }
213 }
214 }
215
216 return false;
217 }
218 }