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

io.spring.gradle.dependencymanagement.internal.ExclusionConfiguringAction Maven / Gradle / Ivy

There is a newer version: 1.1.7
Show newest version
/*
 * Copyright 2014-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 io.spring.gradle.dependencymanagement.internal;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import io.spring.gradle.dependencymanagement.internal.DependencyManagementConfigurationContainer.ConfigurationConfigurer;
import org.gradle.api.Action;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.DependencySet;
import org.gradle.api.artifacts.ModuleDependency;
import org.gradle.api.artifacts.ResolvableDependencies;
import org.gradle.api.artifacts.component.ComponentSelector;
import org.gradle.api.artifacts.component.ModuleComponentSelector;
import org.gradle.api.artifacts.result.DependencyResult;
import org.gradle.api.artifacts.result.ResolutionResult;
import org.gradle.api.artifacts.result.ResolvedComponentResult;
import org.gradle.api.artifacts.result.ResolvedDependencyResult;
import org.gradle.api.artifacts.result.UnresolvedDependencyResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An {@link Action} to be applied to {@link ResolvableDependencies} that configures
 * exclusions based on the Maven exclusion metadata gleaned from the dependencies.
 *
 * @author Andy Wilkinson
 */
class ExclusionConfiguringAction implements Action {

	private static final Logger logger = LoggerFactory.getLogger(ExclusionConfiguringAction.class);

	private final DependencyManagementSettings dependencyManagementSettings;

	private final DependencyManagementContainer dependencyManagementContainer;

	private final DependencyManagementConfigurationContainer configurationContainer;

	private final Configuration configuration;

	private final ExclusionResolver exclusionResolver;

	private final ConfigurationConfigurer configurationConfigurer;

	ExclusionConfiguringAction(DependencyManagementSettings dependencyManagementSettings,
			DependencyManagementContainer dependencyManagementContainer,
			DependencyManagementConfigurationContainer configurationContainer, Configuration configuration,
			ExclusionResolver exclusionResolver, ConfigurationConfigurer configurationConfigurer) {
		this.dependencyManagementSettings = dependencyManagementSettings;
		this.dependencyManagementContainer = dependencyManagementContainer;
		this.configurationContainer = configurationContainer;
		this.configuration = configuration;
		this.exclusionResolver = exclusionResolver;
		this.configurationConfigurer = configurationConfigurer;
	}

	@Override
	public void execute(ResolvableDependencies resolvableDependencies) {
		if (this.dependencyManagementSettings.isApplyMavenExclusions()) {
			applyMavenExclusions(resolvableDependencies);
		}
	}

	private void applyMavenExclusions(ResolvableDependencies resolvableDependencies) {
		Set excludedDependencies = findExcludedDependencies();
		if (logger.isInfoEnabled()) {
			logger.info("Excluding " + excludedDependencies);
		}

		List> exclusions = new ArrayList>();
		for (DependencyCandidate excludedDependency : excludedDependencies) {
			Map exclusion = new HashMap();
			exclusion.put("group", excludedDependency.groupId);
			exclusion.put("module", excludedDependency.artifactId);
			exclusions.add(exclusion);
		}
		for (org.gradle.api.artifacts.Dependency dependency : resolvableDependencies.getDependencies()) {
			if (dependency instanceof ModuleDependency) {
				for (Map exclusion : exclusions) {
					((ModuleDependency) dependency).exclude(exclusion);
				}

			}

		}
	}

	private Set findExcludedDependencies() {
		DependencySet allDependencies = this.configuration.getAllDependencies();
		Configuration configurationCopy = this.configurationContainer.newConfiguration(this.configurationConfigurer,
				allDependencies.toArray(new org.gradle.api.artifacts.Dependency[allDependencies.size()]));
		ResolutionResult resolutionResult = configurationCopy.getIncoming().getResolutionResult();
		ResolvedComponentResult root = resolutionResult.getRoot();
		final Set excludedDependencies = new HashSet();
		resolutionResult.allDependencies(new Action() {
			@Override
			public void execute(DependencyResult dependencyResult) {
				if (dependencyResult instanceof ResolvedDependencyResult) {
					ResolvedDependencyResult resolved = (ResolvedDependencyResult) dependencyResult;
					excludedDependencies
							.add(new DependencyCandidate(resolved.getSelected().getModuleVersion().getGroup(),
									resolved.getSelected().getModuleVersion().getName()));
				}
				else if (dependencyResult instanceof UnresolvedDependencyResult) {
					DependencyCandidate dependencyCandidate = toDependencyCandidate(
							(UnresolvedDependencyResult) dependencyResult);
					if (dependencyCandidate != null) {
						excludedDependencies.add(dependencyCandidate);
					}
				}
			}
		});
		Set includedDependencies = determineIncludedComponents(root,
				this.exclusionResolver.resolveExclusions(resolutionResult.getAllComponents()));
		excludedDependencies.removeAll(includedDependencies);
		return excludedDependencies;
	}

