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