commit
52f612b3eb
@ -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
|
||||
* <a href="https://maven.apache.org/resolver/index.html">Maven Resolver</a>, 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<Exclusion> WILDCARD_EXCLUSION;
|
||||
|
||||
static {
|
||||
List<Exclusion> 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<RemoteRepository> repositories;
|
||||
|
||||
public MavenResolverGrapeEngine(GroovyClassLoader classLoader, RepositorySystem repositorySystem,
|
||||
DefaultRepositorySystemSession repositorySystemSession, List<RemoteRepository> remoteRepositories,
|
||||
DependencyResolutionContext resolutionContext, boolean quiet) {
|
||||
this.classLoader = classLoader;
|
||||
this.repositorySystem = repositorySystem;
|
||||
this.session = repositorySystemSession;
|
||||
this.resolutionContext = resolutionContext;
|
||||
this.repositories = new ArrayList<>();
|
||||
List<RemoteRepository> 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<Exclusion> exclusions = createExclusions(args);
|
||||
List<Dependency> dependencies = createDependencies(dependencyMaps, exclusions);
|
||||
try {
|
||||
List<File> 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<Exclusion> createExclusions(Map<?, ?> args) {
|
||||
List<Exclusion> exclusions = new ArrayList<>();
|
||||
if (args != null) {
|
||||
List<Map<String, Object>> exclusionMaps = (List<Map<String, Object>>) args.get("excludes");
|
||||
if (exclusionMaps != null) {
|
||||
for (Map<String, Object> exclusionMap : exclusionMaps) {
|
||||
exclusions.add(createExclusion(exclusionMap));
|
||||
}
|
||||
}
|
||||
}
|
||||
return exclusions;
|
||||
}
|
||||
|
||||
private Exclusion createExclusion(Map<String, Object> exclusionMap) {
|
||||
String group = (String) exclusionMap.get("group");
|
||||
String module = (String) exclusionMap.get("module");
|
||||
return new Exclusion(group, module, "*", "*");
|
||||
}
|
||||
|
||||
private List<Dependency> createDependencies(Map<?, ?>[] dependencyMaps, List<Exclusion> exclusions) {
|
||||
List<Dependency> dependencies = new ArrayList<>(dependencyMaps.length);
|
||||
for (Map<?, ?> dependencyMap : dependencyMaps) {
|
||||
dependencies.add(createDependency(dependencyMap, exclusions));
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
private Dependency createDependency(Map<?, ?> dependencyMap, List<Exclusion> 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<Dependency> getDependencies(DependencyResult dependencyResult) {
|
||||
List<Dependency> dependencies = new ArrayList<>();
|
||||
for (ArtifactResult artifactResult : dependencyResult.getArtifactResults()) {
|
||||
dependencies.add(new Dependency(artifactResult.getArtifact(), JavaScopes.COMPILE));
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
private List<File> getFiles(DependencyResult dependencyResult) {
|
||||
List<File> 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<String, Object> 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<String, Map<String, List<String>>> 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<Exclusion> exclusions = createExclusions(args);
|
||||
List<Dependency> dependencies = createDependencies(dependencyMaps, exclusions);
|
||||
try {
|
||||
List<File> files = resolve(dependencies);
|
||||
List<URI> 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<File> resolve(List<Dependency> 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<Dependency> 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");
|
||||
}
|
||||
|
||||
}
|
@ -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<RepositoryConfiguration> repositoryConfigurations,
|
||||
DependencyResolutionContext dependencyResolutionContext, boolean quiet) {
|
||||
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 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<RemoteRepository> createRepositories(List<RepositoryConfiguration> repositoryConfigurations) {
|
||||
List<RemoteRepository> 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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue