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