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