	private Set determineIncludedComponents(ResolvedComponentResult root,
			Map pomExclusionsById) {
		LinkedList queue = new LinkedList();
		queue.add(new Node(root, getId(root), new HashSet()));
		Set seen = new HashSet();
		Set includedComponents = new HashSet();
		while (!queue.isEmpty()) {
			Node node = queue.remove();
			includedComponents.add(new DependencyCandidate(node.component.getModuleVersion().getGroup(),
					node.component.getModuleVersion().getName()));
			for (DependencyResult dependency : node.component.getDependencies()) {
				if (dependency instanceof ResolvedDependencyResult) {
					handleResolvedDependency((ResolvedDependencyResult) dependency, node, pomExclusionsById, queue,
							seen);
				}
				else if (dependency instanceof UnresolvedDependencyResult) {
					handleUnresolvedDependency((UnresolvedDependencyResult) dependency, node, includedComponents);
				}
			}
		}
		return includedComponents;
	}

	private void handleResolvedDependency(ResolvedDependencyResult dependency, Node node,
			Map pomExclusionsById, LinkedList queue, Set seen) {
		ResolvedComponentResult child = dependency.getSelected();
		String childId = getId(child);
		if (!node.excluded(childId) && seen.add(child)) {
			queue.add(new Node(child, childId, getChildExclusions(node, childId, pomExclusionsById)));
		}
	}

	private void handleUnresolvedDependency(UnresolvedDependencyResult dependency, Node node,
			Set includedComponents) {
		DependencyCandidate dependencyCandidate = toDependencyCandidate(dependency);
		if (dependencyCandidate != null
				&& (!node.excluded(dependencyCandidate.groupId + ":" + dependencyCandidate.artifactId))) {
			includedComponents.add(dependencyCandidate);
		}
	}

	private DependencyCandidate toDependencyCandidate(UnresolvedDependencyResult unresolved) {
		ComponentSelector attemptedSelector = unresolved.getAttempted();
		if (!(attemptedSelector instanceof ModuleComponentSelector)) {
			return null;
		}
		ModuleComponentSelector attemptedModuleSelector = (ModuleComponentSelector) attemptedSelector;
		return new DependencyCandidate(attemptedModuleSelector.getGroup(), attemptedModuleSelector.getModule());
	}

	private Set getChildExclusions(Node parent, String childId, Map pomExclusionsById) {
		Set childExclusions = new HashSet(parent.exclusions);
		addAllIfPossible(childExclusions,
				this.dependencyManagementContainer.getExclusions(this.configuration).exclusionsForDependency(childId));
		Exclusions exclusionsInPom = pomExclusionsById.get(parent.id);
		if (exclusionsInPom != null) {
			addAllIfPossible(childExclusions, exclusionsInPom.exclusionsForDependency(childId));
		}
		return childExclusions;
	}

	private void addAllIfPossible(Set current, Set addition) {
		if (addition != null) {
			current.addAll(addition);
		}

	}

	private String getId(ResolvedComponentResult component) {
		return component.getModuleVersion().getGroup() + ":" + component.getModuleVersion().getName();
	}

	private static final class Node {

		private final ResolvedComponentResult component;

		private final String id;

		private final Set exclusions;

		private Node(ResolvedComponentResult component, String id, Set exclusions) {
			this.component = component;
			this.id = id;
			this.exclusions = exclusions;
		}

		private boolean excluded(String id) {
			if (this.exclusions == null || this.exclusions.isEmpty()) {
				return false;
			}
			String[] components = id.split(":");
			for (Exclusion exclusion : this.exclusions) {
				if (matches(components[0], exclusion.getGroupId())
						&& matches(components[1], exclusion.getArtifactId())) {
					return true;
				}
			}
			return false;
		}

		private boolean matches(String candidate, String exclusion) {
			return exclusion.equals("*") || exclusion.equals(candidate);
		}

	}

	private static final class DependencyCandidate {

		private final String groupId;

		private final String artifactId;

		private DependencyCandidate(String groupId, String artifactId) {
			this.groupId = groupId;
			this.artifactId = artifactId;
		}

		@Override
		public boolean equals(Object o) {
			if (this == o) {
				return true;
			}
			if (o == null || getClass() != o.getClass()) {
				return false;
			}

			DependencyCandidate that = (DependencyCandidate) o;

			if (!this.groupId.equals(that.groupId)) {
				return false;
			}
			return this.artifactId.equals(that.artifactId);

		}

		@Override
		public int hashCode() {
			int result = this.groupId.hashCode();
			result = 31 * result + this.artifactId.hashCode();
			return result;
		}

		@Override
		public String toString() {
			return this.groupId + ":" + this.artifactId;
		}

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy