From 9a33a50da402fc3af25ec9f91a28f745c21b9238 Mon Sep 17 00:00:00 2001 From: jycr Date: Mon, 27 May 2019 23:53:26 +0200 Subject: [PATCH] fix: #2470 Use mirror to download dependencies if applicable --- .../resolver/maven/MavenRepoInitializer.java | 48 ++++-- .../maven/ProxyAwareMirrorSelector.java | 73 +++++++++ .../maven/test/MavenRepoInitializerTest.java | 139 ++++++++++++++++++ 3 files changed, 248 insertions(+), 12 deletions(-) create mode 100644 independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/resolver/maven/ProxyAwareMirrorSelector.java create mode 100644 independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/maven/test/MavenRepoInitializerTest.java diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenRepoInitializer.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenRepoInitializer.java index 4fba78c1eb2f5..92340a440da7c 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenRepoInitializer.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenRepoInitializer.java @@ -55,6 +55,7 @@ import org.eclipse.aether.repository.Authentication; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.ProxySelector; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.repository.RepositoryPolicy; import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; @@ -68,8 +69,9 @@ import io.quarkus.bootstrap.resolver.AppModelResolverException; import io.quarkus.bootstrap.util.PropertyUtils; +import static java.util.stream.Collectors.toList; + /** - * * @author Alexey Loubyansky */ public class MavenRepoInitializer { @@ -216,7 +218,7 @@ public static DefaultRepositorySystemSession newSession(RepositorySystem system, } public static List getRemoteRepos() throws AppModelResolverException { - if(remoteRepos != null) { + if (remoteRepos != null) { return remoteRepos; } return remoteRepos = Collections.unmodifiableList(getRemoteRepos(getSettings())); @@ -225,8 +227,6 @@ public static List getRemoteRepos() throws AppModelResolverExc public static List getRemoteRepos(Settings settings) throws AppModelResolverException { final List remotes = new ArrayList<>(); - final Proxy proxy = toAetherProxy(settings.getActiveProxy()); - final int profilesTotal = settings.getProfiles().size(); if(profilesTotal > 0) { List modelProfiles = new ArrayList<>(profilesTotal); @@ -276,7 +276,7 @@ public void add(ModelProblemCollectorRequest req) { } }); for(org.apache.maven.model.Profile modelProfile : modelProfiles) { - addProfileRepos(modelProfile, remotes, proxy); + addProfileRepos(modelProfile, remotes); } } @@ -286,7 +286,7 @@ public void add(ModelProblemCollectorRequest req) { for (String profileName : activeProfiles) { final Profile profile = getProfile(profileName, settings); if(profile != null) { - addProfileRepos(profile, remotes, proxy); + addProfileRepos(profile, remotes); } } } @@ -295,15 +295,41 @@ public void add(ModelProblemCollectorRequest req) { remotes.add(new RemoteRepository.Builder(DEFAULT_REMOTE_REPO_ID, "default", DEFAULT_REMOTE_REPO_URL) .setReleasePolicy(new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_DAILY, RepositoryPolicy.CHECKSUM_POLICY_WARN)) .setSnapshotPolicy(new RepositoryPolicy(false, RepositoryPolicy.UPDATE_POLICY_DAILY, RepositoryPolicy.CHECKSUM_POLICY_WARN)) - .setProxy(proxy) .build()); } + final ProxyAwareMirrorSelector proxyAwareMirrorSelector = new ProxyAwareMirrorSelector( + settings.getMirrors(), + getProxySelector(settings) + ); + return remotes.stream() + .map(proxyAwareMirrorSelector::getMirror) + // remove duplicates + .distinct() + .collect(toList()); + } - return remotes; + private static ProxySelector getProxySelector(Settings settings) { + final org.apache.maven.settings.Proxy settingsProxy = settings.getActiveProxy(); + if (settingsProxy == null) { + return null; + } + return new DefaultProxySelector().add( + new Proxy( + settingsProxy.getProtocol(), + settingsProxy.getHost(), + settingsProxy.getPort(), + settingsProxy.getUsername() == null ? null : new AuthenticationBuilder() + .addUsername(settingsProxy.getUsername()) + .addPassword(settingsProxy.getPassword()) + .build() + ), + settingsProxy.getNonProxyHosts() + ); } /** * Convert a {@link org.apache.maven.settings.Proxy} to a {@link Proxy}. + * * @param proxy Maven proxy settings, may be {@code null}. * @return Aether repository proxy or {@code null} if given {@link org.apache.maven.settings.Proxy} is {@code null}. */ @@ -339,7 +365,7 @@ private static void unrecognizedProfile(String name, boolean activate) { log.warn(buf.toString()); } - private static void addProfileRepos(final org.apache.maven.model.Profile profile, final List all, final Proxy proxy) { + private static void addProfileRepos(final org.apache.maven.model.Profile profile, final List all) { final List repositories = profile.getRepositories(); for (org.apache.maven.model.Repository repo : repositories) { final RemoteRepository.Builder repoBuilder = new RemoteRepository.Builder(repo.getId(), repo.getLayout(), repo.getUrl()); @@ -351,12 +377,11 @@ private static void addProfileRepos(final org.apache.maven.model.Profile profile if (policy != null) { repoBuilder.setSnapshotPolicy(toAetherRepoPolicy(policy)); } - repoBuilder.setProxy(proxy); all.add(repoBuilder.build()); } } - private static void addProfileRepos(final Profile profile, final List all, final Proxy proxy) { + private static void addProfileRepos(final Profile profile, final List all) { final List repositories = profile.getRepositories(); for (Repository repo : repositories) { final RemoteRepository.Builder repoBuilder = new RemoteRepository.Builder(repo.getId(), repo.getLayout(), repo.getUrl()); @@ -368,7 +393,6 @@ private static void addProfileRepos(final Profile profile, final List mirrors) { + DefaultMirrorSelector ms = new DefaultMirrorSelector(); + if (mirrors != null) { + for (Mirror m : mirrors) { + ms.add( + m.getId(), + m.getUrl(), + m.getLayout(), + false, + m.getMirrorOf(), + m.getMirrorOfLayouts() + ); + } + } + return ms; + } + + ProxyAwareMirrorSelector(List mirrors, ProxySelector proxySelector) { + this.wrappedMirrorSelector = createMirrorSelector(mirrors); + this.proxySelector = proxySelector == null ? NULL_PROXY_SELECTOR : proxySelector; + } + + /** + * Replace repo with it's mirror if applicable, and ensure proxy is set-up if needed. + * + * @param remoteRepository Remote repository to enhance + * @return Mirror or RemoteRepository (if no mirror is applicable) but add proxy on this mirror or RemoteRepository if needed + */ + @Override + public RemoteRepository getMirror(final RemoteRepository remoteRepository) { + RemoteRepository remoteRepositoryResult = wrappedMirrorSelector.getMirror(remoteRepository); + if (remoteRepositoryResult == null) { + // No Mirror, take remoteRepository it-self + remoteRepositoryResult = remoteRepository; + } + + final Proxy proxy = proxySelector.getProxy(remoteRepositoryResult); + if (proxy == null) { + // No Proxy, return remoteRepositoryMirror + return remoteRepositoryResult; + } + + // Available proxy, use it + return new RemoteRepository.Builder(remoteRepositoryResult) + .setProxy(proxy) + .build(); + } +} \ No newline at end of file diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/maven/test/MavenRepoInitializerTest.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/maven/test/MavenRepoInitializerTest.java new file mode 100644 index 0000000000000..ef21df18c538e --- /dev/null +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/maven/test/MavenRepoInitializerTest.java @@ -0,0 +1,139 @@ +package io.quarkus.bootstrap.resolver.maven.test; + +import io.quarkus.bootstrap.resolver.AppModelResolverException; +import io.quarkus.bootstrap.resolver.maven.MavenRepoInitializer; +import org.apache.maven.settings.*; +import org.eclipse.aether.repository.RemoteRepository; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.List; + +import static org.eclipse.aether.repository.RepositoryPolicy.CHECKSUM_POLICY_WARN; +import static org.eclipse.aether.repository.RepositoryPolicy.UPDATE_POLICY_DAILY; +import static org.junit.Assert.*; + +public class MavenRepoInitializerTest { + private static Mirror mirrorA; + private static Proxy localProxy; + private static Settings baseSettings; + + @BeforeClass + public static void init() { + baseSettings = new Settings(); + + baseSettings.setInteractiveMode(true); + baseSettings.setUsePluginRegistry(false); + baseSettings.setOffline(false); + + final Profile profile = new Profile(); + profile.setId("foo-profile"); + + final RepositoryPolicy releasesPolicy = new RepositoryPolicy(); + releasesPolicy.setEnabled(true); + releasesPolicy.setUpdatePolicy(null); + releasesPolicy.setChecksumPolicy(CHECKSUM_POLICY_WARN); + + final RepositoryPolicy snapshotsPolicy = new RepositoryPolicy(); + snapshotsPolicy.setEnabled(true); + snapshotsPolicy.setUpdatePolicy(UPDATE_POLICY_DAILY); + snapshotsPolicy.setChecksumPolicy(CHECKSUM_POLICY_WARN); + + final RepositoryPolicy noSnapshotsPolicy = new RepositoryPolicy(); + noSnapshotsPolicy.setEnabled(false); + + final Repository customRepository = new Repository(); + customRepository.setId("custom-repo"); + customRepository.setUrl("https://foo.repo/artifact/content/groups/foo/"); + customRepository.setReleases(releasesPolicy); + customRepository.setSnapshots(snapshotsPolicy); + profile.addRepository(customRepository); + + final Repository jbossRepository = new Repository(); + jbossRepository.setId("jboss-public-repository"); + jbossRepository.setUrl("https://repository.jboss.org/nexus/content/repositories/releases/"); + jbossRepository.setReleases(releasesPolicy); + jbossRepository.setSnapshots(noSnapshotsPolicy); + profile.addRepository(jbossRepository); + + final Repository springRepository = new Repository(); + springRepository.setId("spring-public-repository"); + springRepository.setUrl("http://repo.spring.io/libs-release/"); + springRepository.setReleases(releasesPolicy); + springRepository.setSnapshots(noSnapshotsPolicy); + profile.addRepository(springRepository); + + baseSettings.addProfile(profile); + baseSettings.addActiveProfile("foo-profile"); + + localProxy = new Proxy(); + localProxy.setActive(true); + localProxy.setProtocol("http"); + localProxy.setUsername(null); + localProxy.setPassword(null); + localProxy.setPort(8888); + localProxy.setHost("localhost"); + localProxy.setNonProxyHosts("localhost"); + localProxy.setId("local-proxy-http"); + + mirrorA = new Mirror(); + mirrorA.setMirrorOf("central,jboss-public-repository,spring-public-repository"); + mirrorA.setUrl("https://mirror.com/artifact/content/groups/public/"); + mirrorA.setId("mirror-A"); + } + + @Test + public void getRemoteRepoFromSettingsWithNeitherProxyNorMirror() throws AppModelResolverException { + final Settings settings = baseSettings.clone(); + + List repos = MavenRepoInitializer.getRemoteRepos(settings); + assertEquals(4, repos.size()); + + assertEquals("custom-repo", repos.get(0).getId()); + assertNull(repos.get(0).getProxy()); + assertTrue(repos.get(0).getMirroredRepositories().isEmpty()); + + final RemoteRepository centralRepo = repos.get(repos.size() - 1); + assertEquals("central", centralRepo.getId()); + assertNull(centralRepo.getProxy()); + assertTrue(centralRepo.getMirroredRepositories().isEmpty()); + } + + @Test + public void getRemoteRepoFromSettingsWithProxyButWithoutMirror() throws AppModelResolverException { + final Settings settings = baseSettings.clone(); + settings.addProxy(localProxy); + + List repos = MavenRepoInitializer.getRemoteRepos(settings); + assertEquals(4, repos.size()); + + assertEquals("custom-repo", repos.get(0).getId()); + assertNotNull(repos.get(0).getProxy()); + assertNotNull(repos.get(0).getMirroredRepositories()); + + final RemoteRepository centralRepo = repos.get(repos.size() - 1); + assertEquals("central repo must be added as default repository", "central", centralRepo.getId()); + assertNotNull(centralRepo.getProxy()); + assertTrue(centralRepo.getMirroredRepositories().isEmpty()); + } + + @Test + public void getRemoteRepoFromSettingsWithProxyAndMirror() throws AppModelResolverException { + final Settings settings = baseSettings.clone(); + settings.addProxy(localProxy); + settings.addMirror(mirrorA); + + List repos = MavenRepoInitializer.getRemoteRepos(settings); + assertEquals(4, repos.size()); + + assertEquals("custom-repo", repos.get(0).getId()); + assertNotNull(repos.get(0).getProxy()); + assertNotNull(repos.get(0).getMirroredRepositories()); + + final RemoteRepository centralRepo = repos.get(repos.size() - 1); + assertEquals("Central repo must be substitute by mirror", "mirror-A", centralRepo.getId()); + assertNotNull(centralRepo.getProxy()); + assertEquals(1, centralRepo.getMirroredRepositories().size()); + assertEquals("central", centralRepo.getMirroredRepositories().get(0).getId()); + } +} \ No newline at end of file