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

com.jfrog.GradleDependencyTreeUtils Maven / Gradle / Ivy

There is a newer version: 3.0.2
Show newest version
package com.jfrog;

import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ModuleVersionIdentifier;
import org.gradle.api.artifacts.result.DependencyResult;
import org.gradle.api.artifacts.result.ResolvedComponentResult;
import org.gradle.api.artifacts.result.ResolvedDependencyResult;
import org.gradle.api.artifacts.result.UnresolvedDependencyResult;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Utils for building the GradleDependencyTree object. The reason for these utils is to make the GradleDependencyTree
 * class clean from Gradle internal dependencies that may be unresolved during Jackson unmarshal.
 *
 * @author yahavi
 **/
public class GradleDependencyTreeUtils {
    // The maximum number of times a single dependency is populated, during the run of each configuration.
    private static final int MAX_DEP_POPULATIONS_IN_CONFIG = 10;

    /**
     * Add Gradle configuration including its all dependencies.
     *
     * @param root          the root node
     * @param configuration resolved or unresolved Gradle configuration
     * @param nodes         a map of all nodes mapped by their module ID (group:name:version)
     */
    public static void addConfiguration(GradleDependencyNode root, Configuration configuration, Map nodes) {
        if (configuration.isCanBeResolved()) {
            addResolvedConfiguration(root, configuration, nodes);
        } else {
            addUnresolvedConfiguration(root, configuration, nodes);
        }
    }

    /**
     * Add resolved configuration. A resolved configuration may contain transitive dependencies.
     *
     * @param root          the root node
     * @param configuration resolved Gradle configuration
     * @param nodes         a map of all nodes mapped by their module ID (group:name:version)
     */
    private static void addResolvedConfiguration(GradleDependencyNode root, Configuration configuration, Map nodes) {
        root.getConfigurations().add(configuration.getName());
        ResolvedComponentResult componentResult = configuration.getIncoming().getResolutionResult().getRoot();
        Map depPopulations = new HashMap<>();
        for (DependencyResult dependency : componentResult.getDependencies()) {
            populateTree(root, configuration.getName(), dependency, new HashSet<>(), nodes, depPopulations);
        }
    }

    /**
     * Add unresolved configuration. An unresolved configuration can contain only direct dependencies.
     *
     * @param root          the parent node
     * @param configuration unresolved Gradle configuration
     * @param nodes         a map of all nodes mapped by their module ID (group:name:version)
     */
    private static void addUnresolvedConfiguration(GradleDependencyNode root, Configuration configuration, Map nodes) {
        for (Dependency dependency : configuration.getDependencies()) {
            GradleDependencyNode child = new GradleDependencyNode(configuration.getName());
            child.setUnresolved(true);
            if (dependency.getVersion() != null) {
                // If the version is null, the dependency does not contain an ID and we should not add it.
                // For example: "implementation gradleApi()"
                addChild(root, String.join(":", dependency.getGroup(), dependency.getName(), dependency.getVersion()), child, nodes);
            }
        }
    }

    /**
     * Recursively populate the dependency tree.
     *
     * @param node              the parent node
     * @param configurationName the configuration name
     * @param dependency        resolved or unresolved dependency
     * @param addedChildren     a set used to remove duplications to make sure there is no loop in the tree
     * @param nodes             a map of all nodes mapped by their module ID (group:name:version)
     * @param depPopulations    a map of all node population counters mapped by their module ID (group:name:version)
     */
    private static void populateTree(GradleDependencyNode node, String configurationName, DependencyResult dependency, Set addedChildren, Map nodes, Map depPopulations) {
        GradleDependencyNode child = new GradleDependencyNode(configurationName);
        if (dependency instanceof UnresolvedDependencyResult) {
            child.setUnresolved(true);
            addChild(node, dependency.getRequested().getDisplayName(), child, nodes);
            return;
        }
        ResolvedDependencyResult resolvedDependency = (ResolvedDependencyResult) dependency;
        ModuleVersionIdentifier moduleVersion = resolvedDependency.getSelected().getModuleVersion();
        if (moduleVersion == null) {
            // If there is no module version, then the dependency was not found in any repository
            return;
        }
        String nodeId = moduleVersion.toString();
        int populations = depPopulations.getOrDefault(nodeId, 0);
        if (!addedChildren.add(nodeId) || populations >= MAX_DEP_POPULATIONS_IN_CONFIG) {
            return;
        }
        depPopulations.put(nodeId, populations + 1);
        for (DependencyResult dependencyResult : resolvedDependency.getSelected().getDependencies()) {
            populateTree(child, configurationName, dependencyResult, new HashSet<>(addedChildren), nodes, depPopulations);
        }
        addChild(node, nodeId, child, nodes);
    }

    /**
     * Add a child to the dependency tree.
     *
     * @param parent     the parent node
     * @param childId    the child ID
     * @param childToAdd the child node
     * @param nodes      a map of all nodes mapped by their module ID (group:name:version)
     */
    static void addChild(GradleDependencyNode parent, String childId, GradleDependencyNode childToAdd, Map nodes) {
        GradleDependencyNode child = nodes.get(childId);
        if (child == null) {
            nodes.put(childId, childToAdd);
        } else {
            // If the child already exists, add the Gradle configurations of the input child
            child.getConfigurations().addAll(childToAdd.getConfigurations());
            child.setUnresolved(child.isUnresolved() && childToAdd.isUnresolved());
            child.getChildren().addAll(childToAdd.getChildren());
        }
        parent.getChildren().add(childId);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy