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

com.google.cloud.tools.opensource.dependencies.DependencyGraphBuilder Maven / Gradle / Ivy

There is a newer version: 1.5.13
Show newest version
/*
 * Copyright 2018 Google LLC.
 *
 * 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 com.google.cloud.tools.opensource.dependencies;

import static com.google.cloud.tools.opensource.dependencies.RepositoryUtility.CENTRAL;
import static com.google.cloud.tools.opensource.dependencies.RepositoryUtility.mavenRepositoryFromUrl;
import static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.List;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.graph.DefaultDependencyNode;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.resolution.DependencyResolutionException;
import org.eclipse.aether.resolution.DependencyResult;

/**
 * Builds dependency graphs for Maven artifacts by querying repositories for
 * pom.xml files and following the dependency chains therein.
 */
public final class DependencyGraphBuilder {

  private static final RepositorySystem system = RepositoryUtility.newRepositorySystem();

  /** Maven repositories to use when resolving dependencies. */
  private final ImmutableList repositories;
  private Path localRepository;

  static {
    OsProperties.detectOsProperties().forEach(System::setProperty);
  }

  public DependencyGraphBuilder() {
    this(ImmutableList.of(CENTRAL.getUrl()));
  }

  /**
   * @param mavenRepositoryUrls remote Maven repositories to search for dependencies
   * @throws IllegalArgumentException if a URL is malformed or does not have an allowed scheme
   */
  public DependencyGraphBuilder(Iterable mavenRepositoryUrls) {
    ImmutableList.Builder repositoryListBuilder = ImmutableList.builder();
    for (String mavenRepositoryUrl : mavenRepositoryUrls) {
      RemoteRepository repository = mavenRepositoryFromUrl(mavenRepositoryUrl);
      repositoryListBuilder.add(repository);
    }
    this.repositories = repositoryListBuilder.build();
  }
  
  /**
   * Enable temporary repositories for tests.
   */
  @VisibleForTesting
  void setLocalRepository(Path localRepository) {
    this.localRepository = localRepository;
  }

  private DependencyNode resolveCompileTimeDependencies(
      List dependencyNodes, DefaultRepositorySystemSession session)
      throws DependencyResolutionException {

    ImmutableList.Builder dependenciesBuilder = ImmutableList.builder();
    for (DependencyNode dependencyNode : dependencyNodes) {
      Dependency dependency = dependencyNode.getDependency();
      if (dependency == null) {
        // Root DependencyNode has null dependency field.
        dependenciesBuilder.add(new Dependency(dependencyNode.getArtifact(), "compile"));
      } else {
        // The dependency field carries exclusions
        dependenciesBuilder.add(dependency.setScope("compile"));
      }
    }
    ImmutableList dependencyList = dependenciesBuilder.build();

    if (localRepository != null) {
      LocalRepository local = new LocalRepository(localRepository.toAbsolutePath().toString());
      session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, local));
    }

    CollectRequest collectRequest = new CollectRequest();
    if (dependencyList.size() == 1) {
      // With setRoot, the result includes dependencies with `optional:true` or `provided`
      collectRequest.setRoot(dependencyList.get(0));
    } else {
      collectRequest.setDependencies(dependencyList);
    }
    for (RemoteRepository repository : repositories) {
      collectRequest.addRepository(repository);
    }
    DependencyRequest dependencyRequest = new DependencyRequest();
    dependencyRequest.setCollectRequest(collectRequest);

    // resolveDependencies equals to calling both collectDependencies (build dependency tree) and
    // resolveArtifacts (download JAR files).
    DependencyResult dependencyResult = system.resolveDependencies(session, dependencyRequest);
    return dependencyResult.getRoot();
  }

  /**
   * Finds the full compile time, transitive dependency graph including duplicates, conflicting
   * versions, and provided and optional dependencies. Each node's dependencies are resolved
   * recursively. The scope of a dependency does not affect the scope of its children's
   * dependencies. Provided and optional dependencies are not treated differently than any other
   * dependency.
   *
   * 

In the event of I/O errors, missing artifacts, and other problems, it can return an * incomplete graph. * * @param artifacts Maven artifacts whose dependencies to retrieve * @return dependency graph representing the tree of Maven artifacts */ public DependencyGraph buildFullDependencyGraph(List artifacts) { ImmutableList dependencyNodes = artifacts.stream().map(DefaultDependencyNode::new).collect(toImmutableList()); DefaultRepositorySystemSession session = RepositoryUtility.newSessionForFullDependency(system); return buildDependencyGraph(dependencyNodes, session); } /** * Finds the full compile time, transitive dependency graph including duplicates and conflicting * versions, but not optional dependencies. Each node's dependencies are resolved recursively. The * scope of a dependency does not affect the scope of its children's dependencies. * *

In the event of I/O errors, missing artifacts, and other problems, it can return an * incomplete graph. * * @param artifacts Maven artifacts whose dependencies to retrieve * @return dependency graph representing the tree of Maven artifacts */ public DependencyGraph buildVerboseDependencyGraph(List artifacts) { ImmutableList dependencyNodes = artifacts.stream().map(DefaultDependencyNode::new).collect(toImmutableList()); DefaultRepositorySystemSession session = RepositoryUtility.newSessionForVerboseListDependency(system); return buildDependencyGraph(dependencyNodes, session); } /** * Finds the full compile time, transitive dependency graph including conflicting versions and * provided dependencies. This includes direct optional dependencies of the root node but not * optional dependencies of transitive dependencies. Each node's dependencies are resolved * recursively. The scope of a dependency does not affect the scope of its children's * dependencies. Provided and optional dependencies are not treated differently than any other * dependency. * *

In the event of I/O errors, missing artifacts, and other problems, it can return an * incomplete graph. * * @param artifact the root * @return the graph as built by Maven before dependency mediation */ public DependencyGraph buildVerboseDependencyGraph(Artifact artifact) { Dependency dependency = new Dependency(artifact, "compile"); return buildVerboseDependencyGraph(dependency); } DependencyGraph buildVerboseDependencyGraph(Dependency dependency) { DefaultRepositorySystemSession session = RepositoryUtility.newSessionForVerboseDependency(system); ImmutableList roots = ImmutableList.of(new DefaultDependencyNode(dependency)); return buildDependencyGraph(roots, session); } /** * Builds the transitive dependency graph as seen by Maven. It does not include duplicates and * conflicting versions. That is, this resolves conflicting versions by picking the first version * seen. This is how Maven normally operates. It does not contain provided-scope dependencies of * transitive dependencies. It does not contain optional dependencies of transitive dependencies. * *

In the event of I/O errors, missing artifacts, and other problems, it can return an * incomplete graph. */ public DependencyGraph buildMavenDependencyGraph(Dependency dependency) { ImmutableList roots = ImmutableList.of(new DefaultDependencyNode(dependency)); return buildDependencyGraph(roots, RepositoryUtility.newSessionForMaven(system)); } private DependencyGraph buildDependencyGraph( List dependencyNodes, DefaultRepositorySystemSession session) { try { DependencyNode node = resolveCompileTimeDependencies(dependencyNodes, session); return DependencyGraph.from(node); } catch (DependencyResolutionException ex) { DependencyResult result = ex.getResult(); DependencyGraph graph = DependencyGraph.from(result.getRoot()); for (ArtifactResult artifactResult : result.getArtifactResults()) { Artifact resolvedArtifact = artifactResult.getArtifact(); if (resolvedArtifact == null) { Artifact requestedArtifact = artifactResult.getRequest().getArtifact(); graph.addUnresolvableArtifactProblem(requestedArtifact); } } return graph; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy