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