All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.grails.cli.compiler.grape.MavenResolverGrapeEngine Maven / Gradle / Ivy

There is a newer version: 2023.1.0-RC1
Show newest version
/*
 * Copyright 2012-2023 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.grails.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.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 2022.1.0
 */
@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.grails.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 (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) {
        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");
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy