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