1 package org.apache.maven.settings.building;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.StringReader;
25 import java.io.StringWriter;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Map;
29
30 import javax.inject.Inject;
31 import javax.inject.Named;
32 import javax.inject.Singleton;
33
34 import org.apache.maven.building.FileSource;
35 import org.apache.maven.building.Source;
36 import org.apache.maven.api.settings.Settings;
37 import org.apache.maven.settings.TrackableBase;
38 import org.apache.maven.settings.io.SettingsParseException;
39 import org.apache.maven.settings.io.SettingsReader;
40 import org.apache.maven.settings.io.SettingsWriter;
41 import org.apache.maven.settings.merge.MavenSettingsMerger;
42 import org.apache.maven.settings.validation.SettingsValidator;
43 import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
44 import org.codehaus.plexus.interpolation.InterpolationException;
45 import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
46 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
47
48
49
50
51
52
53 @Named
54 @Singleton
55 public class DefaultSettingsBuilder
56 implements SettingsBuilder
57 {
58
59 private SettingsReader settingsReader;
60
61 private SettingsWriter settingsWriter;
62
63 private SettingsValidator settingsValidator;
64
65 private final MavenSettingsMerger settingsMerger = new MavenSettingsMerger();
66
67 @Inject
68 public DefaultSettingsBuilder( SettingsReader settingsReader,
69 SettingsWriter settingsWriter,
70 SettingsValidator settingsValidator )
71 {
72 this.settingsReader = settingsReader;
73 this.settingsWriter = settingsWriter;
74 this.settingsValidator = settingsValidator;
75 }
76
77 public DefaultSettingsBuilder setSettingsReader( SettingsReader settingsReader )
78 {
79 this.settingsReader = settingsReader;
80 return this;
81 }
82
83 public DefaultSettingsBuilder setSettingsWriter( SettingsWriter settingsWriter )
84 {
85 this.settingsWriter = settingsWriter;
86 return this;
87 }
88
89 public DefaultSettingsBuilder setSettingsValidator( SettingsValidator settingsValidator )
90 {
91 this.settingsValidator = settingsValidator;
92 return this;
93 }
94
95 @Override
96 public SettingsBuildingResult build( SettingsBuildingRequest request )
97 throws SettingsBuildingException
98 {
99 DefaultSettingsProblemCollector problems = new DefaultSettingsProblemCollector( null );
100
101 Source globalSettingsSource =
102 getSettingsSource( request.getGlobalSettingsFile(), request.getGlobalSettingsSource() );
103 Settings globalSettings = readSettings( globalSettingsSource, request, problems );
104
105 Source userSettingsSource =
106 getSettingsSource( request.getUserSettingsFile(), request.getUserSettingsSource() );
107 Settings userSettings = readSettings( userSettingsSource, request, problems );
108
109 userSettings = settingsMerger.merge( userSettings, globalSettings, TrackableBase.GLOBAL_LEVEL );
110
111 problems.setSource( "" );
112
113 userSettings = interpolate( userSettings, request, problems );
114
115
116 String localRepository = userSettings.getLocalRepository();
117 if ( localRepository != null && localRepository.length() > 0 )
118 {
119 File file = new File( localRepository );
120 if ( !file.isAbsolute() && file.getPath().startsWith( File.separator ) )
121 {
122 userSettings = userSettings.withLocalRepository( file.getAbsolutePath() );
123 }
124 }
125
126 if ( hasErrors( problems.getProblems() ) )
127 {
128 throw new SettingsBuildingException( problems.getProblems() );
129 }
130
131 return new DefaultSettingsBuildingResult( new org.apache.maven.settings.Settings( userSettings ),
132 problems.getProblems() );
133 }
134
135 private boolean hasErrors( List<SettingsProblem> problems )
136 {
137 if ( problems != null )
138 {
139 for ( SettingsProblem problem : problems )
140 {
141 if ( SettingsProblem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 )
142 {
143 return true;
144 }
145 }
146 }
147
148 return false;
149 }
150
151 private Source getSettingsSource( File settingsFile, Source settingsSource )
152 {
153 if ( settingsSource != null )
154 {
155 return settingsSource;
156 }
157 else if ( settingsFile != null && settingsFile.exists() )
158 {
159 return new FileSource( settingsFile );
160 }
161 return null;
162 }
163
164 private Settings readSettings( Source settingsSource, SettingsBuildingRequest request,
165 DefaultSettingsProblemCollector problems )
166 {
167 if ( settingsSource == null )
168 {
169 return Settings.newInstance();
170 }
171
172 problems.setSource( settingsSource.getLocation() );
173
174 Settings settings;
175
176 try
177 {
178 Map<String, ?> options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.TRUE );
179
180 try
181 {
182 settings = settingsReader.read( settingsSource.getInputStream(), options );
183 }
184 catch ( SettingsParseException e )
185 {
186 options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.FALSE );
187
188 settings = settingsReader.read( settingsSource.getInputStream(), options );
189
190 problems.add( SettingsProblem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(),
191 e );
192 }
193 }
194 catch ( SettingsParseException e )
195 {
196 problems.add( SettingsProblem.Severity.FATAL, "Non-parseable settings " + settingsSource.getLocation()
197 + ": " + e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
198 return Settings.newInstance();
199 }
200 catch ( IOException e )
201 {
202 problems.add( SettingsProblem.Severity.FATAL, "Non-readable settings " + settingsSource.getLocation()
203 + ": " + e.getMessage(), -1, -1, e );
204 return Settings.newInstance();
205 }
206
207 settingsValidator.validate( settings, problems );
208
209 return settings;
210 }
211
212 private Settings interpolate( Settings settings, SettingsBuildingRequest request,
213 SettingsProblemCollector problems )
214 {
215 StringWriter writer = new StringWriter( 1024 * 4 );
216
217 try
218 {
219 settingsWriter.write( writer, null, settings );
220 }
221 catch ( IOException e )
222 {
223 throw new IllegalStateException( "Failed to serialize settings to memory", e );
224 }
225
226 String serializedSettings = writer.toString();
227
228 RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
229
230 interpolator.addValueSource( new PropertiesBasedValueSource( request.getUserProperties() ) );
231
232 interpolator.addValueSource( new PropertiesBasedValueSource( request.getSystemProperties() ) );
233
234 try
235 {
236 interpolator.addValueSource( new EnvarBasedValueSource() );
237 }
238 catch ( IOException e )
239 {
240 problems.add( SettingsProblem.Severity.WARNING, "Failed to use environment variables for interpolation: "
241 + e.getMessage(), -1, -1, e );
242 }
243
244 interpolator.addPostProcessor( ( expression, value ) ->
245 {
246 if ( value != null )
247 {
248
249 value = value.toString().replace( "&", "&" ).replace( "<", "<" ).replace( ">", ">" );
250 return value;
251 }
252 return null;
253 } );
254
255 try
256 {
257 serializedSettings = interpolator.interpolate( serializedSettings, "settings" );
258 }
259 catch ( InterpolationException e )
260 {
261 problems.add( SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1,
262 e );
263
264 return settings;
265 }
266
267 Settings result;
268 try
269 {
270 Map<String, ?> options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.FALSE );
271 result = settingsReader.read( new StringReader( serializedSettings ), options );
272 }
273 catch ( IOException e )
274 {
275 problems.add( SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1,
276 e );
277 return settings;
278 }
279
280 return result;
281 }
282
283 }