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