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

org.gradle.api.tasks.diagnostics.DependencyInsightReportTask Maven / Gradle / Ivy

There is a newer version: 8.11.1
Show newest version
/*
 * Copyright 2016 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
 *
 *      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 org.gradle.api.tasks.diagnostics;

import org.apache.commons.lang.StringUtils;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.Incubating;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.result.DependencyResult;
import org.gradle.api.artifacts.result.ResolutionResult;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionComparator;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelectorScheme;
import org.gradle.api.internal.tasks.options.Option;
import org.gradle.api.specs.Spec;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.diagnostics.internal.dsl.DependencyResultSpecNotationConverter;
import org.gradle.api.tasks.diagnostics.internal.graph.DependencyGraphRenderer;
import org.gradle.api.tasks.diagnostics.internal.graph.LegendRenderer;
import org.gradle.api.tasks.diagnostics.internal.graph.NodeRenderer;
import org.gradle.api.tasks.diagnostics.internal.graph.nodes.RenderableDependency;
import org.gradle.api.tasks.diagnostics.internal.insight.DependencyInsightReporter;
import org.gradle.internal.graph.GraphRenderer;
import org.gradle.internal.logging.text.StyledTextOutput;
import org.gradle.internal.logging.text.StyledTextOutputFactory;
import org.gradle.internal.typeconversion.NotationParser;

import javax.inject.Inject;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

import static org.gradle.internal.logging.text.StyledTextOutput.Style.*;

/**
 * Generates a report that attempts to answer questions like:
 * 
    *
  • Why is this dependency in the dependency graph?
  • *
  • Exactly which dependencies are pulling this dependency into the graph?
  • *
  • What is the actual version (i.e. *selected* version) of the dependency that will be used? Is it the same as what was *requested*?
  • *
  • Why is the *selected* version of a dependency different to the *requested*?
  • *
* * Use this task to get insight into a particular dependency (or dependencies) * and find out what exactly happens during dependency resolution and conflict resolution. * If the dependency version was forced or selected by the conflict resolution * this information will be available in the report. *

* While the regular dependencies report ({@link DependencyReportTask}) shows the path from the top level dependencies down through the transitive dependencies, * the dependency insight report shows the path from a particular dependency to the dependencies that pulled it in. * That is, it is an inverted view of the regular dependencies report. *

* The task requires setting the dependency spec and the configuration. * For more information on how to configure those please refer to docs for * {@link DependencyInsightReportTask#setDependencySpec(Object)} and * {@link DependencyInsightReportTask#setConfiguration(String)}. *

* The task can also be configured from the command line. * For more information please refer to {@link DependencyInsightReportTask#setDependencySpec(Object)} * and {@link DependencyInsightReportTask#setConfiguration(String)} */ @Incubating public class DependencyInsightReportTask extends DefaultTask { private Configuration configuration; private Spec dependencySpec; /** * Selects the dependency (or dependencies if multiple matches found) to show the report for. */ @Internal public Spec getDependencySpec() { return dependencySpec; } /** * The dependency spec selects the dependency (or dependencies if multiple matches found) to show the report for. The spec receives an instance of {@link DependencyResult} as parameter. */ public void setDependencySpec(Spec dependencySpec) { this.dependencySpec = dependencySpec; } /** * Configures the dependency to show the report for. * Multiple notation formats are supported: Strings, instances of {@link Spec} * and groovy closures. Spec and closure receive {@link DependencyResult} as parameter. * Examples of String notation: 'org.slf4j:slf4j-api', 'slf4j-api', or simply: 'slf4j'. * The input may potentially match multiple dependencies. * See also {@link DependencyInsightReportTask#setDependencySpec(Spec)} *

* This method is exposed to the command line interface. Example usage: *

gradle dependencyInsight --dependency slf4j
*/ @Option(option = "dependency", description = "Shows the details of given dependency.") public void setDependencySpec(Object dependencyInsightNotation) { NotationParser> parser = DependencyResultSpecNotationConverter.parser(); this.dependencySpec = parser.parseNotation(dependencyInsightNotation); } /** * Configuration to look the dependency in */ @Internal public Configuration getConfiguration() { return configuration; } /** * Sets the configuration to look the dependency in. */ public void setConfiguration(Configuration configuration) { this.configuration = configuration; } /** * Sets the configuration (via name) to look the dependency in. *

* This method is exposed to the command line interface. Example usage: *

gradle dependencyInsight --configuration runtime --dependency slf4j
*/ @Option(option = "configuration", description = "Looks for the dependency in given configuration.") public void setConfiguration(String configurationName) { this.configuration = getProject().getConfigurations().getByName(configurationName); } @Inject protected StyledTextOutputFactory getTextOutputFactory() { throw new UnsupportedOperationException(); } @Inject protected VersionSelectorScheme getVersionSelectorScheme() { throw new UnsupportedOperationException(); } @Inject protected VersionComparator getVersionComparator() { throw new UnsupportedOperationException(); } @TaskAction public void report() { final Configuration configuration = getConfiguration(); if (configuration == null) { throw new InvalidUserDataException("Dependency insight report cannot be generated because the input configuration was not specified. " + "\nIt can be specified from the command line, e.g: '" + getPath() + " --configuration someConf --dependency someDep'"); } if (dependencySpec == null) { throw new InvalidUserDataException("Dependency insight report cannot be generated because the dependency to show was not specified." + "\nIt can be specified from the command line, e.g: '" + getPath() + " --dependency someDep'"); } StyledTextOutput output = getTextOutputFactory().create(getClass()); GraphRenderer renderer = new GraphRenderer(output); ResolutionResult result = configuration.getIncoming().getResolutionResult(); final Set selectedDependencies = new LinkedHashSet(); result.allDependencies(new Action() { @Override public void execute(DependencyResult dependencyResult) { if (dependencySpec.isSatisfiedBy(dependencyResult)) { selectedDependencies.add(dependencyResult); } } }); if (selectedDependencies.isEmpty()) { output.println("No dependencies matching given input were found in " + String.valueOf(configuration)); return; } Collection sortedDeps = new DependencyInsightReporter().prepare(selectedDependencies, getVersionSelectorScheme(), getVersionComparator()); NodeRenderer nodeRenderer = new NodeRenderer() { public void renderNode(StyledTextOutput target, RenderableDependency node, boolean alreadyRendered) { boolean leaf = node.getChildren().isEmpty(); target.text(leaf ? configuration.getName() : node.getName()); if (alreadyRendered && !leaf) { target.withStyle(Info).text(" (*)"); } } }; LegendRenderer legendRenderer = new LegendRenderer(output); DependencyGraphRenderer dependencyGraphRenderer = new DependencyGraphRenderer(renderer, nodeRenderer, legendRenderer); int i = 1; for (final RenderableDependency dependency : sortedDeps) { renderer.visit(new Action() { public void execute(StyledTextOutput out) { out.withStyle(Identifier).text(dependency.getName()); if (StringUtils.isNotEmpty(dependency.getDescription())) { out.withStyle(Description).text(" (" + dependency.getDescription() + ")"); } switch (dependency.getResolutionState()) { case FAILED: out.withStyle(Failure).text(" FAILED"); break; case RESOLVED: break; case UNRESOLVED: out.withStyle(Failure).text(" (n)"); break; } } }, true); dependencyGraphRenderer.render(dependency); boolean last = i++ == sortedDeps.size(); if (!last) { output.println(); } } legendRenderer.printLegend(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy