http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java ---------------------------------------------------------------------- diff --git a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java deleted file mode 100644 index 5f9d8e0..0000000 --- a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java +++ /dev/null @@ -1,1327 +0,0 @@ -package org.eclipse.aether.util.graph.transformer; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; - -import org.eclipse.aether.RepositoryException; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.collection.DependencyGraphTransformationContext; -import org.eclipse.aether.collection.DependencyGraphTransformer; -import org.eclipse.aether.graph.DefaultDependencyNode; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.graph.DependencyNode; -import org.eclipse.aether.util.ConfigUtils; - -/** - * A dependency graph transformer that resolves version and scope conflicts among dependencies. For a given set of - * conflicting nodes, one node will be chosen as the winner and the other nodes are removed from the dependency graph. - * The exact rules by which a winning node and its effective scope are determined are controlled by user-supplied - * implementations of {@link VersionSelector}, {@link ScopeSelector}, {@link OptionalitySelector} and - * {@link ScopeDeriver}. - * <p> - * By default, this graph transformer will turn the dependency graph into a tree without duplicate artifacts. Using the - * configuration property {@link #CONFIG_PROP_VERBOSE}, a verbose mode can be enabled where the graph is still turned - * into a tree but all nodes participating in a conflict are retained. The nodes that were rejected during conflict - * resolution have no children and link back to the winner node via the {@link #NODE_DATA_WINNER} key in their custom - * data. Additionally, the keys {@link #NODE_DATA_ORIGINAL_SCOPE} and {@link #NODE_DATA_ORIGINAL_OPTIONALITY} are used - * to store the original scope and optionality of each node. Obviously, the resulting dependency tree is not suitable - * for artifact resolution unless a filter is employed to exclude the duplicate dependencies. - * <p> - * This transformer will query the keys {@link TransformationContextKeys#CONFLICT_IDS}, - * {@link TransformationContextKeys#SORTED_CONFLICT_IDS}, {@link TransformationContextKeys#CYCLIC_CONFLICT_IDS} for - * existing information about conflict ids. In absence of this information, it will automatically invoke the - * {@link ConflictIdSorter} to calculate it. - */ -public final class ConflictResolver - implements DependencyGraphTransformer -{ - - /** - * The key in the repository session's {@link RepositorySystemSession#getConfigProperties() configuration - * properties} used to store a {@link Boolean} flag controlling the transformer's verbose mode. - */ - public static final String CONFIG_PROP_VERBOSE = "aether.conflictResolver.verbose"; - - /** - * The key in the dependency node's {@link DependencyNode#getData() custom data} under which a reference to the - * {@link DependencyNode} which has won the conflict is stored. - */ - public static final String NODE_DATA_WINNER = "conflict.winner"; - - /** - * The key in the dependency node's {@link DependencyNode#getData() custom data} under which the scope of the - * dependency before scope derivation and conflict resolution is stored. - */ - public static final String NODE_DATA_ORIGINAL_SCOPE = "conflict.originalScope"; - - /** - * The key in the dependency node's {@link DependencyNode#getData() custom data} under which the optional flag of - * the dependency before derivation and conflict resolution is stored. - */ - public static final String NODE_DATA_ORIGINAL_OPTIONALITY = "conflict.originalOptionality"; - - private final VersionSelector versionSelector; - - private final ScopeSelector scopeSelector; - - private final ScopeDeriver scopeDeriver; - - private final OptionalitySelector optionalitySelector; - - /** - * Creates a new conflict resolver instance with the specified hooks. - * - * @param versionSelector The version selector to use, must not be {@code null}. - * @param scopeSelector The scope selector to use, must not be {@code null}. - * @param optionalitySelector The optionality selector ot use, must not be {@code null}. - * @param scopeDeriver The scope deriver to use, must not be {@code null}. - */ - public ConflictResolver( VersionSelector versionSelector, ScopeSelector scopeSelector, - OptionalitySelector optionalitySelector, ScopeDeriver scopeDeriver ) - { - if ( versionSelector == null ) - { - throw new IllegalArgumentException( "version selector not specified" ); - } - this.versionSelector = versionSelector; - if ( scopeSelector == null ) - { - throw new IllegalArgumentException( "scope selector not specified" ); - } - this.scopeSelector = scopeSelector; - if ( scopeDeriver == null ) - { - throw new IllegalArgumentException( "scope deriver not specified" ); - } - this.scopeDeriver = scopeDeriver; - if ( optionalitySelector == null ) - { - throw new IllegalArgumentException( "optionality selector not specified" ); - } - this.optionalitySelector = optionalitySelector; - } - - public DependencyNode transformGraph( DependencyNode node, DependencyGraphTransformationContext context ) - throws RepositoryException - { - List<?> sortedConflictIds = (List<?>) context.get( TransformationContextKeys.SORTED_CONFLICT_IDS ); - if ( sortedConflictIds == null ) - { - ConflictIdSorter sorter = new ConflictIdSorter(); - sorter.transformGraph( node, context ); - - sortedConflictIds = (List<?>) context.get( TransformationContextKeys.SORTED_CONFLICT_IDS ); - } - - @SuppressWarnings( "unchecked" ) - Map<String, Object> stats = (Map<String, Object>) context.get( TransformationContextKeys.STATS ); - long time1 = System.currentTimeMillis(); - - @SuppressWarnings( "unchecked" ) - Collection<Collection<?>> conflictIdCycles = - (Collection<Collection<?>>) context.get( TransformationContextKeys.CYCLIC_CONFLICT_IDS ); - if ( conflictIdCycles == null ) - { - throw new RepositoryException( "conflict id cycles have not been identified" ); - } - - Map<?, ?> conflictIds = (Map<?, ?>) context.get( TransformationContextKeys.CONFLICT_IDS ); - if ( conflictIds == null ) - { - throw new RepositoryException( "conflict groups have not been identified" ); - } - - Map<Object, Collection<Object>> cyclicPredecessors = new HashMap<Object, Collection<Object>>(); - for ( Collection<?> cycle : conflictIdCycles ) - { - for ( Object conflictId : cycle ) - { - Collection<Object> predecessors = cyclicPredecessors.get( conflictId ); - if ( predecessors == null ) - { - predecessors = new HashSet<Object>(); - cyclicPredecessors.put( conflictId, predecessors ); - } - predecessors.addAll( cycle ); - } - } - - State state = new State( node, conflictIds, sortedConflictIds.size(), context ); - for ( Iterator<?> it = sortedConflictIds.iterator(); it.hasNext(); ) - { - Object conflictId = it.next(); - - // reset data structures for next graph walk - state.prepare( conflictId, cyclicPredecessors.get( conflictId ) ); - - // find nodes with the current conflict id and while walking the graph (more deeply), nuke leftover losers - gatherConflictItems( node, state ); - - // now that we know the min depth of the parents, update depth of conflict items - state.finish(); - - // earlier runs might have nuked all parents of the current conflict id, so it might not exist anymore - if ( !state.items.isEmpty() ) - { - ConflictContext ctx = state.conflictCtx; - state.versionSelector.selectVersion( ctx ); - if ( ctx.winner == null ) - { - throw new RepositoryException( "conflict resolver did not select winner among " + state.items ); - } - DependencyNode winner = ctx.winner.node; - - state.scopeSelector.selectScope( ctx ); - if ( state.verbose ) - { - winner.setData( NODE_DATA_ORIGINAL_SCOPE, winner.getDependency().getScope() ); - } - winner.setScope( ctx.scope ); - - state.optionalitySelector.selectOptionality( ctx ); - if ( state.verbose ) - { - winner.setData( NODE_DATA_ORIGINAL_OPTIONALITY, winner.getDependency().isOptional() ); - } - winner.setOptional( ctx.optional ); - - removeLosers( state ); - } - - // record the winner so we can detect leftover losers during future graph walks - state.winner(); - - // in case of cycles, trigger final graph walk to ensure all leftover losers are gone - if ( !it.hasNext() && !conflictIdCycles.isEmpty() && state.conflictCtx.winner != null ) - { - DependencyNode winner = state.conflictCtx.winner.node; - state.prepare( state, null ); - gatherConflictItems( winner, state ); - } - } - - if ( stats != null ) - { - long time2 = System.currentTimeMillis(); - stats.put( "ConflictResolver.totalTime", time2 - time1 ); - stats.put( "ConflictResolver.conflictItemCount", state.totalConflictItems ); - } - - return node; - } - - private boolean gatherConflictItems( DependencyNode node, State state ) - throws RepositoryException - { - Object conflictId = state.conflictIds.get( node ); - if ( state.currentId.equals( conflictId ) ) - { - // found it, add conflict item (if not already done earlier by another path) - state.add( node ); - // we don't recurse here so we might miss losers beneath us, those will be nuked during future walks below - } - else if ( state.loser( node, conflictId ) ) - { - // found a leftover loser (likely in a cycle) of an already processed conflict id, tell caller to nuke it - return false; - } - else if ( state.push( node, conflictId ) ) - { - // found potential parent, no cycle and not visisted before with the same derived scope, so recurse - for ( Iterator<DependencyNode> it = node.getChildren().iterator(); it.hasNext(); ) - { - DependencyNode child = it.next(); - if ( !gatherConflictItems( child, state ) ) - { - it.remove(); - } - } - state.pop(); - } - return true; - } - - private void removeLosers( State state ) - { - ConflictItem winner = state.conflictCtx.winner; - List<DependencyNode> previousParent = null; - ListIterator<DependencyNode> childIt = null; - boolean conflictVisualized = false; - for ( ConflictItem item : state.items ) - { - if ( item == winner ) - { - continue; - } - if ( item.parent != previousParent ) - { - childIt = item.parent.listIterator(); - previousParent = item.parent; - conflictVisualized = false; - } - while ( childIt.hasNext() ) - { - DependencyNode child = childIt.next(); - if ( child == item.node ) - { - if ( state.verbose && !conflictVisualized && item.parent != winner.parent ) - { - conflictVisualized = true; - DependencyNode loser = new DefaultDependencyNode( child ); - loser.setData( NODE_DATA_WINNER, winner.node ); - loser.setData( NODE_DATA_ORIGINAL_SCOPE, loser.getDependency().getScope() ); - loser.setData( NODE_DATA_ORIGINAL_OPTIONALITY, loser.getDependency().isOptional() ); - loser.setScope( item.getScopes().iterator().next() ); - loser.setChildren( Collections.<DependencyNode>emptyList() ); - childIt.set( loser ); - } - else - { - childIt.remove(); - } - break; - } - } - } - // there might still be losers beneath the winner (e.g. in case of cycles) - // those will be nuked during future graph walks when we include the winner in the recursion - } - - static final class NodeInfo - { - - /** - * The smallest depth at which the node was seen, used for "the" depth of its conflict items. - */ - int minDepth; - - /** - * The set of derived scopes the node was visited with, used to check whether an already seen node needs to be - * revisited again in context of another scope. To conserve memory, we start with {@code String} and update to - * {@code Set<String>} if needed. - */ - Object derivedScopes; - - /** - * The set of derived optionalities the node was visited with, used to check whether an already seen node needs - * to be revisited again in context of another optionality. To conserve memory, encoded as bit field (bit 0 -> - * optional=false, bit 1 -> optional=true). - */ - int derivedOptionalities; - - /** - * The conflict items which are immediate children of the node, used to easily update those conflict items after - * a new parent scope/optionality was encountered. - */ - List<ConflictItem> children; - - static final int CHANGE_SCOPE = 0x01; - - static final int CHANGE_OPTIONAL = 0x02; - - private static final int OPT_FALSE = 0x01; - - private static final int OPT_TRUE = 0x02; - - NodeInfo( int depth, String derivedScope, boolean optional ) - { - minDepth = depth; - derivedScopes = derivedScope; - derivedOptionalities = optional ? OPT_TRUE : OPT_FALSE; - } - - @SuppressWarnings( "unchecked" ) - int update( int depth, String derivedScope, boolean optional ) - { - if ( depth < minDepth ) - { - minDepth = depth; - } - int changes; - if ( derivedScopes.equals( derivedScope ) ) - { - changes = 0; - } - else if ( derivedScopes instanceof Collection ) - { - changes = ( (Collection<String>) derivedScopes ).add( derivedScope ) ? CHANGE_SCOPE : 0; - } - else - { - Collection<String> scopes = new HashSet<String>(); - scopes.add( (String) derivedScopes ); - scopes.add( derivedScope ); - derivedScopes = scopes; - changes = CHANGE_SCOPE; - } - int bit = optional ? OPT_TRUE : OPT_FALSE; - if ( ( derivedOptionalities & bit ) == 0 ) - { - derivedOptionalities |= bit; - changes |= CHANGE_OPTIONAL; - } - return changes; - } - - void add( ConflictItem item ) - { - if ( children == null ) - { - children = new ArrayList<ConflictItem>( 1 ); - } - children.add( item ); - } - - } - - final class State - { - - /** - * The conflict id currently processed. - */ - Object currentId; - - /** - * Stats counter. - */ - int totalConflictItems; - - /** - * Flag whether we should keep losers in the graph to enable visualization/troubleshooting of conflicts. - */ - final boolean verbose; - - /** - * A mapping from conflict id to winner node, helps to recognize nodes that have their effective - * scope&optionality set or are leftovers from previous removals. - */ - final Map<Object, DependencyNode> resolvedIds; - - /** - * The set of conflict ids which could apply to ancestors of nodes with the current conflict id, used to avoid - * recursion early on. This is basically a superset of the key set of resolvedIds, the additional ids account - * for cyclic dependencies. - */ - final Collection<Object> potentialAncestorIds; - - /** - * The output from the conflict marker - */ - final Map<?, ?> conflictIds; - - /** - * The conflict items we have gathered so far for the current conflict id. - */ - final List<ConflictItem> items; - - /** - * The (conceptual) mapping from nodes to extra infos, technically keyed by the node's child list which better - * captures the identity of a node since we're basically concerned with effects towards children. - */ - final Map<List<DependencyNode>, NodeInfo> infos; - - /** - * The set of nodes on the DFS stack to detect cycles, technically keyed by the node's child list to match the - * dirty graph structure produced by the dependency collector for cycles. - */ - final Map<List<DependencyNode>, Object> stack; - - /** - * The stack of parent nodes. - */ - final List<DependencyNode> parentNodes; - - /** - * The stack of derived scopes for parent nodes. - */ - final List<String> parentScopes; - - /** - * The stack of derived optional flags for parent nodes. - */ - final List<Boolean> parentOptionals; - - /** - * The stack of node infos for parent nodes, may contain {@code null} which is used to disable creating new - * conflict items when visiting their parent again (conflict items are meant to be unique by parent-node combo). - */ - final List<NodeInfo> parentInfos; - - /** - * The conflict context passed to the version/scope/optionality selectors, updated as we move along rather than - * recreated to avoid tmp objects. - */ - final ConflictContext conflictCtx; - - /** - * The scope context passed to the scope deriver, updated as we move along rather than recreated to avoid tmp - * objects. - */ - final ScopeContext scopeCtx; - - /** - * The effective version selector, i.e. after initialization. - */ - final VersionSelector versionSelector; - - /** - * The effective scope selector, i.e. after initialization. - */ - final ScopeSelector scopeSelector; - - /** - * The effective scope deriver, i.e. after initialization. - */ - final ScopeDeriver scopeDeriver; - - /** - * The effective optionality selector, i.e. after initialization. - */ - final OptionalitySelector optionalitySelector; - - State( DependencyNode root, Map<?, ?> conflictIds, int conflictIdCount, - DependencyGraphTransformationContext context ) - throws RepositoryException - { - this.conflictIds = conflictIds; - verbose = ConfigUtils.getBoolean( context.getSession(), false, CONFIG_PROP_VERBOSE ); - potentialAncestorIds = new HashSet<Object>( conflictIdCount * 2 ); - resolvedIds = new HashMap<Object, DependencyNode>( conflictIdCount * 2 ); - items = new ArrayList<ConflictItem>( 256 ); - infos = new IdentityHashMap<List<DependencyNode>, NodeInfo>( 64 ); - stack = new IdentityHashMap<List<DependencyNode>, Object>( 64 ); - parentNodes = new ArrayList<DependencyNode>( 64 ); - parentScopes = new ArrayList<String>( 64 ); - parentOptionals = new ArrayList<Boolean>( 64 ); - parentInfos = new ArrayList<NodeInfo>( 64 ); - conflictCtx = new ConflictContext( root, conflictIds, items ); - scopeCtx = new ScopeContext( null, null ); - versionSelector = ConflictResolver.this.versionSelector.getInstance( root, context ); - scopeSelector = ConflictResolver.this.scopeSelector.getInstance( root, context ); - scopeDeriver = ConflictResolver.this.scopeDeriver.getInstance( root, context ); - optionalitySelector = ConflictResolver.this.optionalitySelector.getInstance( root, context ); - } - - void prepare( Object conflictId, Collection<Object> cyclicPredecessors ) - { - currentId = conflictCtx.conflictId = conflictId; - conflictCtx.winner = null; - conflictCtx.scope = null; - conflictCtx.optional = null; - items.clear(); - infos.clear(); - if ( cyclicPredecessors != null ) - { - potentialAncestorIds.addAll( cyclicPredecessors ); - } - } - - void finish() - { - List<DependencyNode> previousParent = null; - int previousDepth = 0; - totalConflictItems += items.size(); - for ( int i = items.size() - 1; i >= 0; i-- ) - { - ConflictItem item = items.get( i ); - if ( item.parent == previousParent ) - { - item.depth = previousDepth; - } - else if ( item.parent != null ) - { - previousParent = item.parent; - NodeInfo info = infos.get( previousParent ); - previousDepth = info.minDepth + 1; - item.depth = previousDepth; - } - } - potentialAncestorIds.add( currentId ); - } - - void winner() - { - resolvedIds.put( currentId, ( conflictCtx.winner != null ) ? conflictCtx.winner.node : null ); - } - - boolean loser( DependencyNode node, Object conflictId ) - { - DependencyNode winner = resolvedIds.get( conflictId ); - return winner != null && winner != node; - } - - boolean push( DependencyNode node, Object conflictId ) - throws RepositoryException - { - if ( conflictId == null ) - { - if ( node.getDependency() != null ) - { - if ( node.getData().get( NODE_DATA_WINNER ) != null ) - { - return false; - } - throw new RepositoryException( "missing conflict id for node " + node ); - } - } - else if ( !potentialAncestorIds.contains( conflictId ) ) - { - return false; - } - - List<DependencyNode> graphNode = node.getChildren(); - if ( stack.put( graphNode, Boolean.TRUE ) != null ) - { - return false; - } - - int depth = depth(); - String scope = deriveScope( node, conflictId ); - boolean optional = deriveOptional( node, conflictId ); - NodeInfo info = infos.get( graphNode ); - if ( info == null ) - { - info = new NodeInfo( depth, scope, optional ); - infos.put( graphNode, info ); - parentInfos.add( info ); - parentNodes.add( node ); - parentScopes.add( scope ); - parentOptionals.add( optional ); - } - else - { - int changes = info.update( depth, scope, optional ); - if ( changes == 0 ) - { - stack.remove( graphNode ); - return false; - } - parentInfos.add( null ); // disable creating new conflict items, we update the existing ones below - parentNodes.add( node ); - parentScopes.add( scope ); - parentOptionals.add( optional ); - if ( info.children != null ) - { - if ( ( changes & NodeInfo.CHANGE_SCOPE ) != 0 ) - { - for ( int i = info.children.size() - 1; i >= 0; i-- ) - { - ConflictItem item = info.children.get( i ); - String childScope = deriveScope( item.node, null ); - item.addScope( childScope ); - } - } - if ( ( changes & NodeInfo.CHANGE_OPTIONAL ) != 0 ) - { - for ( int i = info.children.size() - 1; i >= 0; i-- ) - { - ConflictItem item = info.children.get( i ); - boolean childOptional = deriveOptional( item.node, null ); - item.addOptional( childOptional ); - } - } - } - } - - return true; - } - - void pop() - { - int last = parentInfos.size() - 1; - parentInfos.remove( last ); - parentScopes.remove( last ); - parentOptionals.remove( last ); - DependencyNode node = parentNodes.remove( last ); - stack.remove( node.getChildren() ); - } - - void add( DependencyNode node ) - throws RepositoryException - { - DependencyNode parent = parent(); - if ( parent == null ) - { - ConflictItem item = newConflictItem( parent, node ); - items.add( item ); - } - else - { - NodeInfo info = parentInfos.get( parentInfos.size() - 1 ); - if ( info != null ) - { - ConflictItem item = newConflictItem( parent, node ); - info.add( item ); - items.add( item ); - } - } - } - - private ConflictItem newConflictItem( DependencyNode parent, DependencyNode node ) - throws RepositoryException - { - return new ConflictItem( parent, node, deriveScope( node, null ), deriveOptional( node, null ) ); - } - - private int depth() - { - return parentNodes.size(); - } - - private DependencyNode parent() - { - int size = parentNodes.size(); - return ( size <= 0 ) ? null : parentNodes.get( size - 1 ); - } - - private String deriveScope( DependencyNode node, Object conflictId ) - throws RepositoryException - { - if ( ( node.getManagedBits() & DependencyNode.MANAGED_SCOPE ) != 0 - || ( conflictId != null && resolvedIds.containsKey( conflictId ) ) ) - { - return scope( node.getDependency() ); - } - - int depth = parentNodes.size(); - scopes( depth, node.getDependency() ); - if ( depth > 0 ) - { - scopeDeriver.deriveScope( scopeCtx ); - } - return scopeCtx.derivedScope; - } - - private void scopes( int parent, Dependency child ) - { - scopeCtx.parentScope = ( parent > 0 ) ? parentScopes.get( parent - 1 ) : null; - scopeCtx.derivedScope = scopeCtx.childScope = scope( child ); - } - - private String scope( Dependency dependency ) - { - return ( dependency != null ) ? dependency.getScope() : null; - } - - private boolean deriveOptional( DependencyNode node, Object conflictId ) - { - Dependency dep = node.getDependency(); - boolean optional = ( dep != null ) ? dep.isOptional() : false; - if ( optional || ( node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL ) != 0 - || ( conflictId != null && resolvedIds.containsKey( conflictId ) ) ) - { - return optional; - } - int depth = parentNodes.size(); - return ( depth > 0 ) ? parentOptionals.get( depth - 1 ) : false; - } - - } - - /** - * A context used to hold information that is relevant for deriving the scope of a child dependency. - * - * @see ScopeDeriver - * @noinstantiate This class is not intended to be instantiated by clients in production code, the constructor may - * change without notice and only exists to enable unit testing. - */ - public static final class ScopeContext - { - - String parentScope; - - String childScope; - - String derivedScope; - - /** - * Creates a new scope context with the specified properties. - * - * @param parentScope The scope of the parent dependency, may be {@code null}. - * @param childScope The scope of the child dependency, may be {@code null}. - * @noreference This class is not intended to be instantiated by clients in production code, the constructor may - * change without notice and only exists to enable unit testing. - */ - public ScopeContext( String parentScope, String childScope ) - { - this.parentScope = ( parentScope != null ) ? parentScope : ""; - derivedScope = this.childScope = ( childScope != null ) ? childScope : ""; - } - - /** - * Gets the scope of the parent dependency. This is usually the scope that was derived by earlier invocations of - * the scope deriver. - * - * @return The scope of the parent dependency, never {@code null}. - */ - public String getParentScope() - { - return parentScope; - } - - /** - * Gets the original scope of the child dependency. This is the scope that was declared in the artifact - * descriptor of the parent dependency. - * - * @return The original scope of the child dependency, never {@code null}. - */ - public String getChildScope() - { - return childScope; - } - - /** - * Gets the derived scope of the child dependency. This is initially equal to {@link #getChildScope()} until the - * scope deriver makes changes. - * - * @return The derived scope of the child dependency, never {@code null}. - */ - public String getDerivedScope() - { - return derivedScope; - } - - /** - * Sets the derived scope of the child dependency. - * - * @param derivedScope The derived scope of the dependency, may be {@code null}. - */ - public void setDerivedScope( String derivedScope ) - { - this.derivedScope = ( derivedScope != null ) ? derivedScope : ""; - } - - } - - /** - * A conflicting dependency. - * - * @noinstantiate This class is not intended to be instantiated by clients in production code, the constructor may - * change without notice and only exists to enable unit testing. - */ - public static final class ConflictItem - { - - // nodes can share child lists, we care about the unique owner of a child node which is the child list - final List<DependencyNode> parent; - - // only for debugging/toString() to help identify the parent node(s) - final Artifact artifact; - - final DependencyNode node; - - int depth; - - // we start with String and update to Set<String> if needed - Object scopes; - - // bit field of OPTIONAL_FALSE and OPTIONAL_TRUE - int optionalities; - - /** - * Bit flag indicating whether one or more paths consider the dependency non-optional. - */ - public static final int OPTIONAL_FALSE = 0x01; - - /** - * Bit flag indicating whether one or more paths consider the dependency optional. - */ - public static final int OPTIONAL_TRUE = 0x02; - - ConflictItem( DependencyNode parent, DependencyNode node, String scope, boolean optional ) - { - if ( parent != null ) - { - this.parent = parent.getChildren(); - this.artifact = parent.getArtifact(); - } - else - { - this.parent = null; - this.artifact = null; - } - this.node = node; - this.scopes = scope; - this.optionalities = optional ? OPTIONAL_TRUE : OPTIONAL_FALSE; - } - - /** - * Creates a new conflict item with the specified properties. - * - * @param parent The parent node of the conflicting dependency, may be {@code null}. - * @param node The conflicting dependency, must not be {@code null}. - * @param depth The zero-based depth of the conflicting dependency. - * @param optionalities The optionalities the dependency was encountered with, encoded as a bit field consisting - * of {@link ConflictResolver.ConflictItem#OPTIONAL_TRUE} and - * {@link ConflictResolver.ConflictItem#OPTIONAL_FALSE}. - * @param scopes The derived scopes of the conflicting dependency, must not be {@code null}. - * @noreference This class is not intended to be instantiated by clients in production code, the constructor may - * change without notice and only exists to enable unit testing. - */ - public ConflictItem( DependencyNode parent, DependencyNode node, int depth, int optionalities, String... scopes ) - { - this.parent = ( parent != null ) ? parent.getChildren() : null; - this.artifact = ( parent != null ) ? parent.getArtifact() : null; - this.node = node; - this.depth = depth; - this.optionalities = optionalities; - this.scopes = Arrays.asList( scopes ); - } - - /** - * Determines whether the specified conflict item is a sibling of this item. - * - * @param item The other conflict item, must not be {@code null}. - * @return {@code true} if the given item has the same parent as this item, {@code false} otherwise. - */ - public boolean isSibling( ConflictItem item ) - { - return parent == item.parent; - } - - /** - * Gets the dependency node involved in the conflict. - * - * @return The involved dependency node, never {@code null}. - */ - public DependencyNode getNode() - { - return node; - } - - /** - * Gets the dependency involved in the conflict, short for {@code getNode.getDependency()}. - * - * @return The involved dependency, never {@code null}. - */ - public Dependency getDependency() - { - return node.getDependency(); - } - - /** - * Gets the zero-based depth at which the conflicting node occurs in the graph. As such, the depth denotes the - * number of parent nodes. If actually multiple paths lead to the node, the return value denotes the smallest - * possible depth. - * - * @return The zero-based depth of the node in the graph. - */ - public int getDepth() - { - return depth; - } - - /** - * Gets the derived scopes of the dependency. In general, the same dependency node could be reached via - * different paths and each path might result in a different derived scope. - * - * @see ScopeDeriver - * @return The (read-only) set of derived scopes of the dependency, never {@code null}. - */ - @SuppressWarnings( "unchecked" ) - public Collection<String> getScopes() - { - if ( scopes instanceof String ) - { - return Collections.singleton( (String) scopes ); - } - return (Collection<String>) scopes; - } - - @SuppressWarnings( "unchecked" ) - void addScope( String scope ) - { - if ( scopes instanceof Collection ) - { - ( (Collection<String>) scopes ).add( scope ); - } - else if ( !scopes.equals( scope ) ) - { - Collection<Object> set = new HashSet<Object>(); - set.add( scopes ); - set.add( scope ); - scopes = set; - } - } - - /** - * Gets the derived optionalities of the dependency. In general, the same dependency node could be reached via - * different paths and each path might result in a different derived optionality. - * - * @return A bit field consisting of {@link ConflictResolver.ConflictItem#OPTIONAL_FALSE} and/or - * {@link ConflictResolver.ConflictItem#OPTIONAL_TRUE} indicating the derived optionalities the - * dependency was encountered with. - */ - public int getOptionalities() - { - return optionalities; - } - - void addOptional( boolean optional ) - { - optionalities |= optional ? OPTIONAL_TRUE : OPTIONAL_FALSE; - } - - @Override - public String toString() - { - return node + " @ " + depth + " < " + artifact; - } - - } - - /** - * A context used to hold information that is relevant for resolving version and scope conflicts. - * - * @see VersionSelector - * @see ScopeSelector - * @noinstantiate This class is not intended to be instantiated by clients in production code, the constructor may - * change without notice and only exists to enable unit testing. - */ - public static final class ConflictContext - { - - final DependencyNode root; - - final Map<?, ?> conflictIds; - - final Collection<ConflictItem> items; - - Object conflictId; - - ConflictItem winner; - - String scope; - - Boolean optional; - - ConflictContext( DependencyNode root, Map<?, ?> conflictIds, Collection<ConflictItem> items ) - { - this.root = root; - this.conflictIds = conflictIds; - this.items = Collections.unmodifiableCollection( items ); - } - - /** - * Creates a new conflict context. - * - * @param root The root node of the dependency graph, must not be {@code null}. - * @param conflictId The conflict id for the set of conflicting dependencies in this context, must not be - * {@code null}. - * @param conflictIds The mapping from dependency node to conflict id, must not be {@code null}. - * @param items The conflict items in this context, must not be {@code null}. - * @noreference This class is not intended to be instantiated by clients in production code, the constructor may - * change without notice and only exists to enable unit testing. - */ - public ConflictContext( DependencyNode root, Object conflictId, Map<DependencyNode, Object> conflictIds, - Collection<ConflictItem> items ) - { - this( root, conflictIds, items ); - this.conflictId = conflictId; - } - - /** - * Gets the root node of the dependency graph being transformed. - * - * @return The root node of the dependeny graph, never {@code null}. - */ - public DependencyNode getRoot() - { - return root; - } - - /** - * Determines whether the specified dependency node belongs to this conflict context. - * - * @param node The dependency node to check, must not be {@code null}. - * @return {@code true} if the given node belongs to this conflict context, {@code false} otherwise. - */ - public boolean isIncluded( DependencyNode node ) - { - return conflictId.equals( conflictIds.get( node ) ); - } - - /** - * Gets the collection of conflict items in this context. - * - * @return The (read-only) collection of conflict items in this context, never {@code null}. - */ - public Collection<ConflictItem> getItems() - { - return items; - } - - /** - * Gets the conflict item which has been selected as the winner among the conflicting dependencies. - * - * @return The winning conflict item or {@code null} if not set yet. - */ - public ConflictItem getWinner() - { - return winner; - } - - /** - * Sets the conflict item which has been selected as the winner among the conflicting dependencies. - * - * @param winner The winning conflict item, may be {@code null}. - */ - public void setWinner( ConflictItem winner ) - { - this.winner = winner; - } - - /** - * Gets the effective scope of the winning dependency. - * - * @return The effective scope of the winning dependency or {@code null} if none. - */ - public String getScope() - { - return scope; - } - - /** - * Sets the effective scope of the winning dependency. - * - * @param scope The effective scope, may be {@code null}. - */ - public void setScope( String scope ) - { - this.scope = scope; - } - - /** - * Gets the effective optional flag of the winning dependency. - * - * @return The effective optional flag or {@code null} if none. - */ - public Boolean getOptional() - { - return optional; - } - - /** - * Sets the effective optional flag of the winning dependency. - * - * @param optional The effective optional flag, may be {@code null}. - */ - public void setOptional( Boolean optional ) - { - this.optional = optional; - } - - @Override - public String toString() - { - return winner + " @ " + scope + " < " + items; - } - - } - - /** - * An extension point of {@link ConflictResolver} that determines the winner among conflicting dependencies. The - * winning node (and its children) will be retained in the dependency graph, the other nodes will get removed. The - * version selector does not need to deal with potential scope conflicts, these will be addressed afterwards by the - * {@link ScopeSelector}. - * <p> - * <strong>Note:</strong> Implementations must be stateless. - */ - public abstract static class VersionSelector - { - - /** - * Retrieves the version selector for use during the specified graph transformation. The conflict resolver calls - * this method once per - * {@link ConflictResolver#transformGraph(DependencyNode, DependencyGraphTransformationContext)} invocation to - * allow implementations to prepare any auxiliary data that is needed for their operation. Given that - * implementations must be stateless, a new instance needs to be returned to hold such auxiliary data. The - * default implementation simply returns the current instance which is appropriate for implementations which do - * not require auxiliary data. - * - * @param root The root node of the (possibly cyclic!) graph to transform, must not be {@code null}. - * @param context The graph transformation context, must not be {@code null}. - * @return The scope deriver to use for the given graph transformation, never {@code null}. - * @throws RepositoryException If the instance could not be retrieved. - */ - public VersionSelector getInstance( DependencyNode root, DependencyGraphTransformationContext context ) - throws RepositoryException - { - return this; - } - - /** - * Determines the winning node among conflicting dependencies. Implementations will usually iterate - * {@link ConflictContext#getItems()}, inspect {@link ConflictItem#getNode()} and eventually call - * {@link ConflictContext#setWinner(ConflictResolver.ConflictItem)} to deliver the winner. Failure to select a - * winner will automatically fail the entire conflict resolution. - * - * @param context The conflict context, must not be {@code null}. - * @throws RepositoryException If the version selection failed. - */ - public abstract void selectVersion( ConflictContext context ) - throws RepositoryException; - - } - - /** - * An extension point of {@link ConflictResolver} that determines the effective scope of a dependency from a - * potentially conflicting set of {@link ScopeDeriver derived scopes}. The scope selector gets invoked after the - * {@link VersionSelector} has picked the winning node. - * <p> - * <strong>Note:</strong> Implementations must be stateless. - */ - public abstract static class ScopeSelector - { - - /** - * Retrieves the scope selector for use during the specified graph transformation. The conflict resolver calls - * this method once per - * {@link ConflictResolver#transformGraph(DependencyNode, DependencyGraphTransformationContext)} invocation to - * allow implementations to prepare any auxiliary data that is needed for their operation. Given that - * implementations must be stateless, a new instance needs to be returned to hold such auxiliary data. The - * default implementation simply returns the current instance which is appropriate for implementations which do - * not require auxiliary data. - * - * @param root The root node of the (possibly cyclic!) graph to transform, must not be {@code null}. - * @param context The graph transformation context, must not be {@code null}. - * @return The scope selector to use for the given graph transformation, never {@code null}. - * @throws RepositoryException If the instance could not be retrieved. - */ - public ScopeSelector getInstance( DependencyNode root, DependencyGraphTransformationContext context ) - throws RepositoryException - { - return this; - } - - /** - * Determines the effective scope of the dependency given by {@link ConflictContext#getWinner()}. - * Implementations will usually iterate {@link ConflictContext#getItems()}, inspect - * {@link ConflictItem#getScopes()} and eventually call {@link ConflictContext#setScope(String)} to deliver the - * effective scope. - * - * @param context The conflict context, must not be {@code null}. - * @throws RepositoryException If the scope selection failed. - */ - public abstract void selectScope( ConflictContext context ) - throws RepositoryException; - - } - - /** - * An extension point of {@link ConflictResolver} that determines the scope of a dependency in relation to the scope - * of its parent. - * <p> - * <strong>Note:</strong> Implementations must be stateless. - */ - public abstract static class ScopeDeriver - { - - /** - * Retrieves the scope deriver for use during the specified graph transformation. The conflict resolver calls - * this method once per - * {@link ConflictResolver#transformGraph(DependencyNode, DependencyGraphTransformationContext)} invocation to - * allow implementations to prepare any auxiliary data that is needed for their operation. Given that - * implementations must be stateless, a new instance needs to be returned to hold such auxiliary data. The - * default implementation simply returns the current instance which is appropriate for implementations which do - * not require auxiliary data. - * - * @param root The root node of the (possibly cyclic!) graph to transform, must not be {@code null}. - * @param context The graph transformation context, must not be {@code null}. - * @return The scope deriver to use for the given graph transformation, never {@code null}. - * @throws RepositoryException If the instance could not be retrieved. - */ - public ScopeDeriver getInstance( DependencyNode root, DependencyGraphTransformationContext context ) - throws RepositoryException - { - return this; - } - - /** - * Determines the scope of a dependency in relation to the scope of its parent. Implementors need to call - * {@link ScopeContext#setDerivedScope(String)} to deliver the result of their calculation. If said method is - * not invoked, the conflict resolver will assume the scope of the child dependency remains unchanged. - * - * @param context The scope context, must not be {@code null}. - * @throws RepositoryException If the scope deriviation failed. - */ - public abstract void deriveScope( ScopeContext context ) - throws RepositoryException; - - } - - /** - * An extension point of {@link ConflictResolver} that determines the effective optional flag of a dependency from a - * potentially conflicting set of derived optionalities. The optionality selector gets invoked after the - * {@link VersionSelector} has picked the winning node. - * <p> - * <strong>Note:</strong> Implementations must be stateless. - */ - public abstract static class OptionalitySelector - { - - /** - * Retrieves the optionality selector for use during the specified graph transformation. The conflict resolver - * calls this method once per - * {@link ConflictResolver#transformGraph(DependencyNode, DependencyGraphTransformationContext)} invocation to - * allow implementations to prepare any auxiliary data that is needed for their operation. Given that - * implementations must be stateless, a new instance needs to be returned to hold such auxiliary data. The - * default implementation simply returns the current instance which is appropriate for implementations which do - * not require auxiliary data. - * - * @param root The root node of the (possibly cyclic!) graph to transform, must not be {@code null}. - * @param context The graph transformation context, must not be {@code null}. - * @return The optionality selector to use for the given graph transformation, never {@code null}. - * @throws RepositoryException If the instance could not be retrieved. - */ - public OptionalitySelector getInstance( DependencyNode root, DependencyGraphTransformationContext context ) - throws RepositoryException - { - return this; - } - - /** - * Determines the effective optional flag of the dependency given by {@link ConflictContext#getWinner()}. - * Implementations will usually iterate {@link ConflictContext#getItems()}, inspect - * {@link ConflictItem#getOptionalities()} and eventually call {@link ConflictContext#setOptional(Boolean)} to - * deliver the effective optional flag. - * - * @param context The conflict context, must not be {@code null}. - * @throws RepositoryException If the optionality selection failed. - */ - public abstract void selectOptionality( ConflictContext context ) - throws RepositoryException; - - } - -}
http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaDependencyContextRefiner.java ---------------------------------------------------------------------- diff --git a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaDependencyContextRefiner.java b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaDependencyContextRefiner.java deleted file mode 100644 index d96e04e..0000000 --- a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaDependencyContextRefiner.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.eclipse.aether.util.graph.transformer; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -import org.eclipse.aether.RepositoryException; -import org.eclipse.aether.collection.DependencyGraphTransformationContext; -import org.eclipse.aether.collection.DependencyGraphTransformer; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.graph.DependencyNode; -import org.eclipse.aether.util.artifact.JavaScopes; - -/** - * A dependency graph transformer that refines the request context for nodes that belong to the "project" context by - * appending the classpath type to which the node belongs. For instance, a compile-time project dependency will be - * assigned the request context "project/compile". - * - * @see DependencyNode#getRequestContext() - */ -public final class JavaDependencyContextRefiner - implements DependencyGraphTransformer -{ - - public DependencyNode transformGraph( DependencyNode node, DependencyGraphTransformationContext context ) - throws RepositoryException - { - String ctx = node.getRequestContext(); - - if ( "project".equals( ctx ) ) - { - String scope = getClasspathScope( node ); - if ( scope != null ) - { - ctx += '/' + scope; - node.setRequestContext( ctx ); - } - } - - for ( DependencyNode child : node.getChildren() ) - { - transformGraph( child, context ); - } - - return node; - } - - private String getClasspathScope( DependencyNode node ) - { - Dependency dependency = node.getDependency(); - if ( dependency == null ) - { - return null; - } - - String scope = dependency.getScope(); - - if ( JavaScopes.COMPILE.equals( scope ) || JavaScopes.SYSTEM.equals( scope ) - || JavaScopes.PROVIDED.equals( scope ) ) - { - return JavaScopes.COMPILE; - } - else if ( JavaScopes.RUNTIME.equals( scope ) ) - { - return JavaScopes.RUNTIME; - } - else if ( JavaScopes.TEST.equals( scope ) ) - { - return JavaScopes.TEST; - } - - return null; - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaScopeDeriver.java ---------------------------------------------------------------------- diff --git a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaScopeDeriver.java b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaScopeDeriver.java deleted file mode 100644 index 4c5fd3e..0000000 --- a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaScopeDeriver.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.eclipse.aether.util.graph.transformer; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -import org.eclipse.aether.RepositoryException; -import org.eclipse.aether.util.artifact.JavaScopes; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.ScopeContext; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.ScopeDeriver; - -/** - * A scope deriver for use with {@link ConflictResolver} that supports the scopes from {@link JavaScopes}. - */ -public final class JavaScopeDeriver - extends ScopeDeriver -{ - - /** - * Creates a new instance of this scope deriver. - */ - public JavaScopeDeriver() - { - } - - @Override - public void deriveScope( ScopeContext context ) - throws RepositoryException - { - context.setDerivedScope( getDerivedScope( context.getParentScope(), context.getChildScope() ) ); - } - - private String getDerivedScope( String parentScope, String childScope ) - { - String derivedScope; - - if ( JavaScopes.SYSTEM.equals( childScope ) || JavaScopes.TEST.equals( childScope ) ) - { - derivedScope = childScope; - } - else if ( parentScope == null || parentScope.length() <= 0 || JavaScopes.COMPILE.equals( parentScope ) ) - { - derivedScope = childScope; - } - else if ( JavaScopes.TEST.equals( parentScope ) || JavaScopes.RUNTIME.equals( parentScope ) ) - { - derivedScope = parentScope; - } - else if ( JavaScopes.SYSTEM.equals( parentScope ) || JavaScopes.PROVIDED.equals( parentScope ) ) - { - derivedScope = JavaScopes.PROVIDED; - } - else - { - derivedScope = JavaScopes.RUNTIME; - } - - return derivedScope; - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaScopeSelector.java ---------------------------------------------------------------------- diff --git a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaScopeSelector.java b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaScopeSelector.java deleted file mode 100644 index 93edf05..0000000 --- a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaScopeSelector.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.eclipse.aether.util.graph.transformer; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.aether.RepositoryException; -import org.eclipse.aether.util.artifact.JavaScopes; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.ConflictContext; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.ConflictItem; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.ScopeSelector; - -/** - * A scope selector for use with {@link ConflictResolver} that supports the scopes from {@link JavaScopes}. In general, - * this selector picks the widest scope present among conflicting dependencies where e.g. "compile" is wider than - * "runtime" which is wider than "test". If however a direct dependency is involved, its scope is selected. - */ -public final class JavaScopeSelector - extends ScopeSelector -{ - - /** - * Creates a new instance of this scope selector. - */ - public JavaScopeSelector() - { - } - - @Override - public void selectScope( ConflictContext context ) - throws RepositoryException - { - String scope = context.getWinner().getDependency().getScope(); - if ( !JavaScopes.SYSTEM.equals( scope ) ) - { - scope = chooseEffectiveScope( context.getItems() ); - } - context.setScope( scope ); - } - - private String chooseEffectiveScope( Collection<ConflictItem> items ) - { - Set<String> scopes = new HashSet<String>(); - for ( ConflictItem item : items ) - { - if ( item.getDepth() <= 1 ) - { - return item.getDependency().getScope(); - } - scopes.addAll( item.getScopes() ); - } - return chooseEffectiveScope( scopes ); - } - - private String chooseEffectiveScope( Set<String> scopes ) - { - if ( scopes.size() > 1 ) - { - scopes.remove( JavaScopes.SYSTEM ); - } - - String effectiveScope = ""; - - if ( scopes.size() == 1 ) - { - effectiveScope = scopes.iterator().next(); - } - else if ( scopes.contains( JavaScopes.COMPILE ) ) - { - effectiveScope = JavaScopes.COMPILE; - } - else if ( scopes.contains( JavaScopes.RUNTIME ) ) - { - effectiveScope = JavaScopes.RUNTIME; - } - else if ( scopes.contains( JavaScopes.PROVIDED ) ) - { - effectiveScope = JavaScopes.PROVIDED; - } - else if ( scopes.contains( JavaScopes.TEST ) ) - { - effectiveScope = JavaScopes.TEST; - } - - return effectiveScope; - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/NearestVersionSelector.java ---------------------------------------------------------------------- diff --git a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/NearestVersionSelector.java b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/NearestVersionSelector.java deleted file mode 100644 index c1ffa85..0000000 --- a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/NearestVersionSelector.java +++ /dev/null @@ -1,185 +0,0 @@ -package org.eclipse.aether.util.graph.transformer; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.aether.RepositoryException; -import org.eclipse.aether.collection.UnsolvableVersionConflictException; -import org.eclipse.aether.graph.DependencyFilter; -import org.eclipse.aether.graph.DependencyNode; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.ConflictContext; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.ConflictItem; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.VersionSelector; -import org.eclipse.aether.util.graph.visitor.PathRecordingDependencyVisitor; -import org.eclipse.aether.version.Version; -import org.eclipse.aether.version.VersionConstraint; - -/** - * A version selector for use with {@link ConflictResolver} that resolves version conflicts using a nearest-wins - * strategy. If there is no single node that satisfies all encountered version ranges, the selector will fail. - */ -public final class NearestVersionSelector - extends VersionSelector -{ - - /** - * Creates a new instance of this version selector. - */ - public NearestVersionSelector() - { - } - - @Override - public void selectVersion( ConflictContext context ) - throws RepositoryException - { - ConflictGroup group = new ConflictGroup(); - for ( ConflictItem item : context.getItems() ) - { - DependencyNode node = item.getNode(); - VersionConstraint constraint = node.getVersionConstraint(); - - boolean backtrack = false; - boolean hardConstraint = constraint.getRange() != null; - - if ( hardConstraint ) - { - if ( group.constraints.add( constraint ) ) - { - if ( group.winner != null && !constraint.containsVersion( group.winner.getNode().getVersion() ) ) - { - backtrack = true; - } - } - } - - if ( isAcceptable( group, node.getVersion() ) ) - { - group.candidates.add( item ); - - if ( backtrack ) - { - backtrack( group, context ); - } - else if ( group.winner == null || isNearer( item, group.winner ) ) - { - group.winner = item; - } - } - else if ( backtrack ) - { - backtrack( group, context ); - } - } - context.setWinner( group.winner ); - } - - private void backtrack( ConflictGroup group, ConflictContext context ) - throws UnsolvableVersionConflictException - { - group.winner = null; - - for ( Iterator<ConflictItem> it = group.candidates.iterator(); it.hasNext(); ) - { - ConflictItem candidate = it.next(); - - if ( !isAcceptable( group, candidate.getNode().getVersion() ) ) - { - it.remove(); - } - else if ( group.winner == null || isNearer( candidate, group.winner ) ) - { - group.winner = candidate; - } - } - - if ( group.winner == null ) - { - throw newFailure( context ); - } - } - - private boolean isAcceptable( ConflictGroup group, Version version ) - { - for ( VersionConstraint constraint : group.constraints ) - { - if ( !constraint.containsVersion( version ) ) - { - return false; - } - } - return true; - } - - private boolean isNearer( ConflictItem item1, ConflictItem item2 ) - { - if ( item1.isSibling( item2 ) ) - { - return item1.getNode().getVersion().compareTo( item2.getNode().getVersion() ) > 0; - } - else - { - return item1.getDepth() < item2.getDepth(); - } - } - - private UnsolvableVersionConflictException newFailure( final ConflictContext context ) - { - DependencyFilter filter = new DependencyFilter() - { - public boolean accept( DependencyNode node, List<DependencyNode> parents ) - { - return context.isIncluded( node ); - } - }; - PathRecordingDependencyVisitor visitor = new PathRecordingDependencyVisitor( filter ); - context.getRoot().accept( visitor ); - return new UnsolvableVersionConflictException( visitor.getPaths() ); - } - - static final class ConflictGroup - { - - final Collection<VersionConstraint> constraints; - - final Collection<ConflictItem> candidates; - - ConflictItem winner; - - public ConflictGroup() - { - constraints = new HashSet<VersionConstraint>(); - candidates = new ArrayList<ConflictItem>( 64 ); - } - - @Override - public String toString() - { - return String.valueOf( winner ); - } - - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/NoopDependencyGraphTransformer.java ---------------------------------------------------------------------- diff --git a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/NoopDependencyGraphTransformer.java b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/NoopDependencyGraphTransformer.java deleted file mode 100644 index 55b6175..0000000 --- a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/NoopDependencyGraphTransformer.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.eclipse.aether.util.graph.transformer; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -import org.eclipse.aether.RepositoryException; -import org.eclipse.aether.collection.DependencyGraphTransformationContext; -import org.eclipse.aether.collection.DependencyGraphTransformer; -import org.eclipse.aether.graph.DependencyNode; - -/** - * A dependency graph transformer that does not perform any changes on its input. - */ -public final class NoopDependencyGraphTransformer - implements DependencyGraphTransformer -{ - - /** - * A ready-made instance of this dependency graph transformer which can safely be reused throughout an entire - * application regardless of multi-threading. - */ - public static final DependencyGraphTransformer INSTANCE = new NoopDependencyGraphTransformer(); - - /** - * Creates a new instance of this graph transformer. Usually, {@link #INSTANCE} should be used instead. - */ - public NoopDependencyGraphTransformer() - { - } - - public DependencyNode transformGraph( DependencyNode node, DependencyGraphTransformationContext context ) - throws RepositoryException - { - return node; - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/SimpleOptionalitySelector.java ---------------------------------------------------------------------- diff --git a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/SimpleOptionalitySelector.java b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/SimpleOptionalitySelector.java deleted file mode 100644 index 0cc7a73..0000000 --- a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/SimpleOptionalitySelector.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.eclipse.aether.util.graph.transformer; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -import java.util.Collection; - -import org.eclipse.aether.RepositoryException; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.ConflictContext; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.ConflictItem; -import org.eclipse.aether.util.graph.transformer.ConflictResolver.OptionalitySelector; - -/** - * An optionality selector for use with {@link ConflictResolver}. In general, this selector only marks a dependency as - * optional if all its occurrences are optional. If however a direct dependency is involved, its optional flag is - * selected. - */ -public final class SimpleOptionalitySelector - extends OptionalitySelector -{ - - /** - * Creates a new instance of this optionality selector. - */ - public SimpleOptionalitySelector() - { - } - - @Override - public void selectOptionality( ConflictContext context ) - throws RepositoryException - { - boolean optional = chooseEffectiveOptionality( context.getItems() ); - context.setOptional( optional ); - } - - private boolean chooseEffectiveOptionality( Collection<ConflictItem> items ) - { - boolean optional = true; - for ( ConflictItem item : items ) - { - if ( item.getDepth() <= 1 ) - { - return item.getDependency().isOptional(); - } - if ( ( item.getOptionalities() & ConflictItem.OPTIONAL_FALSE ) != 0 ) - { - optional = false; - } - } - return optional; - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/TransformationContextKeys.java ---------------------------------------------------------------------- diff --git a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/TransformationContextKeys.java b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/TransformationContextKeys.java deleted file mode 100644 index a9ebf68..0000000 --- a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/TransformationContextKeys.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.eclipse.aether.util.graph.transformer; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -/** - * A collection of keys used by the dependency graph transformers when exchanging information via the graph - * transformation context. - * - * @see org.eclipse.aether.collection.DependencyGraphTransformationContext#get(Object) - */ -public final class TransformationContextKeys -{ - - /** - * The key in the graph transformation context where a {@code Map<DependencyNode, Object>} is stored which maps - * dependency nodes to their conflict ids. All nodes that map to an equal conflict id belong to the same group of - * conflicting dependencies. Note that the map keys use reference equality. - * - * @see ConflictMarker - */ - public static final Object CONFLICT_IDS = "conflictIds"; - - /** - * The key in the graph transformation context where a {@code List<Object>} is stored that denotes a topological - * sorting of the conflict ids. - * - * @see ConflictIdSorter - */ - public static final Object SORTED_CONFLICT_IDS = "sortedConflictIds"; - - /** - * The key in the graph transformation context where a {@code Collection<Collection<Object>>} is stored that denotes - * cycles among conflict ids. Each element in the outer collection denotes one cycle, i.e. if the collection is - * empty, the conflict ids have no cyclic dependencies. - * - * @see ConflictIdSorter - */ - public static final Object CYCLIC_CONFLICT_IDS = "cyclicConflictIds"; - - /** - * The key in the graph transformation context where a {@code Map<String, Object>} is stored that can be used to - * include some runtime/performance stats in the debug log. If this map is not present, no stats should be recorded. - */ - public static final Object STATS = "stats"; - - private TransformationContextKeys() - { - // hide constructor - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/package-info.java ---------------------------------------------------------------------- diff --git a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/package-info.java b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/package-info.java deleted file mode 100644 index a41adcd..0000000 --- a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -// CHECKSTYLE_OFF: RegexpHeader -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ -/** - * Various dependency graph transformers for post-processing a dependency graph. - */ -package org.eclipse.aether.util.graph.transformer; -