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