/* * Copyright 2013 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.ivyresolve; import org.gradle.api.artifacts.ComponentMetadata; import org.gradle.api.artifacts.ComponentSelection; import org.gradle.api.artifacts.ModuleVersionSelector; import org.gradle.api.artifacts.component.ModuleComponentIdentifier; import org.gradle.api.internal.artifacts.ComponentSelectionInternal; import org.gradle.api.internal.artifacts.ComponentSelectionRulesInternal; import org.gradle.api.internal.artifacts.DefaultComponentSelection; import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionComparator; import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelector; import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelectorScheme; import org.gradle.internal.component.model.ComponentResolveMetadata; import org.gradle.internal.resolve.result.BuildableComponentSelectionResult; import org.gradle.internal.resolve.result.BuildableModuleComponentMetaDataResolveResult; import org.gradle.internal.rules.SpecRuleAction; import org.gradle.util.CollectionUtils; import java.util.Collection; import java.util.Collections; import java.util.List; class DefaultVersionedComponentChooser implements VersionedComponentChooser { private final ComponentSelectionRulesProcessor rulesProcessor = new ComponentSelectionRulesProcessor(); private final VersionSelectorScheme versionSelectorScheme; private final VersionComparator versionComparator; private final ComponentSelectionRulesInternal componentSelectionRules; DefaultVersionedComponentChooser(VersionComparator versionComparator, VersionSelectorScheme versionSelectorScheme, ComponentSelectionRulesInternal componentSelectionRules) { this.versionComparator = versionComparator; this.versionSelectorScheme = versionSelectorScheme; this.componentSelectionRules = componentSelectionRules; } public ComponentResolveMetadata selectNewestComponent(ComponentResolveMetadata one, ComponentResolveMetadata two) { if (one == null || two == null) { return two == null ? one : two; } int comparison = versionComparator.compare(new VersionInfo(one.getId().getVersion()), new VersionInfo(two.getId().getVersion())); if (comparison == 0) { if (isGeneratedModuleDescriptor(one) && !isGeneratedModuleDescriptor(two)) { return two; } return one; } return comparison < 0 ? two : one; } private boolean isGeneratedModuleDescriptor(ComponentResolveMetadata componentResolveMetadata) { return componentResolveMetadata.isGenerated(); } public void selectNewestMatchingComponent(Collection<? extends ModuleComponentResolveState> versions, BuildableComponentSelectionResult result, ModuleVersionSelector requested) { VersionSelector requestedVersion = versionSelectorScheme.parseSelector(requested.getVersion()); Collection<SpecRuleAction<? super ComponentSelection>> rules = componentSelectionRules.getRules(); for (ModuleComponentResolveState candidate : sortLatestFirst(versions)) { MetadataProvider metadataProvider = createMetadataProvider(candidate); boolean versionMatches = versionMatches(requestedVersion, candidate, metadataProvider); if (!metadataProvider.isUsable()) { applyTo(metadataProvider, result); return; } String version = candidate.getVersion().getSource(); if (!versionMatches) { result.notMatched(version); continue; } ModuleComponentIdentifier candidateIdentifier = candidate.getId(); boolean accepted = !isRejectedByRules(candidateIdentifier, rules, metadataProvider); if (!metadataProvider.isUsable()) { applyTo(metadataProvider, result); return; } if (accepted) { result.matches(candidateIdentifier); return; } result.rejected(version); if (requestedVersion.matchesUniqueVersion()) { // Only consider one candidate break; } } result.noMatchFound(); } protected MetadataProvider createMetadataProvider(ModuleComponentResolveState candidate) { return new MetadataProvider(candidate); } private void applyTo(MetadataProvider provider, BuildableComponentSelectionResult result) { BuildableModuleComponentMetaDataResolveResult metaDataResult = provider.getResult(); switch (metaDataResult.getState()) { case Unknown: // For example, when using a local access to resolve something remote result.noMatchFound(); break; case Missing: result.noMatchFound(); break; case Failed: result.failed(metaDataResult.getFailure()); break; default: throw new IllegalStateException("Unexpected meta-data resolution result."); } } private boolean versionMatches(VersionSelector selector, ModuleComponentResolveState component, MetadataProvider metadataProvider) { if (selector.requiresMetadata()) { ComponentMetadata componentMetadata = metadataProvider.getComponentMetadata(); return componentMetadata != null && selector.accept(componentMetadata); } else { return selector.accept(component.getVersion()); } } public boolean isRejectedComponent(ModuleComponentIdentifier candidateIdentifier, MetadataProvider metadataProvider) { return isRejectedByRules(candidateIdentifier, componentSelectionRules.getRules(), metadataProvider); } private boolean isRejectedByRules(ModuleComponentIdentifier candidateIdentifier, Collection<SpecRuleAction<? super ComponentSelection>> rules, MetadataProvider metadataProvider) { ComponentSelectionInternal selection = new DefaultComponentSelection(candidateIdentifier); rulesProcessor.apply(selection, rules, metadataProvider); return selection.isRejected(); } private List<ModuleComponentResolveState> sortLatestFirst(Collection<? extends ModuleComponentResolveState> listing) { return CollectionUtils.sort(listing, Collections.reverseOrder(versionComparator)); } }