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