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