1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.impl;
20
21 import javax.xml.stream.Location;
22 import javax.xml.stream.XMLStreamException;
23
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import org.apache.maven.api.di.Named;
30 import org.apache.maven.api.services.BuilderProblem;
31 import org.apache.maven.api.services.Source;
32 import org.apache.maven.api.services.ToolchainsBuilder;
33 import org.apache.maven.api.services.ToolchainsBuilderException;
34 import org.apache.maven.api.services.ToolchainsBuilderRequest;
35 import org.apache.maven.api.services.ToolchainsBuilderResult;
36 import org.apache.maven.api.services.xml.ToolchainsXmlFactory;
37 import org.apache.maven.api.services.xml.XmlReaderException;
38 import org.apache.maven.api.services.xml.XmlReaderRequest;
39 import org.apache.maven.api.toolchain.PersistedToolchains;
40 import org.apache.maven.toolchain.v4.MavenToolchainsMerger;
41 import org.apache.maven.toolchain.v4.MavenToolchainsTransformer;
42 import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
43 import org.codehaus.plexus.interpolation.InterpolationException;
44 import org.codehaus.plexus.interpolation.MapBasedValueSource;
45 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
46
47
48
49
50
51 @Named
52 public class DefaultToolchainsBuilder implements ToolchainsBuilder {
53
54 private final MavenToolchainsMerger toolchainsMerger = new MavenToolchainsMerger();
55
56 @Override
57 public ToolchainsBuilderResult build(ToolchainsBuilderRequest request) throws ToolchainsBuilderException {
58 List<BuilderProblem> problems = new ArrayList<>();
59
60 Source installationSource = request.getInstallationToolchainsSource().orElse(null);
61 PersistedToolchains installation = readToolchains(installationSource, request, problems);
62
63 Source userSource = request.getUserToolchainsSource().orElse(null);
64 PersistedToolchains user = readToolchains(userSource, request, problems);
65
66 PersistedToolchains effective = toolchainsMerger.merge(user, installation, false, null);
67
68 if (hasErrors(problems)) {
69 throw new ToolchainsBuilderException("Error building toolchains", problems);
70 }
71
72 return new DefaultToolchainsBuilderResult(effective, problems);
73 }
74
75 private boolean hasErrors(List<BuilderProblem> problems) {
76 if (problems != null) {
77 for (BuilderProblem problem : problems) {
78 if (BuilderProblem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) {
79 return true;
80 }
81 }
82 }
83
84 return false;
85 }
86
87 private PersistedToolchains readToolchains(
88 Source toolchainsSource, ToolchainsBuilderRequest request, List<BuilderProblem> problems) {
89 if (toolchainsSource == null) {
90 return PersistedToolchains.newInstance();
91 }
92
93 PersistedToolchains toolchains;
94
95 try {
96 try {
97 InputStream is = toolchainsSource.openStream();
98 if (is == null) {
99 return PersistedToolchains.newInstance();
100 }
101 toolchains = request.getSession()
102 .getService(ToolchainsXmlFactory.class)
103 .read(XmlReaderRequest.builder()
104 .inputStream(is)
105 .location(toolchainsSource.getLocation())
106 .strict(true)
107 .build());
108 } catch (XmlReaderException e) {
109 InputStream is = toolchainsSource.openStream();
110 if (is == null) {
111 return PersistedToolchains.newInstance();
112 }
113 toolchains = request.getSession()
114 .getService(ToolchainsXmlFactory.class)
115 .read(XmlReaderRequest.builder()
116 .inputStream(is)
117 .location(toolchainsSource.getLocation())
118 .strict(false)
119 .build());
120 Location loc = e.getCause() instanceof XMLStreamException xe ? xe.getLocation() : null;
121 problems.add(new DefaultBuilderProblem(
122 toolchainsSource.getLocation(),
123 loc != null ? loc.getLineNumber() : -1,
124 loc != null ? loc.getColumnNumber() : -1,
125 e,
126 e.getMessage(),
127 BuilderProblem.Severity.WARNING));
128 }
129 } catch (XmlReaderException e) {
130 Location loc = e.getCause() instanceof XMLStreamException xe ? xe.getLocation() : null;
131 problems.add(new DefaultBuilderProblem(
132 toolchainsSource.getLocation(),
133 loc != null ? loc.getLineNumber() : -1,
134 loc != null ? loc.getColumnNumber() : -1,
135 e,
136 "Non-parseable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(),
137 BuilderProblem.Severity.FATAL));
138 return PersistedToolchains.newInstance();
139 } catch (IOException e) {
140 problems.add(new DefaultBuilderProblem(
141 toolchainsSource.getLocation(),
142 -1,
143 -1,
144 e,
145 "Non-readable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(),
146 BuilderProblem.Severity.FATAL));
147 return PersistedToolchains.newInstance();
148 }
149
150 toolchains = interpolate(toolchains, request, problems);
151
152 return toolchains;
153 }
154
155 private PersistedToolchains interpolate(
156 PersistedToolchains toolchains, ToolchainsBuilderRequest request, List<BuilderProblem> problems) {
157
158 RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
159
160 interpolator.addValueSource(new MapBasedValueSource(request.getSession().getUserProperties()));
161
162 interpolator.addValueSource(new MapBasedValueSource(request.getSession().getSystemProperties()));
163
164 try {
165 interpolator.addValueSource(new EnvarBasedValueSource());
166 } catch (IOException e) {
167 problems.add(new DefaultBuilderProblem(
168 null,
169 -1,
170 -1,
171 e,
172 "Failed to use environment variables for interpolation: " + e.getMessage(),
173 BuilderProblem.Severity.WARNING));
174 }
175
176 return new MavenToolchainsTransformer(value -> {
177 try {
178 return value != null ? interpolator.interpolate(value) : null;
179 } catch (InterpolationException e) {
180 problems.add(new DefaultBuilderProblem(
181 null,
182 -1,
183 -1,
184 e,
185 "Failed to interpolate toolchains: " + e.getMessage(),
186 BuilderProblem.Severity.WARNING));
187 return value;
188 }
189 })
190 .visit(toolchains);
191 }
192
193
194
195
196
197 static class DefaultToolchainsBuilderResult implements ToolchainsBuilderResult {
198
199 private final PersistedToolchains effectiveToolchains;
200
201 private final List<BuilderProblem> problems;
202
203 DefaultToolchainsBuilderResult(PersistedToolchains effectiveToolchains, List<BuilderProblem> problems) {
204 this.effectiveToolchains = effectiveToolchains;
205 this.problems = (problems != null) ? problems : new ArrayList<>();
206 }
207
208 @Override
209 public PersistedToolchains getEffectiveToolchains() {
210 return effectiveToolchains;
211 }
212
213 @Override
214 public List<BuilderProblem> getProblems() {
215 return problems;
216 }
217 }
218 }