From 9cb66d55d1486aeb87efae964ed8dce3c81d505d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 19 Jan 2022 13:18:05 +0000 Subject: [PATCH] Refer to Maven Resolver rather than Aether Closes gh-29255 --- .../boot/cli/compiler/GroovyCompiler.java | 8 +- .../cli/compiler/grape/AetherGrapeEngine.java | 296 +--------------- .../grape/AetherGrapeEngineFactory.java | 5 +- .../grape/MavenResolverGrapeEngine.java | 331 ++++++++++++++++++ .../MavenResolverGrapeEngineFactory.java | 84 +++++ ...ositorySystemSessionAutoConfiguration.java | 6 +- ...ava => MavenResolverGrapeEngineTests.java} | 17 +- .../src/docs/asciidoc/cli/maven-setting.adoc | 4 +- 8 files changed, 443 insertions(+), 308 deletions(-) create mode 100644 spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngine.java create mode 100644 spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngineFactory.java rename spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/{AetherGrapeEngineTests.java => MavenResolverGrapeEngineTests.java} (94%) diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java index 3f04f629b0..4a9602cf0c 100644 --- a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -26,6 +26,7 @@ import java.util.LinkedList; import java.util.List; import java.util.ServiceLoader; +import groovy.grape.GrapeEngine; import groovy.lang.GroovyClassLoader; import groovy.lang.GroovyClassLoader.ClassCollector; import groovy.lang.GroovyCodeSource; @@ -44,10 +45,9 @@ import org.codehaus.groovy.transform.ASTTransformation; import org.codehaus.groovy.transform.ASTTransformationVisitor; import org.springframework.boot.cli.compiler.dependencies.SpringBootDependenciesDependencyManagement; -import org.springframework.boot.cli.compiler.grape.AetherGrapeEngine; -import org.springframework.boot.cli.compiler.grape.AetherGrapeEngineFactory; import org.springframework.boot.cli.compiler.grape.DependencyResolutionContext; import org.springframework.boot.cli.compiler.grape.GrapeEngineInstaller; +import org.springframework.boot.cli.compiler.grape.MavenResolverGrapeEngineFactory; import org.springframework.boot.cli.util.ResourceUtils; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.util.ClassUtils; @@ -96,7 +96,7 @@ public class GroovyCompiler { DependencyResolutionContext resolutionContext = new DependencyResolutionContext(); resolutionContext.addDependencyManagement(new SpringBootDependenciesDependencyManagement()); - AetherGrapeEngine grapeEngine = AetherGrapeEngineFactory.create(this.loader, + GrapeEngine grapeEngine = MavenResolverGrapeEngineFactory.create(this.loader, configuration.getRepositoryConfiguration(), resolutionContext, configuration.isQuiet()); GrapeEngineInstaller.install(grapeEngine); diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java index a95fa1bbfb..012b311b07 100644 --- a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -16,31 +16,13 @@ package org.springframework.boot.cli.compiler.grape; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URI; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.List; -import java.util.Map; import groovy.grape.GrapeEngine; import groovy.lang.GroovyClassLoader; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.collection.CollectRequest; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.graph.Exclusion; import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.resolution.ArtifactResolutionException; -import org.eclipse.aether.resolution.ArtifactResult; -import org.eclipse.aether.resolution.DependencyRequest; -import org.eclipse.aether.resolution.DependencyResult; -import org.eclipse.aether.util.artifact.JavaScopes; -import org.eclipse.aether.util.filter.DependencyFilterUtils; /** * A {@link GrapeEngine} implementation that uses @@ -50,282 +32,16 @@ import org.eclipse.aether.util.filter.DependencyFilterUtils; * @author Andy Wilkinson * @author Phillip Webb * @since 1.0.0 + * @deprecated since 2.5.9 for removal in 2.8.0 in favor of + * {@link MavenResolverGrapeEngine} */ -@SuppressWarnings("rawtypes") -public class AetherGrapeEngine implements GrapeEngine { - - private static final Collection WILDCARD_EXCLUSION; - - static { - List exclusions = new ArrayList<>(); - exclusions.add(new Exclusion("*", "*", "*", "*")); - WILDCARD_EXCLUSION = Collections.unmodifiableList(exclusions); - } - - private final DependencyResolutionContext resolutionContext; - - private final ProgressReporter progressReporter; - - private final GroovyClassLoader classLoader; - - private final DefaultRepositorySystemSession session; - - private final RepositorySystem repositorySystem; - - private final List repositories; +@Deprecated +public class AetherGrapeEngine extends MavenResolverGrapeEngine { public AetherGrapeEngine(GroovyClassLoader classLoader, RepositorySystem repositorySystem, DefaultRepositorySystemSession repositorySystemSession, List remoteRepositories, DependencyResolutionContext resolutionContext, boolean quiet) { - this.classLoader = classLoader; - this.repositorySystem = repositorySystem; - this.session = repositorySystemSession; - this.resolutionContext = resolutionContext; - this.repositories = new ArrayList<>(); - List remotes = new ArrayList<>(remoteRepositories); - Collections.reverse(remotes); // priority is reversed in addRepository - for (RemoteRepository repository : remotes) { - addRepository(repository); - } - this.progressReporter = getProgressReporter(this.session, quiet); - } - - private ProgressReporter getProgressReporter(DefaultRepositorySystemSession session, boolean quiet) { - String progressReporter = (quiet ? "none" - : System.getProperty("org.springframework.boot.cli.compiler.grape.ProgressReporter")); - if ("detail".equals(progressReporter) || Boolean.getBoolean("groovy.grape.report.downloads")) { - return new DetailedProgressReporter(session, System.out); - } - if ("none".equals(progressReporter)) { - return () -> { - }; - } - return new SummaryProgressReporter(session, System.out); - } - - @Override - public Object grab(Map args) { - return grab(args, args); - } - - @Override - public Object grab(Map args, Map... dependencyMaps) { - List exclusions = createExclusions(args); - List dependencies = createDependencies(dependencyMaps, exclusions); - try { - List files = resolve(dependencies); - GroovyClassLoader classLoader = getClassLoader(args); - for (File file : files) { - classLoader.addURL(file.toURI().toURL()); - } - } - catch (ArtifactResolutionException | MalformedURLException ex) { - throw new DependencyResolutionFailedException(ex); - } - return null; - } - - @SuppressWarnings("unchecked") - private List createExclusions(Map args) { - List exclusions = new ArrayList<>(); - if (args != null) { - List> exclusionMaps = (List>) args.get("excludes"); - if (exclusionMaps != null) { - for (Map exclusionMap : exclusionMaps) { - exclusions.add(createExclusion(exclusionMap)); - } - } - } - return exclusions; - } - - private Exclusion createExclusion(Map exclusionMap) { - String group = (String) exclusionMap.get("group"); - String module = (String) exclusionMap.get("module"); - return new Exclusion(group, module, "*", "*"); - } - - private List createDependencies(Map[] dependencyMaps, List exclusions) { - List dependencies = new ArrayList<>(dependencyMaps.length); - for (Map dependencyMap : dependencyMaps) { - dependencies.add(createDependency(dependencyMap, exclusions)); - } - return dependencies; - } - - private Dependency createDependency(Map dependencyMap, List exclusions) { - Artifact artifact = createArtifact(dependencyMap); - if (isTransitive(dependencyMap)) { - return new Dependency(artifact, JavaScopes.COMPILE, false, exclusions); - } - return new Dependency(artifact, JavaScopes.COMPILE, null, WILDCARD_EXCLUSION); - } - - private Artifact createArtifact(Map dependencyMap) { - String group = (String) dependencyMap.get("group"); - String module = (String) dependencyMap.get("module"); - String version = (String) dependencyMap.get("version"); - if (version == null) { - version = this.resolutionContext.getManagedVersion(group, module); - } - String classifier = (String) dependencyMap.get("classifier"); - String type = determineType(dependencyMap); - return new DefaultArtifact(group, module, classifier, type, version); - } - - private String determineType(Map dependencyMap) { - String type = (String) dependencyMap.get("type"); - String ext = (String) dependencyMap.get("ext"); - if (type == null) { - type = ext; - if (type == null) { - type = "jar"; - } - } - else if (ext != null && !type.equals(ext)) { - throw new IllegalArgumentException("If both type and ext are specified they must have the same value"); - } - return type; - } - - private boolean isTransitive(Map dependencyMap) { - Boolean transitive = (Boolean) dependencyMap.get("transitive"); - return (transitive != null) ? transitive : true; - } - - private List getDependencies(DependencyResult dependencyResult) { - List dependencies = new ArrayList<>(); - for (ArtifactResult artifactResult : dependencyResult.getArtifactResults()) { - dependencies.add(new Dependency(artifactResult.getArtifact(), JavaScopes.COMPILE)); - } - return dependencies; - } - - private List getFiles(DependencyResult dependencyResult) { - List files = new ArrayList<>(); - for (ArtifactResult result : dependencyResult.getArtifactResults()) { - files.add(result.getArtifact().getFile()); - } - return files; - } - - private GroovyClassLoader getClassLoader(Map args) { - GroovyClassLoader classLoader = (GroovyClassLoader) args.get("classLoader"); - return (classLoader != null) ? classLoader : this.classLoader; - } - - @Override - public void addResolver(Map args) { - String name = (String) args.get("name"); - String root = (String) args.get("root"); - RemoteRepository.Builder builder = new RemoteRepository.Builder(name, "default", root); - RemoteRepository repository = builder.build(); - addRepository(repository); - } - - protected void addRepository(RemoteRepository repository) { - if (this.repositories.contains(repository)) { - return; - } - repository = getPossibleMirror(repository); - repository = applyProxy(repository); - repository = applyAuthentication(repository); - this.repositories.add(0, repository); - } - - private RemoteRepository getPossibleMirror(RemoteRepository remoteRepository) { - RemoteRepository mirror = this.session.getMirrorSelector().getMirror(remoteRepository); - if (mirror != null) { - return mirror; - } - return remoteRepository; - } - - private RemoteRepository applyProxy(RemoteRepository repository) { - if (repository.getProxy() == null) { - RemoteRepository.Builder builder = new RemoteRepository.Builder(repository); - builder.setProxy(this.session.getProxySelector().getProxy(repository)); - repository = builder.build(); - } - return repository; - } - - private RemoteRepository applyAuthentication(RemoteRepository repository) { - if (repository.getAuthentication() == null) { - RemoteRepository.Builder builder = new RemoteRepository.Builder(repository); - builder.setAuthentication(this.session.getAuthenticationSelector().getAuthentication(repository)); - repository = builder.build(); - } - return repository; - } - - @Override - public Map>> enumerateGrapes() { - throw new UnsupportedOperationException("Grape enumeration is not supported"); - } - - @Override - public URI[] resolve(Map args, Map... dependencyMaps) { - return resolve(args, null, dependencyMaps); - } - - @Override - public URI[] resolve(Map args, List depsInfo, Map... dependencyMaps) { - List exclusions = createExclusions(args); - List dependencies = createDependencies(dependencyMaps, exclusions); - try { - List files = resolve(dependencies); - List uris = new ArrayList<>(files.size()); - for (File file : files) { - uris.add(file.toURI()); - } - return uris.toArray(new URI[0]); - } - catch (Exception ex) { - throw new DependencyResolutionFailedException(ex); - } - } - - private List resolve(List dependencies) throws ArtifactResolutionException { - try { - CollectRequest collectRequest = getCollectRequest(dependencies); - DependencyRequest dependencyRequest = getDependencyRequest(collectRequest); - DependencyResult result = this.repositorySystem.resolveDependencies(this.session, dependencyRequest); - addManagedDependencies(result); - return getFiles(result); - } - catch (Exception ex) { - throw new DependencyResolutionFailedException(ex); - } - finally { - this.progressReporter.finished(); - } - } - - private CollectRequest getCollectRequest(List dependencies) { - CollectRequest collectRequest = new CollectRequest((Dependency) null, dependencies, - new ArrayList<>(this.repositories)); - collectRequest.setManagedDependencies(this.resolutionContext.getManagedDependencies()); - return collectRequest; - } - - private DependencyRequest getDependencyRequest(CollectRequest collectRequest) { - return new DependencyRequest(collectRequest, - DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE, JavaScopes.RUNTIME)); - } - - private void addManagedDependencies(DependencyResult result) { - this.resolutionContext.addManagedDependencies(getDependencies(result)); - } - - @Override - public Map[] listDependencies(ClassLoader classLoader) { - throw new UnsupportedOperationException("Listing dependencies is not supported"); - } - - @Override - public Object grab(String endorsedModule) { - throw new UnsupportedOperationException("Grabbing an endorsed module is not supported"); + super(classLoader, repositorySystem, repositorySystemSession, remoteRepositories, resolutionContext, quiet); } } diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineFactory.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineFactory.java index cf46b4c23d..5465051e8f 100644 --- a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineFactory.java +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -40,7 +40,10 @@ import org.eclipse.aether.transport.http.HttpTransporterFactory; * * @author Andy Wilkinson * @since 1.0.0 + * @deprecated since 2.5.9 for removal in 2.8.0 in favor of + * {@link MavenResolverGrapeEngineFactory} */ +@Deprecated public abstract class AetherGrapeEngineFactory { public static AetherGrapeEngine create(GroovyClassLoader classLoader, diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngine.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngine.java new file mode 100644 index 0000000000..575ebee0a5 --- /dev/null +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngine.java @@ -0,0 +1,331 @@ +/* + * Copyright 2012-2022 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 + * + * https://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 java.net.MalformedURLException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import groovy.grape.GrapeEngine; +import groovy.lang.GroovyClassLoader; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.Exclusion; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactResolutionException; +import org.eclipse.aether.resolution.ArtifactResult; +import org.eclipse.aether.resolution.DependencyRequest; +import org.eclipse.aether.resolution.DependencyResult; +import org.eclipse.aether.util.artifact.JavaScopes; +import org.eclipse.aether.util.filter.DependencyFilterUtils; + +/** + * A {@link GrapeEngine} implementation that uses + * Maven Resolver, the + * dependency resolution system used by Maven. + * + * @author Andy Wilkinson + * @author Phillip Webb + * @since 2.5.9 + */ +@SuppressWarnings("rawtypes") +public class MavenResolverGrapeEngine implements GrapeEngine { + + private static final Collection WILDCARD_EXCLUSION; + + static { + List exclusions = new ArrayList<>(); + exclusions.add(new Exclusion("*", "*", "*", "*")); + WILDCARD_EXCLUSION = Collections.unmodifiableList(exclusions); + } + + private final DependencyResolutionContext resolutionContext; + + private final ProgressReporter progressReporter; + + private final GroovyClassLoader classLoader; + + private final DefaultRepositorySystemSession session; + + private final RepositorySystem repositorySystem; + + private final List repositories; + + public MavenResolverGrapeEngine(GroovyClassLoader classLoader, RepositorySystem repositorySystem, + DefaultRepositorySystemSession repositorySystemSession, List remoteRepositories, + DependencyResolutionContext resolutionContext, boolean quiet) { + this.classLoader = classLoader; + this.repositorySystem = repositorySystem; + this.session = repositorySystemSession; + this.resolutionContext = resolutionContext; + this.repositories = new ArrayList<>(); + List remotes = new ArrayList<>(remoteRepositories); + Collections.reverse(remotes); // priority is reversed in addRepository + for (RemoteRepository repository : remotes) { + addRepository(repository); + } + this.progressReporter = getProgressReporter(this.session, quiet); + } + + private ProgressReporter getProgressReporter(DefaultRepositorySystemSession session, boolean quiet) { + String progressReporter = (quiet ? "none" + : System.getProperty("org.springframework.boot.cli.compiler.grape.ProgressReporter")); + if ("detail".equals(progressReporter) || Boolean.getBoolean("groovy.grape.report.downloads")) { + return new DetailedProgressReporter(session, System.out); + } + if ("none".equals(progressReporter)) { + return () -> { + }; + } + return new SummaryProgressReporter(session, System.out); + } + + @Override + public Object grab(Map args) { + return grab(args, args); + } + + @Override + public Object grab(Map args, Map... dependencyMaps) { + List exclusions = createExclusions(args); + List dependencies = createDependencies(dependencyMaps, exclusions); + try { + List files = resolve(dependencies); + GroovyClassLoader classLoader = getClassLoader(args); + for (File file : files) { + classLoader.addURL(file.toURI().toURL()); + } + } + catch (ArtifactResolutionException | MalformedURLException ex) { + throw new DependencyResolutionFailedException(ex); + } + return null; + } + + @SuppressWarnings("unchecked") + private List createExclusions(Map args) { + List exclusions = new ArrayList<>(); + if (args != null) { + List> exclusionMaps = (List>) args.get("excludes"); + if (exclusionMaps != null) { + for (Map exclusionMap : exclusionMaps) { + exclusions.add(createExclusion(exclusionMap)); + } + } + } + return exclusions; + } + + private Exclusion createExclusion(Map exclusionMap) { + String group = (String) exclusionMap.get("group"); + String module = (String) exclusionMap.get("module"); + return new Exclusion(group, module, "*", "*"); + } + + private List createDependencies(Map[] dependencyMaps, List exclusions) { + List dependencies = new ArrayList<>(dependencyMaps.length); + for (Map dependencyMap : dependencyMaps) { + dependencies.add(createDependency(dependencyMap, exclusions)); + } + return dependencies; + } + + private Dependency createDependency(Map dependencyMap, List exclusions) { + Artifact artifact = createArtifact(dependencyMap); + if (isTransitive(dependencyMap)) { + return new Dependency(artifact, JavaScopes.COMPILE, false, exclusions); + } + return new Dependency(artifact, JavaScopes.COMPILE, null, WILDCARD_EXCLUSION); + } + + private Artifact createArtifact(Map dependencyMap) { + String group = (String) dependencyMap.get("group"); + String module = (String) dependencyMap.get("module"); + String version = (String) dependencyMap.get("version"); + if (version == null) { + version = this.resolutionContext.getManagedVersion(group, module); + } + String classifier = (String) dependencyMap.get("classifier"); + String type = determineType(dependencyMap); + return new DefaultArtifact(group, module, classifier, type, version); + } + + private String determineType(Map dependencyMap) { + String type = (String) dependencyMap.get("type"); + String ext = (String) dependencyMap.get("ext"); + if (type == null) { + type = ext; + if (type == null) { + type = "jar"; + } + } + else if (ext != null && !type.equals(ext)) { + throw new IllegalArgumentException("If both type and ext are specified they must have the same value"); + } + return type; + } + + private boolean isTransitive(Map dependencyMap) { + Boolean transitive = (Boolean) dependencyMap.get("transitive"); + return (transitive != null) ? transitive : true; + } + + private List getDependencies(DependencyResult dependencyResult) { + List dependencies = new ArrayList<>(); + for (ArtifactResult artifactResult : dependencyResult.getArtifactResults()) { + dependencies.add(new Dependency(artifactResult.getArtifact(), JavaScopes.COMPILE)); + } + return dependencies; + } + + private List getFiles(DependencyResult dependencyResult) { + List files = new ArrayList<>(); + for (ArtifactResult result : dependencyResult.getArtifactResults()) { + files.add(result.getArtifact().getFile()); + } + return files; + } + + private GroovyClassLoader getClassLoader(Map args) { + GroovyClassLoader classLoader = (GroovyClassLoader) args.get("classLoader"); + return (classLoader != null) ? classLoader : this.classLoader; + } + + @Override + public void addResolver(Map args) { + String name = (String) args.get("name"); + String root = (String) args.get("root"); + RemoteRepository.Builder builder = new RemoteRepository.Builder(name, "default", root); + RemoteRepository repository = builder.build(); + addRepository(repository); + } + + protected void addRepository(RemoteRepository repository) { + if (this.repositories.contains(repository)) { + return; + } + repository = getPossibleMirror(repository); + repository = applyProxy(repository); + repository = applyAuthentication(repository); + this.repositories.add(0, repository); + } + + private RemoteRepository getPossibleMirror(RemoteRepository remoteRepository) { + RemoteRepository mirror = this.session.getMirrorSelector().getMirror(remoteRepository); + if (mirror != null) { + return mirror; + } + return remoteRepository; + } + + private RemoteRepository applyProxy(RemoteRepository repository) { + if (repository.getProxy() == null) { + RemoteRepository.Builder builder = new RemoteRepository.Builder(repository); + builder.setProxy(this.session.getProxySelector().getProxy(repository)); + repository = builder.build(); + } + return repository; + } + + private RemoteRepository applyAuthentication(RemoteRepository repository) { + if (repository.getAuthentication() == null) { + RemoteRepository.Builder builder = new RemoteRepository.Builder(repository); + builder.setAuthentication(this.session.getAuthenticationSelector().getAuthentication(repository)); + repository = builder.build(); + } + return repository; + } + + @Override + public Map>> enumerateGrapes() { + throw new UnsupportedOperationException("Grape enumeration is not supported"); + } + + @Override + public URI[] resolve(Map args, Map... dependencyMaps) { + return resolve(args, null, dependencyMaps); + } + + @Override + public URI[] resolve(Map args, List depsInfo, Map... dependencyMaps) { + List exclusions = createExclusions(args); + List dependencies = createDependencies(dependencyMaps, exclusions); + try { + List files = resolve(dependencies); + List uris = new ArrayList<>(files.size()); + for (File file : files) { + uris.add(file.toURI()); + } + return uris.toArray(new URI[0]); + } + catch (Exception ex) { + throw new DependencyResolutionFailedException(ex); + } + } + + private List resolve(List dependencies) throws ArtifactResolutionException { + try { + CollectRequest collectRequest = getCollectRequest(dependencies); + DependencyRequest dependencyRequest = getDependencyRequest(collectRequest); + DependencyResult result = this.repositorySystem.resolveDependencies(this.session, dependencyRequest); + addManagedDependencies(result); + return getFiles(result); + } + catch (Exception ex) { + throw new DependencyResolutionFailedException(ex); + } + finally { + this.progressReporter.finished(); + } + } + + private CollectRequest getCollectRequest(List dependencies) { + CollectRequest collectRequest = new CollectRequest((Dependency) null, dependencies, + new ArrayList<>(this.repositories)); + collectRequest.setManagedDependencies(this.resolutionContext.getManagedDependencies()); + return collectRequest; + } + + private DependencyRequest getDependencyRequest(CollectRequest collectRequest) { + return new DependencyRequest(collectRequest, + DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE, JavaScopes.RUNTIME)); + } + + private void addManagedDependencies(DependencyResult result) { + this.resolutionContext.addManagedDependencies(getDependencies(result)); + } + + @Override + public Map[] listDependencies(ClassLoader classLoader) { + throw new UnsupportedOperationException("Listing dependencies is not supported"); + } + + @Override + public Object grab(String endorsedModule) { + throw new UnsupportedOperationException("Grabbing an endorsed module is not supported"); + } + +} diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngineFactory.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngineFactory.java new file mode 100644 index 0000000000..9e2adf63b1 --- /dev/null +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngineFactory.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012-2022 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 + * + * https://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.util.ArrayList; +import java.util.List; +import java.util.ServiceLoader; + +import groovy.lang.GroovyClassLoader; +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 MavenResolverGrapeEngine}. + * + * @author Andy Wilkinson + * @since 2.5.9 + */ +public abstract class MavenResolverGrapeEngineFactory { + + public static MavenResolverGrapeEngine create(GroovyClassLoader classLoader, + List repositoryConfigurations, + DependencyResolutionContext dependencyResolutionContext, boolean quiet) { + RepositorySystem repositorySystem = createServiceLocator().getService(RepositorySystem.class); + DefaultRepositorySystemSession repositorySystemSession = MavenRepositorySystemUtils.newSession(); + ServiceLoader autoConfigurations = ServiceLoader + .load(RepositorySystemSessionAutoConfiguration.class); + for (RepositorySystemSessionAutoConfiguration autoConfiguration : autoConfigurations) { + autoConfiguration.apply(repositorySystemSession, repositorySystem); + } + new DefaultRepositorySystemSessionAutoConfiguration().apply(repositorySystemSession, repositorySystem); + return new MavenResolverGrapeEngine(classLoader, repositorySystem, repositorySystemSession, + createRepositories(repositoryConfigurations), dependencyResolutionContext, quiet); + } + + 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 createRepositories(List repositoryConfigurations) { + List repositories = new ArrayList<>(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; + } + +} diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/RepositorySystemSessionAutoConfiguration.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/RepositorySystemSessionAutoConfiguration.java index e30f405f49..6da09826f3 100644 --- a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/RepositorySystemSessionAutoConfiguration.java +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/RepositorySystemSessionAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -20,8 +20,8 @@ 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}. + * Strategy that can be used to apply some auto-configuration during the installation of a + * {@link MavenResolverGrapeEngine}. * * @author Andy Wilkinson * @since 1.0.0 diff --git a/spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java b/spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngineTests.java similarity index 94% rename from spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java rename to spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngineTests.java index 728e7d9d2c..8d9d7fb4eb 100644 --- a/spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java +++ b/spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/MavenResolverGrapeEngineTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import groovy.grape.GrapeEngine; import groovy.lang.GroovyClassLoader; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.repository.Authentication; @@ -43,7 +44,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException * * @author Andy Wilkinson */ -class AetherGrapeEngineTests { +class MavenResolverGrapeEngineTests { private final GroovyClassLoader groovyClassLoader = new GroovyClassLoader(); @@ -53,14 +54,14 @@ class AetherGrapeEngineTests { private final RepositoryConfiguration springSnapshot = new RepositoryConfiguration("spring-snapshot", URI.create("https://repo.spring.io/snapshot"), true); - private AetherGrapeEngine createGrapeEngine(RepositoryConfiguration... additionalRepositories) { + private GrapeEngine createGrapeEngine(RepositoryConfiguration... additionalRepositories) { List repositoryConfigurations = new ArrayList<>(); repositoryConfigurations .add(new RepositoryConfiguration("central", URI.create("https://repo1.maven.org/maven2"), false)); repositoryConfigurations.addAll(Arrays.asList(additionalRepositories)); DependencyResolutionContext dependencyResolutionContext = new DependencyResolutionContext(); dependencyResolutionContext.addDependencyManagement(new SpringBootDependenciesDependencyManagement()); - return AetherGrapeEngineFactory.create(this.groovyClassLoader, repositoryConfigurations, + return MavenResolverGrapeEngineFactory.create(this.groovyClassLoader, repositoryConfigurations, dependencyResolutionContext, false); } @@ -75,7 +76,7 @@ class AetherGrapeEngineTests { @Test void proxySelector() { doWithCustomUserHome(() -> { - AetherGrapeEngine grapeEngine = createGrapeEngine(); + GrapeEngine grapeEngine = createGrapeEngine(); DefaultRepositorySystemSession session = (DefaultRepositorySystemSession) ReflectionTestUtils .getField(grapeEngine, "session"); @@ -139,7 +140,7 @@ class AetherGrapeEngineTests { @Test void resolutionWithCustomResolver() { Map args = new HashMap<>(); - AetherGrapeEngine grapeEngine = createGrapeEngine(); + GrapeEngine grapeEngine = createGrapeEngine(); grapeEngine.addResolver(createResolver("spring-releases", "https://repo.spring.io/release")); Map dependency = createDependency("io.spring.docresources", "spring-doc-resources", "0.1.1.RELEASE"); @@ -153,7 +154,7 @@ class AetherGrapeEngineTests { Map dependency = createDependency("org.grails", "grails-dependencies", "2.4.0"); dependency.put("type", "foo"); dependency.put("ext", "bar"); - AetherGrapeEngine grapeEngine = createGrapeEngine(); + GrapeEngine grapeEngine = createGrapeEngine(); assertThatIllegalArgumentException().isThrownBy(() -> grapeEngine.grab(Collections.emptyMap(), dependency)); } @@ -196,7 +197,7 @@ class AetherGrapeEngineTests { @SuppressWarnings("unchecked") private List getRepositories() { - AetherGrapeEngine grapeEngine = createGrapeEngine(); + GrapeEngine grapeEngine = createGrapeEngine(); return (List) ReflectionTestUtils.getField(grapeEngine, "repositories"); } diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/cli/maven-setting.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/cli/maven-setting.adoc index 7ff6423802..6be011286e 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/cli/maven-setting.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/cli/maven-setting.adoc @@ -1,7 +1,7 @@ [[cli.maven-setting]] == Configuring the CLI with settings.xml -The Spring Boot CLI uses Aether, Maven's dependency resolution engine, to resolve dependencies. -The CLI makes use of the Maven configuration found in `~/.m2/settings.xml` to configure Aether. +The Spring Boot CLI uses Maven Resolver, Maven's dependency resolution engine, to resolve dependencies. +The CLI makes use of the Maven configuration found in `~/.m2/settings.xml` to configure Maven Resolver. The following configuration settings are honored by the CLI: * Offline