/*
* Copyright 2011 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.internal.artifacts.ivyservice.resolutionstrategy;
import org.gradle.api.Action;
import org.gradle.api.artifacts.ComponentSelection;
import org.gradle.api.artifacts.ComponentSelectionRules;
import org.gradle.api.artifacts.DependencyResolveDetails;
import org.gradle.api.artifacts.DependencySubstitution;
import org.gradle.api.artifacts.DependencySubstitutions;
import org.gradle.api.artifacts.ModuleVersionSelector;
import org.gradle.api.artifacts.ResolutionStrategy;
import org.gradle.api.artifacts.cache.ResolutionRules;
import org.gradle.api.internal.artifacts.ComponentSelectionRulesInternal;
import org.gradle.api.internal.artifacts.ImmutableModuleIdentifierFactory;
import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory;
import org.gradle.api.internal.artifacts.configurations.ConflictResolution;
import org.gradle.api.internal.artifacts.configurations.MutationValidator;
import org.gradle.api.internal.artifacts.configurations.ResolutionStrategyInternal;
import org.gradle.api.internal.artifacts.dsl.ModuleVersionSelectorParsers;
import org.gradle.api.internal.artifacts.ivyservice.dependencysubstitution.DefaultDependencySubstitutions;
import org.gradle.api.internal.artifacts.ivyservice.dependencysubstitution.DependencySubstitutionRules;
import org.gradle.api.internal.artifacts.ivyservice.dependencysubstitution.DependencySubstitutionsInternal;
import org.gradle.internal.Actions;
import org.gradle.internal.rules.SpecRuleAction;
import org.gradle.internal.typeconversion.NormalizedTimeUnit;
import org.gradle.internal.typeconversion.TimeUnitsParser;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.gradle.api.internal.artifacts.configurations.MutationValidator.MutationType.STRATEGY;
import static org.gradle.util.GUtil.flattenElements;
public class DefaultResolutionStrategy implements ResolutionStrategyInternal {
private final Set<ModuleVersionSelector> forcedModules = new LinkedHashSet<ModuleVersionSelector>();
private ConflictResolution conflictResolution = new LatestConflictResolution();
private final DefaultComponentSelectionRules componentSelectionRules;
private final DefaultCachePolicy cachePolicy;
private final DependencySubstitutionsInternal dependencySubstitutions;
private final DependencySubstitutionRules globalDependencySubstitutionRules;
private final ImmutableModuleIdentifierFactory moduleIdentifierFactory;
private MutationValidator mutationValidator = MutationValidator.IGNORE;
private boolean assumeFluidDependencies;
private SortOrder sortOrder = SortOrder.DEFAULT;
private static final String ASSUME_FLUID_DEPENDENCIES = "org.gradle.resolution.assumeFluidDependencies";
public DefaultResolutionStrategy(DependencySubstitutionRules globalDependencySubstitutionRules, ComponentIdentifierFactory componentIdentifierFactory, ImmutableModuleIdentifierFactory moduleIdentifierFactory) {
this(new DefaultCachePolicy(moduleIdentifierFactory), DefaultDependencySubstitutions.forResolutionStrategy(componentIdentifierFactory, moduleIdentifierFactory), globalDependencySubstitutionRules, moduleIdentifierFactory);
}
DefaultResolutionStrategy(DefaultCachePolicy cachePolicy, DependencySubstitutionsInternal dependencySubstitutions, DependencySubstitutionRules globalDependencySubstitutionRules, ImmutableModuleIdentifierFactory moduleIdentifierFactory) {
this.cachePolicy = cachePolicy;
this.dependencySubstitutions = dependencySubstitutions;
this.globalDependencySubstitutionRules = globalDependencySubstitutionRules;
this.moduleIdentifierFactory = moduleIdentifierFactory;
this.componentSelectionRules = new DefaultComponentSelectionRules(moduleIdentifierFactory);
// This is only used for testing purposes so we can test handling of fluid dependencies without adding dependency substitution rule
assumeFluidDependencies = Boolean.getBoolean(ASSUME_FLUID_DEPENDENCIES);
}
@Override
public void setMutationValidator(MutationValidator validator) {
mutationValidator = validator;
cachePolicy.setMutationValidator(validator);
componentSelectionRules.setMutationValidator(validator);
dependencySubstitutions.setMutationValidator(validator);
}
public Set<ModuleVersionSelector> getForcedModules() {
return Collections.unmodifiableSet(forcedModules);
}
public ResolutionStrategy failOnVersionConflict() {
mutationValidator.validateMutation(STRATEGY);
this.conflictResolution = new StrictConflictResolution();
return this;
}
public void preferProjectModules() {
if (this.conflictResolution instanceof LatestConflictResolution) {
this.conflictResolution = new PreferProjectModulesConflictResolution();
}
}
@Override
public void sortArtifacts(SortOrder sortOrder) {
this.sortOrder = sortOrder;
}
@Override
public SortOrder getSortOrder() {
return sortOrder;
}
public ConflictResolution getConflictResolution() {
return this.conflictResolution;
}
public ResolutionRules getResolutionRules() {
return cachePolicy;
}
public DefaultResolutionStrategy force(Object... moduleVersionSelectorNotations) {
mutationValidator.validateMutation(STRATEGY);
Set<ModuleVersionSelector> modules = ModuleVersionSelectorParsers.multiParser().parseNotation(moduleVersionSelectorNotations);
this.forcedModules.addAll(modules);
return this;
}
public ResolutionStrategy eachDependency(Action<? super DependencyResolveDetails> rule) {
mutationValidator.validateMutation(STRATEGY);
dependencySubstitutions.allWithDependencyResolveDetails(rule);
return this;
}
public Action<DependencySubstitution> getDependencySubstitutionRule() {
Collection<Action<DependencySubstitution>> allRules = flattenElements(
new ModuleForcingResolveRule(forcedModules, moduleIdentifierFactory),
dependencySubstitutions.getRuleAction(),
globalDependencySubstitutionRules.getRuleAction());
return Actions.composite(allRules);
}
public void assumeFluidDependencies() {
assumeFluidDependencies = true;
}
public boolean resolveGraphToDetermineTaskDependencies() {
return assumeFluidDependencies || dependencySubstitutions.hasRules() || globalDependencySubstitutionRules.hasRules();
}
public DefaultResolutionStrategy setForcedModules(Object ... moduleVersionSelectorNotations) {
mutationValidator.validateMutation(STRATEGY);
Set<ModuleVersionSelector> modules = ModuleVersionSelectorParsers.multiParser().parseNotation(moduleVersionSelectorNotations);
this.forcedModules.clear();
this.forcedModules.addAll(modules);
return this;
}
public DefaultCachePolicy getCachePolicy() {
return cachePolicy;
}
public void cacheDynamicVersionsFor(int value, String units) {
NormalizedTimeUnit timeUnit = new TimeUnitsParser().parseNotation(units, value);
cacheDynamicVersionsFor(timeUnit.getValue(), timeUnit.getTimeUnit());
}
public void cacheDynamicVersionsFor(int value, TimeUnit units) {
this.cachePolicy.cacheDynamicVersionsFor(value, units);
}
public void cacheChangingModulesFor(int value, String units) {
NormalizedTimeUnit timeUnit = new TimeUnitsParser().parseNotation(units, value);
cacheChangingModulesFor(timeUnit.getValue(), timeUnit.getTimeUnit());
}
public void cacheChangingModulesFor(int value, TimeUnit units) {
this.cachePolicy.cacheChangingModulesFor(value, units);
}
public ComponentSelectionRulesInternal getComponentSelection() {
return componentSelectionRules;
}
public ResolutionStrategy componentSelection(Action<? super ComponentSelectionRules> action) {
action.execute(componentSelectionRules);
return this;
}
public DependencySubstitutionsInternal getDependencySubstitution() {
return dependencySubstitutions;
}
public ResolutionStrategy dependencySubstitution(Action<? super DependencySubstitutions> action) {
action.execute(dependencySubstitutions);
return this;
}
public DefaultResolutionStrategy copy() {
DefaultResolutionStrategy out = new DefaultResolutionStrategy(cachePolicy.copy(), dependencySubstitutions.copy(), globalDependencySubstitutionRules, moduleIdentifierFactory);
if (conflictResolution instanceof StrictConflictResolution) {
out.failOnVersionConflict();
} else if (conflictResolution instanceof PreferProjectModulesConflictResolution) {
out.preferProjectModules();
}
out.setForcedModules(getForcedModules());
for (SpecRuleAction<? super ComponentSelection> ruleAction : componentSelectionRules.getRules()) {
out.getComponentSelection().addRule(ruleAction);
}
return out;
}
}