Fully honour local repository location configured in settings.xml

Previously, DefaultRepositorySystemSessionAutoConfiguration would
read the local repository configuration from settings.xml, but did
not perform any property interpolation. This would leave placeholders
such as ${user.home} as-is and result in the use of the wrong
location. To address this, the code that reads settings.xml has been
updated to provide the current System properties as a property
interpolation source.

RepositoryConfigurationFactory configures the local repository as a
"remote" repository when the local repository location has been
overridden. This allows spring grab to copy dependencies from the
local repository into the grab output location (configured via the
grape.root system property) rather than having to download them again.
This logic did not consider the customization of the local repository
location via settings.xml so the dependencies would be downloaded again.
To address this, RepositoryConfigurationFactory has been updated to
attempt to use the location configured in settings.xml, before falling
back to the default location.

The logic that reads settings.xml has deliberately been duplicated. It
could have been extracted into a separate class, but this is only a
temporary measure until gh-3275 is tackled. Duplication was deemed
preferable to adding a new public class in 1.2.x that we’d then want to
remove in 1.3.

Closes gh-3274
This commit is contained in:
Andy Wilkinson 2015-06-18 10:59:39 +01:00
parent bbb0b7a80b
commit 5e743fb299
7 changed files with 252 additions and 14 deletions

View File

