private Set<ResolvedArtifact> getArtifacts(ConfigurationNode childConfiguration) { String[] targetConfigurations = from.metaData.getHierarchy().toArray(new String[from.metaData.getHierarchy().size()]); DependencyArtifactDescriptor[] dependencyArtifacts = dependencyDescriptor.getDependencyArtifacts(targetConfigurations); if (dependencyArtifacts.length == 0) { return Collections.emptySet(); } Set<ResolvedArtifact> artifacts = new LinkedHashSet<ResolvedArtifact>(); for (DependencyArtifactDescriptor artifactDescriptor : dependencyArtifacts) { ModuleRevisionId id = childConfiguration.moduleRevision.metaData.getDescriptor().getModuleRevisionId(); Artifact artifact = new DefaultArtifact( id, null, artifactDescriptor.getName(), artifactDescriptor.getType(), artifactDescriptor.getExt(), artifactDescriptor.getUrl(), artifactDescriptor.getQualifiedExtraAttributes()); artifacts.add( resolveState.builder.newArtifact( childConfiguration.getResult(), artifact, targetModuleRevision.resolve().getArtifactResolver())); } return artifacts; }
public void visitOutgoingDependencies(Collection<DependencyEdge> target) { // If this configuration's version is in conflict, don't do anything // If not traversed before, add all selected outgoing edges // If traversed before, and the selected modules have changed, remove previous outgoing edges // and add outgoing edges again with // the new selections. // If traversed before, and the selected modules have not changed, ignore // If none of the incoming edges are transitive, then the node has no outgoing edges if (moduleRevision.state != ModuleState.Selected) { LOGGER.debug("version for {} is not selected. ignoring.", this); return; } List<DependencyEdge> transitiveIncoming = new ArrayList<DependencyEdge>(); for (DependencyEdge edge : incomingEdges) { if (edge.isTransitive()) { transitiveIncoming.add(edge); } } if (transitiveIncoming.isEmpty() && this != resolveState.root) { if (previousTraversal != null) { removeOutgoingEdges(); } if (incomingEdges.isEmpty()) { LOGGER.debug("{} has no incoming edges. ignoring.", this); } else { LOGGER.debug("{} has no transitive incoming edges. ignoring outgoing edges.", this); } return; } ModuleVersionSpec selectorSpec = getSelector(transitiveIncoming); if (previousTraversal != null) { if (previousTraversal.acceptsSameModulesAs(selectorSpec)) { LOGGER.debug( "Changed edges for {} selects same versions as previous traversal. ignoring", this); return; } removeOutgoingEdges(); } for (DependencyMetaData dependency : metaData.getDependencies()) { DependencyDescriptor dependencyDescriptor = dependency.getDescriptor(); ModuleId targetModuleId = dependencyDescriptor.getDependencyRevisionId().getModuleId(); if (!selectorSpec.isSatisfiedBy(targetModuleId)) { LOGGER.debug("{} is excluded from {}.", targetModuleId, this); continue; } DependencyEdge dependencyEdge = new DependencyEdge(this, dependency, selectorSpec, resolveState); outgoingEdges.add(dependencyEdge); target.add(dependencyEdge); } previousTraversal = selectorSpec; }
public void removeOutgoingEdges() { for (DependencyEdge outgoingDependency : outgoingEdges) { outgoingDependency.removeFromTargetConfigurations(); } outgoingEdges.clear(); previousTraversal = null; }
/** * Called when a change is made to a configuration node, such that its dependency graph * <em>may</em> now be larger than it previously was, and the node should be visited. */ public void onMoreSelected(ConfigurationNode configuration) { // Add to the end of the queue, so that we traverse the graph in breadth-wise order to pick up // as many conflicts as // possible before attempting to resolve them if (queued.add(configuration)) { queue.addLast(configuration); } }
public void attachToParents( ConfigurationNode childConfiguration, ResolvedConfigurationBuilder result) { ResolvedConfigurationIdentifier parent = from.getResult(); ResolvedConfigurationIdentifier child = childConfiguration.getResult(); result.addChild(parent, child); Set<ResolvedArtifact> artifacts = getArtifacts(childConfiguration); if (artifacts.isEmpty()) { artifacts = childConfiguration.getArtifacts(); } // TODO SF merge with addChild result.addParentSpecificArtifacts(child, parent, artifacts); if (parent == resolveState.root.getResult()) { EnhancedDependencyDescriptor enhancedDependencyDescriptor = (EnhancedDependencyDescriptor) dependencyDescriptor; result.addFirstLevelDependency(enhancedDependencyDescriptor.getModuleDependency(), child); } }
public void restart(ModuleVersionResolveState selected) { select(selected); for (ModuleVersionResolveState version : versions.values()) { version.restart(selected); } for (DependencyEdge dependency : new ArrayList<DependencyEdge>(unattachedDependencies)) { dependency.restart(selected); } unattachedDependencies.clear(); }
public Set<ResolvedArtifact> getArtifacts() { if (artifacts == null) { artifacts = new LinkedHashSet<ResolvedArtifact>(); for (Artifact artifact : metaData.getArtifacts()) { artifacts.add( resolveState.builder.newArtifact( getResult(), artifact, moduleRevision.resolve().getArtifactResolver())); } } return artifacts; }
public void attachToTargetConfigurations() { if (targetModuleRevision.state != ModuleState.Selected) { return; } calculateTargetConfigurations(); for (ConfigurationNode targetConfiguration : targetConfigurations) { targetConfiguration.addIncomingEdge(this); } if (!targetConfigurations.isEmpty()) { selector.getSelectedModule().removeUnattachedDependency(this); } }
public void restart(ModuleVersionResolveState selected) { // Restarting this configuration after conflict resolution. // If this configuration belongs to the select version, queue ourselves up for traversal. // If not, then move our incoming edges across to the selected configuration if (moduleRevision == selected) { resolveState.onMoreSelected(this); } else { for (DependencyEdge dependency : incomingEdges) { dependency.restart(selected); } incomingEdges.clear(); } }
private void calculateTargetConfigurations() { targetConfigurations.clear(); ModuleVersionMetaData targetModuleVersion = targetModuleRevision.getMetaData(); if (targetModuleVersion == null) { // Broken version return; } Set<ConfigurationMetaData> targetConfigurations = resolveState.dependencyToConfigurationResolver.resolveTargetConfigurations( dependencyMetaData, from.metaData, targetModuleVersion); for (ConfigurationMetaData targetConfiguration : targetConfigurations) { ConfigurationNode targetConfigurationNode = resolveState.getConfigurationNode(targetModuleRevision, targetConfiguration.getName()); this.targetConfigurations.add(targetConfigurationNode); } }
/** * Traverses the dependency graph, resolving conflicts and building the paths from the root * configuration. */ private void traverseGraph(ResolveState resolveState) { Set<ModuleIdentifier> conflicts = new LinkedHashSet<ModuleIdentifier>(); resolveState.onMoreSelected(resolveState.root); List<DependencyEdge> dependencies = new ArrayList<DependencyEdge>(); while (resolveState.peek() != null || !conflicts.isEmpty()) { if (resolveState.peek() != null) { ConfigurationNode node = resolveState.pop(); LOGGER.debug("Visiting configuration {}.", node); // Calculate the outgoing edges of this configuration dependencies.clear(); node.visitOutgoingDependencies(dependencies); for (DependencyEdge dependency : dependencies) { LOGGER.debug("Visiting dependency {}", dependency); // Resolve dependency to a particular revision ModuleVersionResolveState moduleRevision = dependency.resolveModuleRevisionId(); if (moduleRevision == null) { // Failed to resolve. continue; } ModuleIdentifier moduleId = moduleRevision.id.getModule(); // Check for a new conflict if (moduleRevision.state == ModuleState.New) { ModuleResolveState module = resolveState.getModule(moduleId); // A new module revision. Check for conflict Collection<ModuleVersionResolveState> versions = module.getVersions(); if (versions.size() == 1) { // First version of this module. Select it for now LOGGER.debug("Selecting new module version {}", moduleRevision); module.select(moduleRevision); } else { // Not the first version of this module. We have a new conflict LOGGER.debug("Found new conflicting module version {}", moduleRevision); conflicts.add(moduleId); // Deselect the currently selected version, and remove all outgoing edges from the // version // This will propagate through the graph and prune configurations that are no longer // required ModuleVersionResolveState previouslySelected = module.clearSelection(); if (previouslySelected != null) { for (ConfigurationNode configuration : previouslySelected.configurations) { configuration.removeOutgoingEdges(); } } } } dependency.attachToTargetConfigurations(); } } else { // We have some batched up conflicts. Resolve the first, and continue traversing the graph ModuleIdentifier moduleId = conflicts.iterator().next(); conflicts.remove(moduleId); ModuleResolveState module = resolveState.getModule(moduleId); ModuleVersionResolveState selected = conflictResolver.select(module.getVersions(), resolveState.root.moduleRevision); LOGGER.debug("Selected {} from conflicting modules {}.", selected, module.getVersions()); // Restart each configuration. For the evicted configuration, this means moving incoming // dependencies across to the // matching selected configuration. For the select configuration, this mean traversing its // dependencies. module.restart(selected); } } }
public void removeIncomingEdge(DependencyEdge dependencyEdge) { incomingEdges.remove(dependencyEdge); resolveState.onFewerSelected(this); }
public void addIncomingEdge(DependencyEdge dependencyEdge) { incomingEdges.add(dependencyEdge); resolveState.onMoreSelected(this); }
public void removeFromTargetConfigurations() { for (ConfigurationNode targetConfiguration : targetConfigurations) { targetConfiguration.removeIncomingEdge(this); } targetConfigurations.clear(); }
public void addConfiguration(ConfigurationNode configurationNode) { configurations.add(configurationNode); }
public void removeUnattachedDependency(DependencyEdge edge) { unattachedDependencies.remove(edge); }
public ConfigurationNode pop() { ConfigurationNode next = queue.removeFirst(); queued.remove(next); return next; }
/** * Called when a change is made to a configuration node, such that its dependency graph * <em>may</em> now be smaller than it previously was, and the node should be visited. */ public void onFewerSelected(ConfigurationNode configuration) { // Add to the front of the queue, to flush out configurations that are no longer required. if (queued.add(configuration)) { queue.addFirst(configuration); } }
public void addUnattachedDependency(DependencyEdge edge) { unattachedDependencies.add(edge); }
private Collection<List<ModuleVersionIdentifier>> calculatePaths( BrokenDependency brokenDependency) { // Include the shortest path from each version that has a direct dependency on the broken // dependency, back to the root Map<ModuleVersionResolveState, List<ModuleVersionIdentifier>> shortestPaths = new LinkedHashMap<ModuleVersionResolveState, List<ModuleVersionIdentifier>>(); List<ModuleVersionIdentifier> rootPath = new ArrayList<ModuleVersionIdentifier>(); rootPath.add(root.moduleRevision.id); shortestPaths.put(root.moduleRevision, rootPath); Set<ModuleVersionResolveState> directDependees = new LinkedHashSet<ModuleVersionResolveState>(); for (ConfigurationNode node : brokenDependency.requiredBy) { directDependees.add(node.moduleRevision); } Set<ModuleVersionResolveState> seen = new HashSet<ModuleVersionResolveState>(); LinkedList<ModuleVersionResolveState> queue = new LinkedList<ModuleVersionResolveState>(); queue.addAll(directDependees); while (!queue.isEmpty()) { ModuleVersionResolveState version = queue.getFirst(); if (version == root.moduleRevision) { queue.removeFirst(); } else if (seen.add(version)) { for (ConfigurationNode configuration : version.configurations) { for (DependencyEdge dependencyEdge : configuration.incomingEdges) { queue.add(0, dependencyEdge.from.moduleRevision); } } } else { queue.remove(); List<ModuleVersionIdentifier> shortest = null; for (ConfigurationNode configuration : version.configurations) { for (DependencyEdge dependencyEdge : configuration.incomingEdges) { List<ModuleVersionIdentifier> candidate = shortestPaths.get(dependencyEdge.from.moduleRevision); if (candidate == null) { continue; } if (shortest == null) { shortest = candidate; } else if (shortest.size() > candidate.size()) { shortest = candidate; } } } if (shortest == null) { continue; } List<ModuleVersionIdentifier> path = new ArrayList<ModuleVersionIdentifier>(); path.addAll(shortest); path.add(version.id); shortestPaths.put(version, path); } } List<List<ModuleVersionIdentifier>> paths = new ArrayList<List<ModuleVersionIdentifier>>(); for (ModuleVersionResolveState version : directDependees) { List<ModuleVersionIdentifier> path = shortestPaths.get(version); paths.add(path); } return paths; }