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.RegexBasedInterpolator;
45
46
47
48
49
50 @Named
51 @Singleton
52 public class DefaultToolchainsBuilder implements ToolchainsBuilder {
53 private final MavenToolchainMerger toolchainsMerger = new MavenToolchainMerger();
54 private final ToolchainsWriter toolchainsWriter;
55 private final ToolchainsReader toolchainsReader;
56
57 @Inject
58 public DefaultToolchainsBuilder(ToolchainsWriter toolchainsWriter, ToolchainsReader toolchainsReader) {
59 this.toolchainsWriter = toolchainsWriter;
60 this.toolchainsReader = toolchainsReader;
61 }
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((expression, value) -> {
109 if (value != null) {
110
111 value = value.toString()
112 .replace("&", "&")
113 .replace("<", "<")
114 .replace(">", ">");
115 return value;
116 }
117 return null;
118 });
119
120 try {
121 serializedToolchains = interpolator.interpolate(serializedToolchains);
122 } catch (InterpolationException e) {
123 problems.add(Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e);
124 return toolchains;
125 }
126
127 PersistedToolchains result;
128 try {
129 Map<String, ?> options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.FALSE);
130
131 result = toolchainsReader.read(new StringReader(serializedToolchains), options);
132 } catch (IOException e) {
133 problems.add(Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e);
134 return toolchains;
135 }
136
137 return result;
138 }
139
140 private PersistedToolchains readToolchains(
141 Source toolchainsSource, ToolchainsBuildingRequest request, ProblemCollector problems) {
142 if (toolchainsSource == null) {
143 return new PersistedToolchains();
144 }
145
146 PersistedToolchains toolchains;
147
148 try {
149 Map<String, ?> options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.TRUE);
150
151 try {
152 toolchains = toolchainsReader.read(toolchainsSource.getInputStream(), options);
153 } catch (ToolchainsParseException e) {
154 options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.FALSE);
155
156 toolchains = toolchainsReader.read(toolchainsSource.getInputStream(), options);
157
158 problems.add(Problem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e);
159 }
160 } catch (ToolchainsParseException e) {
161 problems.add(
162 Problem.Severity.FATAL,
163 "Non-parseable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(),
164 e.getLineNumber(),
165 e.getColumnNumber(),
166 e);
167 return new PersistedToolchains();
168 } catch (IOException e) {
169 problems.add(
170 Problem.Severity.FATAL,
171 "Non-readable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(),
172 -1,
173 -1,
174 e);
175 return new PersistedToolchains();
176 }
177
178 return toolchains;
179 }
180
181 private boolean hasErrors(List<Problem> problems) {
182 if (problems != null) {
183 for (Problem problem : problems) {
184 if (Problem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) {
185 return true;
186 }
187 }
188 }
189
190 return false;
191 }
192 }