@ -21,6 +21,11 @@ import java.net.URI;
import java.util.ArrayList;
import java.util.List;
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.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
import org.springframework.util.StringUtils;
@ -66,12 +71,35 @@ public final class RepositoryConfigurationFactory {
public static void addDefaultCacheAsRespository(
List<RepositoryConfiguration> repositoryConfiguration) {
RepositoryConfiguration repository = new RepositoryConfiguration("local",
new File(getM2HomeDirectory(), "repository").toURI(), true);
getLocalRepositoryDirectory().toURI(), true);
if (!repositoryConfiguration.contains(repository)) {
repositoryConfiguration.add(0, repository);
}
}
private static File getLocalRepositoryDirectory() {
String localRepository = loadSettings().getLocalRepository();
if (StringUtils.hasText(localRepository)) {
return new File(localRepository);
}
return new File(getM2HomeDirectory(), "repository");
}
private static Settings loadSettings() {
File settingsFile = new File(System.getProperty("user.home"), ".m2/settings.xml");
SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
request.setUserSettingsFile(settingsFile);
request.setSystemProperties(System.getProperties());
try {
return new DefaultSettingsBuilderFactory().newInstance().build(request)
.getEffectiveSettings();
}
catch (SettingsBuildingException ex) {
throw new IllegalStateException("Failed to build settings from "
+ settingsFile, ex);
}
}
private static File getM2HomeDirectory() {
String mavenRoot = System.getProperty("maven.home");
if (StringUtils.hasLength(mavenRoot)) {

View File

@ -57,15 +57,7 @@ public class DefaultRepositorySystemSessionAutoConfiguration implements
}
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();
return new File(getDefaultM2HomeDirectory(), "repository");
}
private File getDefaultM2HomeDirectory() {

View File

@ -0,0 +1,55 @@
/*
* Copyright 2012-2015 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;
/**
* Honours the configuration of {@code grape.root} by customizing the session's local
* repository location.
*
* @author Andy Wilkinson
* @since 1.2.5
*/
public class GrapeRootRepositorySystemSessionAutoConfiguration implements
RepositorySystemSessionAutoConfiguration {
@Override
public void apply(DefaultRepositorySystemSession session,
RepositorySystem repositorySystem) {
String grapeRoot = System.getProperty("grape.root");
if (StringUtils.hasLength(grapeRoot)) {
configureLocalRepository(session, repositorySystem, grapeRoot);
}
}
private void configureLocalRepository(DefaultRepositorySystemSession session,
RepositorySystem repositorySystem, String grapeRoot) {
File repositoryDir = new File(grapeRoot, "repository");
LocalRepository localRepository = new LocalRepository(repositoryDir);
LocalRepositoryManager localRepositoryManager = repositorySystem
.newLocalRepositoryManager(session, localRepository);
session.setLocalRepositoryManager(localRepositoryManager);
}
}

View File

@ -96,6 +96,7 @@ public class SettingsXmlRepositorySystemSessionAutoConfiguration implements
File settingsFile = new File(this.homeDir, ".m2/settings.xml");
SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
request.setUserSettingsFile(settingsFile);
request.setSystemProperties(System.getProperties());
try {
return new DefaultSettingsBuilderFactory().newInstance().build(request)
.getEffectiveSettings();

View File

@ -1 +1,2 @@
org.springframework.boot.cli.compiler.grape.SettingsXmlRepositorySystemSessionAutoConfiguration
org.springframework.boot.cli.compiler.grape.SettingsXmlRepositorySystemSessionAutoConfiguration
org.springframework.boot.cli.compiler.grape.GrapeRootRepositorySystemSessionAutoConfiguration

View File

@ -0,0 +1,122 @@
/*
* Copyright 2012-2015 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.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.LocalRepositoryManager;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link GrapeRootRepositorySystemSessionAutoConfiguration}
*
* @author Andy Wilkinson
*/
@RunWith(MockitoJUnitRunner.class)
public class GrapeRootRepositorySystemSessionAutoConfigurationTests {
private DefaultRepositorySystemSession session = MavenRepositorySystemUtils
.newSession();
@Mock
private RepositorySystem repositorySystem;
@Test
public void noLocalRepositoryWhenNoGrapeRoot() {
given(
this.repositorySystem.newLocalRepositoryManager(eq(this.session),
any(LocalRepository.class))).willAnswer(
new Answer<LocalRepositoryManager>() {
@Override
public LocalRepositoryManager answer(InvocationOnMock invocation)
throws Throwable {
LocalRepository localRepository = invocation.getArgumentAt(1,
LocalRepository.class);
return new SimpleLocalRepositoryManagerFactory()
.newInstance(
GrapeRootRepositorySystemSessionAutoConfigurationTests.this.session,
localRepository);
}
});
new GrapeRootRepositorySystemSessionAutoConfiguration().apply(this.session,
this.repositorySystem);
verify(this.repositorySystem, times(0)).newLocalRepositoryManager(
eq(this.session), any(LocalRepository.class));
assertThat(this.session.getLocalRepository(), is(nullValue()));
}
@Test
public void grapeRootConfiguresLocalRepositoryLocation() {
given(
this.repositorySystem.newLocalRepositoryManager(eq(this.session),
any(LocalRepository.class))).willAnswer(
new LocalRepositoryManagerAnswer());
System.setProperty("grape.root", "foo");
try {
new GrapeRootRepositorySystemSessionAutoConfiguration().apply(this.session,
this.repositorySystem);
}
finally {
System.clearProperty("grape.root");
}
verify(this.repositorySystem, times(1)).newLocalRepositoryManager(
eq(this.session), any(LocalRepository.class));
assertThat(this.session.getLocalRepository(), is(notNullValue()));
assertThat(this.session.getLocalRepository().getBasedir().getAbsolutePath(),
endsWith("/foo/repository"));
}
private class LocalRepositoryManagerAnswer implements Answer<LocalRepositoryManager> {
@Override
public LocalRepositoryManager answer(InvocationOnMock invocation)
throws Throwable {
LocalRepository localRepository = invocation.getArgumentAt(1,
LocalRepository.class);
return new SimpleLocalRepositoryManagerFactory().newInstance(
GrapeRootRepositorySystemSessionAutoConfigurationTests.this.session,
localRepository);
}
}
}

View File

@ -20,8 +20,10 @@ 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.internal.impl.SimpleLocalRepositoryManagerFactory;
import org.eclipse.aether.repository.Authentication;
import org.eclipse.aether.repository.AuthenticationContext;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.LocalRepositoryManager;
import org.eclipse.aether.repository.Proxy;
import org.eclipse.aether.repository.RemoteRepository;
@ -30,10 +32,17 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import static org.hamcrest.Matchers.endsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
/**
* Tests for {@link SettingsXmlRepositorySystemSessionAutoConfiguration}.
@ -49,9 +58,6 @@ public class SettingsXmlRepositorySystemSessionAutoConfigurationTests {
@Mock
private RepositorySystem repositorySystem;
@Mock
LocalRepositoryManager localRepositoryManager;
@Test
public void basicSessionCustomization() throws SettingsBuildingException {
assertSessionCustomization("src/test/resources/maven-settings/basic");
@ -62,6 +68,39 @@ public class SettingsXmlRepositorySystemSessionAutoConfigurationTests {
assertSessionCustomization("src/test/resources/maven-settings/encrypted");
}
@Test
public void propertyInterpolation() throws SettingsBuildingException {
final DefaultRepositorySystemSession session = MavenRepositorySystemUtils
.newSession();
given(
this.repositorySystem.newLocalRepositoryManager(eq(session),
any(LocalRepository.class))).willAnswer(
new Answer<LocalRepositoryManager>() {
@Override
public LocalRepositoryManager answer(InvocationOnMock invocation)
throws Throwable {
LocalRepository localRepository = invocation.getArgumentAt(1,
LocalRepository.class);
return new SimpleLocalRepositoryManagerFactory().newInstance(
session, localRepository);
}
});
System.setProperty("foo", "bar");
try {
new SettingsXmlRepositorySystemSessionAutoConfiguration(
"src/test/resources/maven-settings/property-interpolation").apply(
session, this.repositorySystem);
}
finally {
System.clearProperty("foo");
}
assertThat(session.getLocalRepository().getBasedir().getAbsolutePath(),
endsWith("/bar/repository"));
}
private void assertSessionCustomization(String userHome) {
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();