1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.aether;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23
24 import java.nio.file.Paths;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.HashMap;
28 import java.util.LinkedHashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.stream.Collectors;
32
33 import org.apache.maven.RepositoryUtils;
34 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
35 import org.apache.maven.bridge.MavenRepositorySystem;
36 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
37 import org.apache.maven.execution.MavenExecutionRequest;
38 import org.apache.maven.model.ModelBase;
39 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
40 import org.apache.maven.rtinfo.RuntimeInformation;
41 import org.apache.maven.settings.Mirror;
42 import org.apache.maven.settings.Proxy;
43 import org.apache.maven.settings.Server;
44 import org.apache.maven.settings.building.SettingsProblem;
45 import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
46 import org.apache.maven.settings.crypto.SettingsDecrypter;
47 import org.apache.maven.settings.crypto.SettingsDecryptionResult;
48 import org.codehaus.plexus.configuration.PlexusConfiguration;
49 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
50 import org.codehaus.plexus.logging.Logger;
51 import org.codehaus.plexus.util.xml.Xpp3Dom;
52 import org.eclipse.aether.ConfigurationProperties;
53 import org.eclipse.aether.DefaultRepositorySystemSession;
54 import org.eclipse.aether.RepositorySystem;
55 import org.eclipse.aether.repository.LocalRepository;
56 import org.eclipse.aether.repository.LocalRepositoryManager;
57 import org.eclipse.aether.repository.RepositoryPolicy;
58 import org.eclipse.aether.repository.WorkspaceReader;
59 import org.eclipse.aether.resolution.ResolutionErrorPolicy;
60 import org.eclipse.aether.util.ConfigUtils;
61 import org.eclipse.aether.util.listener.ChainedRepositoryListener;
62 import org.eclipse.aether.util.repository.AuthenticationBuilder;
63 import org.eclipse.aether.util.repository.ChainedLocalRepositoryManager;
64 import org.eclipse.aether.util.repository.DefaultAuthenticationSelector;
65 import org.eclipse.aether.util.repository.DefaultMirrorSelector;
66 import org.eclipse.aether.util.repository.DefaultProxySelector;
67 import org.eclipse.aether.util.repository.SimpleResolutionErrorPolicy;
68 import org.eclipse.sisu.Nullable;
69
70
71
72
73 @Named
74 public class DefaultRepositorySystemSessionFactory {
75
76
77
78
79
80
81
82 private static final String MAVEN_REPO_LOCAL_TAIL = "maven.repo.local.tail";
83
84
85
86
87
88
89
90
91
92 public static final String MAVEN_REPO_LOCAL_HEAD = "maven.repo.local.head";
93
94
95
96
97
98
99
100 private static final String MAVEN_REPO_LOCAL_TAIL_IGNORE_AVAILABILITY = "maven.repo.local.tail.ignoreAvailability";
101
102
103
104
105
106
107
108
109
110 private static final String MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE = "maven.repo.local.recordReverseTree";
111
112 private static final String MAVEN_RESOLVER_TRANSPORT_KEY = "maven.resolver.transport";
113
114 private static final String MAVEN_RESOLVER_TRANSPORT_DEFAULT = "default";
115
116 private static final String MAVEN_RESOLVER_TRANSPORT_WAGON = "wagon";
117
118 private static final String MAVEN_RESOLVER_TRANSPORT_NATIVE = "native";
119
120 private static final String MAVEN_RESOLVER_TRANSPORT_AUTO = "auto";
121
122 private static final String WAGON_TRANSPORTER_PRIORITY_KEY = "aether.priority.WagonTransporterFactory";
123
124 private static final String NATIVE_HTTP_TRANSPORTER_PRIORITY_KEY = "aether.priority.HttpTransporterFactory";
125
126 private static final String NATIVE_FILE_TRANSPORTER_PRIORITY_KEY = "aether.priority.FileTransporterFactory";
127
128 private static final String RESOLVER_MAX_PRIORITY = String.valueOf(Float.MAX_VALUE);
129
130 @Inject
131 private Logger logger;
132
133 @Inject
134 private ArtifactHandlerManager artifactHandlerManager;
135
136 @Inject
137 private RepositorySystem repoSystem;
138
139 @Inject
140 @Nullable
141 @Named("ide")
142 private WorkspaceReader workspaceRepository;
143
144 @Inject
145 private SettingsDecrypter settingsDecrypter;
146
147 @Inject
148 private EventSpyDispatcher eventSpyDispatcher;
149
150 @Inject
151 MavenRepositorySystem mavenRepositorySystem;
152
153 @Inject
154 private RuntimeInformation runtimeInformation;
155
156 @SuppressWarnings("checkstyle:methodlength")
157 public DefaultRepositorySystemSession newRepositorySession(MavenExecutionRequest request) {
158 DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
159
160 session.setCache(request.getRepositoryCache());
161
162 Map<Object, Object> configProps = new LinkedHashMap<>();
163 configProps.put(ConfigurationProperties.USER_AGENT, getUserAgent());
164 configProps.put(ConfigurationProperties.INTERACTIVE, request.isInteractiveMode());
165 configProps.put("maven.startTime", request.getStartTime());
166
167 configProps.putAll(getPropertiesFromRequestedProfiles(request));
168
169 configProps.putAll(request.getSystemProperties());
170 configProps.putAll(request.getUserProperties());
171
172 session.setOffline(request.isOffline());
173 session.setChecksumPolicy(request.getGlobalChecksumPolicy());
174 if (request.isNoSnapshotUpdates()) {
175 session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_NEVER);
176 } else if (request.isUpdateSnapshots()) {
177 session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_ALWAYS);
178 } else {
179 session.setUpdatePolicy(null);
180 }
181
182 int errorPolicy = 0;
183 errorPolicy |= request.isCacheNotFound()
184 ? ResolutionErrorPolicy.CACHE_NOT_FOUND
185 : ResolutionErrorPolicy.CACHE_DISABLED;
186 errorPolicy |= request.isCacheTransferError()
187 ? ResolutionErrorPolicy.CACHE_TRANSFER_ERROR
188 : ResolutionErrorPolicy.CACHE_DISABLED;
189 session.setResolutionErrorPolicy(
190 new SimpleResolutionErrorPolicy(errorPolicy, errorPolicy | ResolutionErrorPolicy.CACHE_NOT_FOUND));
191
192 session.setArtifactTypeRegistry(RepositoryUtils.newArtifactTypeRegistry(artifactHandlerManager));
193
194 if (request.getWorkspaceReader() != null) {
195 session.setWorkspaceReader(request.getWorkspaceReader());
196 } else {
197 session.setWorkspaceReader(workspaceRepository);
198 }
199
200 DefaultSettingsDecryptionRequest decrypt = new DefaultSettingsDecryptionRequest();
201 decrypt.setProxies(request.getProxies());
202 decrypt.setServers(request.getServers());
203 SettingsDecryptionResult decrypted = settingsDecrypter.decrypt(decrypt);
204
205 if (logger.isDebugEnabled()) {
206 for (SettingsProblem problem : decrypted.getProblems()) {
207 logger.debug(problem.getMessage(), problem.getException());
208 }
209 }
210
211 DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
212 for (Mirror mirror : request.getMirrors()) {
213 mirrorSelector.add(
214 mirror.getId(),
215 mirror.getUrl(),
216 mirror.getLayout(),
217 false,
218 mirror.isBlocked(),
219 mirror.getMirrorOf(),
220 mirror.getMirrorOfLayouts());
221 }
222 session.setMirrorSelector(mirrorSelector);
223
224 DefaultProxySelector proxySelector = new DefaultProxySelector();
225 for (Proxy proxy : decrypted.getProxies()) {
226 AuthenticationBuilder authBuilder = new AuthenticationBuilder();
227 authBuilder.addUsername(proxy.getUsername()).addPassword(proxy.getPassword());
228 proxySelector.add(
229 new org.eclipse.aether.repository.Proxy(
230 proxy.getProtocol(), proxy.getHost(), proxy.getPort(), authBuilder.build()),
231 proxy.getNonProxyHosts());
232 }
233 session.setProxySelector(proxySelector);
234
235 DefaultAuthenticationSelector authSelector = new DefaultAuthenticationSelector();
236 for (Server server : decrypted.getServers()) {
237 AuthenticationBuilder authBuilder = new AuthenticationBuilder();
238 authBuilder.addUsername(server.getUsername()).addPassword(server.getPassword());
239 authBuilder.addPrivateKey(server.getPrivateKey(), server.getPassphrase());
240 authSelector.add(server.getId(), authBuilder.build());
241
242 if (server.getConfiguration() != null) {
243 Xpp3Dom dom = (Xpp3Dom) server.getConfiguration();
244 for (int i = dom.getChildCount() - 1; i >= 0; i--) {
245 Xpp3Dom child = dom.getChild(i);
246 if ("wagonProvider".equals(child.getName())) {
247 dom.removeChild(i);
248 }
249 }
250
251 XmlPlexusConfiguration config = new XmlPlexusConfiguration(dom);
252 configProps.put("aether.connector.wagon.config." + server.getId(), config);
253
254
255
256
257 Map<String, String> headers = null;
258 Integer connectTimeout = null;
259 Integer requestTimeout = null;
260
261 PlexusConfiguration httpHeaders = config.getChild("httpHeaders", false);
262 if (httpHeaders != null) {
263 PlexusConfiguration[] properties = httpHeaders.getChildren("property");
264 if (properties != null && properties.length > 0) {
265 headers = new HashMap<>();
266 for (PlexusConfiguration property : properties) {
267 headers.put(
268 property.getChild("name").getValue(),
269 property.getChild("value").getValue());
270 }
271 }
272 }
273
274 PlexusConfiguration connectTimeoutXml = config.getChild("connectTimeout", false);
275 if (connectTimeoutXml != null) {
276 connectTimeout = Integer.parseInt(connectTimeoutXml.getValue());
277 } else {
278
279 PlexusConfiguration httpConfiguration = config.getChild("httpConfiguration", false);
280 if (httpConfiguration != null) {
281 PlexusConfiguration httpConfigurationAll = httpConfiguration.getChild("all", false);
282 if (httpConfigurationAll != null) {
283 connectTimeoutXml = httpConfigurationAll.getChild("connectionTimeout", false);
284 if (connectTimeoutXml != null) {
285 connectTimeout = Integer.parseInt(connectTimeoutXml.getValue());
286 logger.warn("Settings for server " + server.getId() + " uses legacy format");
287 }
288 }
289 }
290 }
291
292 PlexusConfiguration requestTimeoutXml = config.getChild("requestTimeout", false);
293 if (requestTimeoutXml != null) {
294 requestTimeout = Integer.parseInt(requestTimeoutXml.getValue());
295 } else {
296
297 PlexusConfiguration httpConfiguration = config.getChild("httpConfiguration", false);
298 if (httpConfiguration != null) {
299 PlexusConfiguration httpConfigurationAll = httpConfiguration.getChild("all", false);
300 if (httpConfigurationAll != null) {
301 requestTimeoutXml = httpConfigurationAll.getChild("readTimeout", false);
302 if (requestTimeoutXml != null) {
303 requestTimeout = Integer.parseInt(requestTimeoutXml.getValue());
304 logger.warn("Settings for server " + server.getId() + " uses legacy format");
305 }
306 }
307 }
308 }
309
310
311 if (headers != null) {
312 configProps.put(ConfigurationProperties.HTTP_HEADERS + "." + server.getId(), headers);
313 }
314
315 if (connectTimeout != null) {
316 configProps.put(ConfigurationProperties.CONNECT_TIMEOUT + "." + server.getId(), connectTimeout);
317 }
318
319 if (requestTimeout != null) {
320 configProps.put(ConfigurationProperties.REQUEST_TIMEOUT + "." + server.getId(), requestTimeout);
321 }
322 }
323
324 configProps.put("aether.connector.perms.fileMode." + server.getId(), server.getFilePermissions());
325 configProps.put("aether.connector.perms.dirMode." + server.getId(), server.getDirectoryPermissions());
326 }
327 session.setAuthenticationSelector(authSelector);
328
329 Object transport = configProps.getOrDefault(MAVEN_RESOLVER_TRANSPORT_KEY, MAVEN_RESOLVER_TRANSPORT_DEFAULT);
330 if (MAVEN_RESOLVER_TRANSPORT_DEFAULT.equals(transport)) {
331
332 } else if (MAVEN_RESOLVER_TRANSPORT_NATIVE.equals(transport)) {
333
334 configProps.put(NATIVE_FILE_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
335 configProps.put(NATIVE_HTTP_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
336 } else if (MAVEN_RESOLVER_TRANSPORT_WAGON.equals(transport)) {
337
338 configProps.put(WAGON_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
339 } else if (!MAVEN_RESOLVER_TRANSPORT_AUTO.equals(transport)) {
340 throw new IllegalArgumentException("Unknown resolver transport '" + transport
341 + "'. Supported transports are: " + MAVEN_RESOLVER_TRANSPORT_WAGON + ", "
342 + MAVEN_RESOLVER_TRANSPORT_NATIVE + ", " + MAVEN_RESOLVER_TRANSPORT_AUTO);
343 }
344
345 session.setUserProperties(request.getUserProperties());
346 session.setSystemProperties(request.getSystemProperties());
347 session.setConfigProperties(configProps);
348
349 session.setTransferListener(request.getTransferListener());
350
351 session.setRepositoryListener(eventSpyDispatcher.chainListener(new LoggingRepositoryListener(logger)));
352
353 session.setIgnoreArtifactDescriptorRepositories(request.isIgnoreTransitiveRepositories());
354
355 boolean recordReverseTree = ConfigUtils.getBoolean(session, false, MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE);
356 if (recordReverseTree) {
357 session.setRepositoryListener(new ChainedRepositoryListener(
358 session.getRepositoryListener(), new ReverseTreeRepositoryListener()));
359 }
360
361 mavenRepositorySystem.injectMirror(request.getRemoteRepositories(), request.getMirrors());
362 mavenRepositorySystem.injectProxy(session, request.getRemoteRepositories());
363 mavenRepositorySystem.injectAuthentication(session, request.getRemoteRepositories());
364
365 mavenRepositorySystem.injectMirror(request.getPluginArtifactRepositories(), request.getMirrors());
366 mavenRepositorySystem.injectProxy(session, request.getPluginArtifactRepositories());
367 mavenRepositorySystem.injectAuthentication(session, request.getPluginArtifactRepositories());
368
369 setUpLocalRepositoryManager(request, session);
370
371 return session;
372 }
373
374 private void setUpLocalRepositoryManager(MavenExecutionRequest request, DefaultRepositorySystemSession session) {
375 List<String> paths = new ArrayList<>();
376 String localRepoHead = ConfigUtils.getString(session, null, MAVEN_REPO_LOCAL_HEAD);
377 if (localRepoHead != null) {
378 Arrays.stream(localRepoHead.split(","))
379 .filter(p -> p != null && !p.trim().isEmpty())
380 .map(this::resolve)
381 .forEach(paths::add);
382 }
383
384 paths.add(request.getLocalRepository().getBasedir());
385
386 String localRepoTail = ConfigUtils.getString(session, null, MAVEN_REPO_LOCAL_TAIL);
387 if (localRepoTail != null) {
388 Arrays.stream(localRepoTail.split(","))
389 .filter(p -> p != null && !p.trim().isEmpty())
390 .map(this::resolve)
391 .forEach(paths::add);
392 }
393
394 LocalRepository localRepo = new LocalRepository(paths.remove(0));
395 LocalRepositoryManager lrm = repoSystem.newLocalRepositoryManager(session, localRepo);
396
397 if (paths.isEmpty()) {
398
399 session.setLocalRepositoryManager(lrm);
400 } else {
401 List<LocalRepositoryManager> tail = new ArrayList<>();
402 for (String path : paths) {
403 tail.add(repoSystem.newLocalRepositoryManager(session, new LocalRepository(path)));
404 }
405 boolean ignoreTailAvailability =
406 ConfigUtils.getBoolean(session, true, MAVEN_REPO_LOCAL_TAIL_IGNORE_AVAILABILITY);
407
408 session.setLocalRepositoryManager(new ChainedLocalRepositoryManager(lrm, tail, ignoreTailAvailability));
409 }
410 }
411
412 private String resolve(String string) {
413 if (string.startsWith("~/") || string.startsWith("~\\")) {
414
415 return Paths.get(System.getProperty("user.home"))
416 .resolve(string.substring(2))
417 .normalize()
418 .toAbsolutePath()
419 .toString();
420 } else {
421
422 return Paths.get(string).normalize().toAbsolutePath().toString();
423 }
424 }
425
426 private Map<?, ?> getPropertiesFromRequestedProfiles(MavenExecutionRequest request) {
427
428 List<String> activeProfileId = request.getActiveProfiles();
429
430 return request.getProfiles().stream()
431 .filter(profile -> activeProfileId.contains(profile.getId()))
432 .map(ModelBase::getProperties)
433 .flatMap(properties -> properties.entrySet().stream())
434 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k1, k2) -> k2));
435 }
436
437 private String getUserAgent() {
438 String version = runtimeInformation.getMavenVersion();
439 version = version.isEmpty() ? version : "/" + version;
440 return "Apache-Maven" + version + " (Java " + System.getProperty("java.version") + "; "
441 + System.getProperty("os.name") + " " + System.getProperty("os.version") + ")";
442 }
443 }