Browse Source
Previously, Aether's configuration was largely hard-coded making it
impossible to configure a mirror, provide credentials for accessing
a repository, etc.
This commit adds support for configuring Aether via Maven's
settings.xml file. The support is optional and must be enabled by
grabbing spring-boot-maven-settings in an init script. The Aether
instance that's used when running the application will then be
configured using settings.xml. The settings file is expected to be
found in ${user.home}/.m2/settings.xml.
The configuration of the following items is currently supported:
- Offline
- Proxies
- Mirrors
- Server authentication
- Local repository location
If the support is not enabled, settings.xml does not exist, or
settings.xml does not configure certain things then sensible defaults
are applied.
pull/208/head
13 changed files with 437 additions and 84 deletions
@ -0,0 +1,97 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2013 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.boot.cli.compiler.grape; |
||||||
|
|
||||||
|
import groovy.lang.GroovyClassLoader; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.ServiceLoader; |
||||||
|
|
||||||
|
import org.apache.maven.repository.internal.MavenRepositorySystemUtils; |
||||||
|
import org.eclipse.aether.DefaultRepositorySystemSession; |
||||||
|
import org.eclipse.aether.RepositorySystem; |
||||||
|
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; |
||||||
|
import org.eclipse.aether.impl.DefaultServiceLocator; |
||||||
|
import org.eclipse.aether.internal.impl.DefaultRepositorySystem; |
||||||
|
import org.eclipse.aether.repository.RemoteRepository; |
||||||
|
import org.eclipse.aether.repository.RepositoryPolicy; |
||||||
|
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; |
||||||
|
import org.eclipse.aether.spi.connector.transport.TransporterFactory; |
||||||
|
import org.eclipse.aether.spi.locator.ServiceLocator; |
||||||
|
import org.eclipse.aether.transport.file.FileTransporterFactory; |
||||||
|
import org.eclipse.aether.transport.http.HttpTransporterFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* Utility class to create a pre-configured {@link AetherGrapeEngine}. |
||||||
|
* |
||||||
|
* @author Andy Wilkinson |
||||||
|
*/ |
||||||
|
public abstract class AetherGrapeEngineFactory { |
||||||
|
|
||||||
|
public static AetherGrapeEngine create(GroovyClassLoader classLoader, |
||||||
|
List<RepositoryConfiguration> repositoryConfigurations) { |
||||||
|
|
||||||
|
RepositorySystem repositorySystem = createServiceLocator().getService( |
||||||
|
RepositorySystem.class); |
||||||
|
|
||||||
|
DefaultRepositorySystemSession repositorySystemSession = MavenRepositorySystemUtils |
||||||
|
.newSession(); |
||||||
|
|
||||||
|
ServiceLoader<RepositorySystemSessionAutoConfiguration> autoConfigurations = ServiceLoader |
||||||
|
.load(RepositorySystemSessionAutoConfiguration.class); |
||||||
|
|
||||||
|
for (RepositorySystemSessionAutoConfiguration autoConfiguration : autoConfigurations) { |
||||||
|
autoConfiguration.apply(repositorySystemSession, repositorySystem); |
||||||
|
} |
||||||
|
|
||||||
|
new DefaultRepositorySystemSessionAutoConfiguration().apply( |
||||||
|
repositorySystemSession, repositorySystem); |
||||||
|
|
||||||
|
return new AetherGrapeEngine(classLoader, repositorySystem, |
||||||
|
repositorySystemSession, createRepositories(repositoryConfigurations)); |
||||||
|
} |
||||||
|
|
||||||
|
private static ServiceLocator createServiceLocator() { |
||||||
|
DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); |
||||||
|
locator.addService(RepositorySystem.class, DefaultRepositorySystem.class); |
||||||
|
locator.addService(RepositoryConnectorFactory.class, |
||||||
|
BasicRepositoryConnectorFactory.class); |
||||||
|
locator.addService(TransporterFactory.class, HttpTransporterFactory.class); |
||||||
|
locator.addService(TransporterFactory.class, FileTransporterFactory.class); |
||||||
|
return locator; |
||||||
|
} |
||||||
|
|
||||||
|
private static List<RemoteRepository> createRepositories( |
||||||
|
List<RepositoryConfiguration> repositoryConfigurations) { |
||||||
|
List<RemoteRepository> repositories = new ArrayList<RemoteRepository>( |
||||||
|
repositoryConfigurations.size()); |
||||||
|
for (RepositoryConfiguration repositoryConfiguration : repositoryConfigurations) { |
||||||
|
RemoteRepository.Builder builder = new RemoteRepository.Builder( |
||||||
|
repositoryConfiguration.getName(), "default", repositoryConfiguration |
||||||
|
.getUri().toASCIIString()); |
||||||
|
|
||||||
|
if (!repositoryConfiguration.getSnapshotsEnabled()) { |
||||||
|
builder.setSnapshotPolicy(new RepositoryPolicy(false, |
||||||
|
RepositoryPolicy.UPDATE_POLICY_NEVER, |
||||||
|
RepositoryPolicy.CHECKSUM_POLICY_IGNORE)); |
||||||
|
} |
||||||
|
repositories.add(builder.build()); |
||||||
|
} |
||||||
|
return repositories; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,71 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2013 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.boot.cli.compiler.grape; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
|
||||||
|
import org.eclipse.aether.DefaultRepositorySystemSession; |
||||||
|
import org.eclipse.aether.RepositorySystem; |
||||||
|
import org.eclipse.aether.repository.LocalRepository; |
||||||
|
import org.eclipse.aether.repository.LocalRepositoryManager; |
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* A {@link RepositorySystemSessionAutoConfiguration} that, in the absence of any |
||||||
|
* configuration, applies sensible defaults. |
||||||
|
* |
||||||
|
* @author Andy Wilkinson |
||||||
|
*/ |
||||||
|
public class DefaultRepositorySystemSessionAutoConfiguration implements |
||||||
|
RepositorySystemSessionAutoConfiguration { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void apply(DefaultRepositorySystemSession session, |
||||||
|
RepositorySystem repositorySystem) { |
||||||
|
|
||||||
|
if (session.getLocalRepositoryManager() == null) { |
||||||
|
LocalRepository localRepository = new LocalRepository(getM2RepoDirectory()); |
||||||
|
LocalRepositoryManager localRepositoryManager = repositorySystem |
||||||
|
.newLocalRepositoryManager(session, localRepository); |
||||||
|
session.setLocalRepositoryManager(localRepositoryManager); |
||||||
|
} |
||||||
|
|
||||||
|
if (session.getProxySelector() == null) { |
||||||
|
session.setProxySelector(new JreProxySelector()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private File getM2RepoDirectory() { |
||||||
|
return new File(getM2HomeDirectory(), "repository"); |
||||||
|
} |
||||||
|
|
||||||
|
private File getM2HomeDirectory() { |
||||||
|
String grapeRoot = System.getProperty("grape.root"); |
||||||
|
if (StringUtils.hasLength(grapeRoot)) { |
||||||
|
return new File(grapeRoot); |
||||||
|
} |
||||||
|
return getDefaultM2HomeDirectory(); |
||||||
|
} |
||||||
|
|
||||||
|
private File getDefaultM2HomeDirectory() { |
||||||
|
String mavenRoot = System.getProperty("maven.home"); |
||||||
|
if (StringUtils.hasLength(mavenRoot)) { |
||||||
|
return new File(mavenRoot); |
||||||
|
} |
||||||
|
return new File(System.getProperty("user.home"), ".m2"); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2013 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.boot.cli.compiler.grape; |
||||||
|
|
||||||
|
import org.eclipse.aether.DefaultRepositorySystemSession; |
||||||
|
import org.eclipse.aether.RepositorySystem; |
||||||
|
|
||||||
|
/** |
||||||
|
* Strategy that can be used to apply some auto-configuration during the installation of |
||||||
|
* an {@link AetherGrapeEngine}. |
||||||
|
* |
||||||
|
* @author Andy Wilkinson |
||||||
|
*/ |
||||||
|
public interface RepositorySystemSessionAutoConfiguration { |
||||||
|
|
||||||
|
/** |
||||||
|
* Apply the configuration |
||||||
|
*/ |
||||||
|
void apply(DefaultRepositorySystemSession session, RepositorySystem repositorySystem); |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
<parent> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-parent</artifactId> |
||||||
|
<version>0.5.0.BUILD-SNAPSHOT</version> |
||||||
|
<relativePath>../spring-boot-parent</relativePath> |
||||||
|
</parent> |
||||||
|
<artifactId>spring-boot-maven-settings</artifactId> |
||||||
|
<packaging>jar</packaging> |
||||||
|
<dependencies> |
||||||
|
<!-- Compile --> |
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.maven</groupId> |
||||||
|
<artifactId>maven-settings-builder</artifactId> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.eclipse.aether</groupId> |
||||||
|
<artifactId>aether-api</artifactId> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.eclipse.aether</groupId> |
||||||
|
<artifactId>aether-util</artifactId> |
||||||
|
</dependency> |
||||||
|
<!-- Provided --> |
||||||
|
<dependency> |
||||||
|
<groupId>${project.groupId}</groupId> |
||||||
|
<artifactId>spring-boot-cli</artifactId> |
||||||
|
<version>${project.version}</version> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
</project> |
||||||
@ -0,0 +1,113 @@ |
|||||||
|
package org.springframework.boot.maven.settings; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
|
||||||
|
import org.apache.maven.settings.Mirror; |
||||||
|
import org.apache.maven.settings.Proxy; |
||||||
|
import org.apache.maven.settings.Server; |
||||||
|
import org.apache.maven.settings.Settings; |
||||||
|
import org.apache.maven.settings.building.DefaultSettingsBuilderFactory; |
||||||
|
import org.apache.maven.settings.building.DefaultSettingsBuildingRequest; |
||||||
|
import org.apache.maven.settings.building.SettingsBuildingException; |
||||||
|
import org.apache.maven.settings.building.SettingsBuildingRequest; |
||||||
|
import org.apache.maven.settings.building.SettingsBuildingResult; |
||||||
|
import org.eclipse.aether.DefaultRepositorySystemSession; |
||||||
|
import org.eclipse.aether.RepositorySystem; |
||||||
|
import org.eclipse.aether.repository.Authentication; |
||||||
|
import org.eclipse.aether.repository.AuthenticationSelector; |
||||||
|
import org.eclipse.aether.repository.LocalRepository; |
||||||
|
import org.eclipse.aether.repository.MirrorSelector; |
||||||
|
import org.eclipse.aether.repository.ProxySelector; |
||||||
|
import org.eclipse.aether.util.repository.AuthenticationBuilder; |
||||||
|
import org.eclipse.aether.util.repository.ConservativeAuthenticationSelector; |
||||||
|
import org.eclipse.aether.util.repository.DefaultAuthenticationSelector; |
||||||
|
import org.eclipse.aether.util.repository.DefaultMirrorSelector; |
||||||
|
import org.eclipse.aether.util.repository.DefaultProxySelector; |
||||||
|
import org.springframework.boot.cli.compiler.grape.RepositorySystemSessionAutoConfiguration; |
||||||
|
|
||||||
|
/** |
||||||
|
* Auto-configuration for a RepositorySystemSession that uses Maven's settings.xml to |
||||||
|
* determine the configuration settings |
||||||
|
* |
||||||
|
* @author Andy Wilkinson |
||||||
|
*/ |
||||||
|
public class SettingsXmlRepositorySystemSessionAutoConfiguration implements |
||||||
|
RepositorySystemSessionAutoConfiguration { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void apply(DefaultRepositorySystemSession session, |
||||||
|
RepositorySystem repositorySystem) { |
||||||
|
Settings settings = loadSettings(); |
||||||
|
|
||||||
|
session.setOffline(settings.isOffline()); |
||||||
|
session.setMirrorSelector(createMirrorSelector(settings)); |
||||||
|
session.setAuthenticationSelector(createAuthenticationSelector(settings)); |
||||||
|
session.setProxySelector(createProxySelector(settings)); |
||||||
|
|
||||||
|
String localRepository = settings.getLocalRepository(); |
||||||
|
|
||||||
|
if (localRepository != null) { |
||||||
|
session.setLocalRepositoryManager(repositorySystem.newLocalRepositoryManager( |
||||||
|
session, new LocalRepository(localRepository))); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Settings loadSettings() { |
||||||
|
SettingsBuildingRequest request = new DefaultSettingsBuildingRequest(); |
||||||
|
|
||||||
|
File userSettingsFile = new File(System.getProperty("user.home"), |
||||||
|
".m2/settings.xml"); |
||||||
|
|
||||||
|
request.setUserSettingsFile(userSettingsFile); |
||||||
|
|
||||||
|
SettingsBuildingResult result; |
||||||
|
try { |
||||||
|
result = new DefaultSettingsBuilderFactory().newInstance().build(request); |
||||||
|
} |
||||||
|
catch (SettingsBuildingException e) { |
||||||
|
throw new IllegalStateException("Failed to build settings from " |
||||||
|
+ userSettingsFile, e); |
||||||
|
} |
||||||
|
|
||||||
|
return result.getEffectiveSettings(); |
||||||
|
} |
||||||
|
|
||||||
|
private MirrorSelector createMirrorSelector(Settings settings) { |
||||||
|
DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector(); |
||||||
|
for (Mirror mirror : settings.getMirrors()) { |
||||||
|
mirrorSelector.add(mirror.getId(), mirror.getUrl(), mirror.getLayout(), |
||||||
|
false, mirror.getMirrorOf(), mirror.getMirrorOfLayouts()); |
||||||
|
} |
||||||
|
return mirrorSelector; |
||||||
|
} |
||||||
|
|
||||||
|
private AuthenticationSelector createAuthenticationSelector(Settings settings) { |
||||||
|
DefaultAuthenticationSelector authenticationSelector = new DefaultAuthenticationSelector(); |
||||||
|
|
||||||
|
for (Server server : settings.getServers()) { |
||||||
|
AuthenticationBuilder auth = new AuthenticationBuilder(); |
||||||
|
auth.addUsername(server.getUsername()).addPassword(server.getPassword()); |
||||||
|
auth.addPrivateKey(server.getPrivateKey(), server.getPassphrase()); |
||||||
|
authenticationSelector.add(server.getId(), auth.build()); |
||||||
|
} |
||||||
|
|
||||||
|
return new ConservativeAuthenticationSelector(authenticationSelector); |
||||||
|
} |
||||||
|
|
||||||
|
private ProxySelector createProxySelector(Settings settings) { |
||||||
|
DefaultProxySelector proxySelector = new DefaultProxySelector(); |
||||||
|
|
||||||
|
for (Proxy proxy : settings.getProxies()) { |
||||||
|
Authentication authentication = new AuthenticationBuilder() |
||||||
|
.addUsername(proxy.getUsername()).addPassword(proxy.getPassword()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
proxySelector.add( |
||||||
|
new org.eclipse.aether.repository.Proxy(proxy.getProtocol(), proxy |
||||||
|
.getHost(), proxy.getPort(), authentication), proxy |
||||||
|
.getNonProxyHosts()); |
||||||
|
} |
||||||
|
|
||||||
|
return proxySelector; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1 @@ |
|||||||
|
org.springframework.boot.maven.settings.SettingsXmlRepositorySystemSessionAutoConfiguration |
||||||
@ -0,0 +1,39 @@ |
|||||||
|
package org.springframework.boot.maven.settings; |
||||||
|
|
||||||
|
import org.apache.maven.repository.internal.MavenRepositorySystemUtils; |
||||||
|
import org.apache.maven.settings.building.SettingsBuildingException; |
||||||
|
import org.eclipse.aether.DefaultRepositorySystemSession; |
||||||
|
import org.eclipse.aether.RepositorySystem; |
||||||
|
import org.eclipse.aether.repository.LocalRepositoryManager; |
||||||
|
import org.junit.Rule; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.rules.ExpectedException; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.mockito.Mock; |
||||||
|
import org.mockito.runners.MockitoJUnitRunner; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull; |
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class) |
||||||
|
public class SettingsXmlRepositorySystemSessionAutoConfigurationTests { |
||||||
|
|
||||||
|
@Rule |
||||||
|
public ExpectedException thrown = ExpectedException.none(); |
||||||
|
|
||||||
|
@Mock |
||||||
|
private RepositorySystem repositorySystem; |
||||||
|
|
||||||
|
@Mock |
||||||
|
LocalRepositoryManager localRepositoryManager; |
||||||
|
|
||||||
|
@Test |
||||||
|
public void basicSessionCustomization() throws SettingsBuildingException { |
||||||
|
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); |
||||||
|
|
||||||
|
new SettingsXmlRepositorySystemSessionAutoConfiguration().apply(session, |
||||||
|
this.repositorySystem); |
||||||
|
|
||||||
|
assertNotNull(session.getMirrorSelector()); |
||||||
|
assertNotNull(session.getProxySelector()); |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue