FIX: now handle transitive eviction (IVY-51)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ivy/trunk@484002 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Xavier Hanin 2005-07-04 18:27:06 +00:00
parent f5a532d606
commit 8c02470fb0
6 changed files with 115 additions and 19 deletions

View File

@ -6,6 +6,7 @@
- new type filtering in cachepath task
- new cachefileset task: builds an ant fileset of artifacts in cache
- publish task now uses srcivypattern for ivy files finding and for delivery
- FIX: now handle transitive eviction (IVY-51)
- FIX: resolve now store resolved file id in ivy variables, so that multiple resolve calls
can be followed by multiple retrieve, each retrieve will use the last resolve info (IVY-49)
- FIX: IllegalStateException on retrieve done from command line

View File

@ -733,6 +733,7 @@ public class Ivy implements TransferListener {
}
}
// prune and reverse sort fectched dependencies
Collection dependencies = new HashSet(dependenciesMap.size()); // use a Set to avoids duplicates
for (Iterator iter = dependenciesMap.values().iterator(); iter.hasNext();) {
@ -743,6 +744,39 @@ public class Ivy implements TransferListener {
}
List sortedDependencies = sortNodes(dependencies);
Collections.reverse(sortedDependencies);
// handle transitive eviction now:
// if a module has been evicted then all its dependencies required
// only by it should be evicted too. Since nodes are now sorted from the more dependent to
// the less one, we can traverse the list and check only the direct parent and not all
// the ancestors
for (ListIterator iter = sortedDependencies.listIterator(); iter.hasNext();) {
IvyNode node = (IvyNode)iter.next();
if (!node.isCompletelyEvicted()) {
for (int i = 0; i < confs.length; i++) {
IvyNode.Caller[] callers = node.getCallers(confs[i]);
boolean allEvicted = callers.length > 0;
for (int j = 0; j < callers.length; j++) {
if (callers[j].getModuleRevisionId().equals(md.getModuleRevisionId())) {
// the caller is the root module itself, it can't be evicted
allEvicted = false;
break;
} else {
IvyNode callerNode = (IvyNode)dependenciesMap.get(callers[j].getModuleRevisionId());
if (callerNode != null && !callerNode.isEvicted(confs[i])) {
allEvicted = false;
break;
}
}
}
if (allEvicted) {
Message.verbose("all callers are evicted for "+node+": evicting too");
node.markEvicted(confs[i], null, null, null);
}
}
}
}
return (IvyNode[])sortedDependencies.toArray(new IvyNode[sortedDependencies.size()]);
}

View File

@ -22,9 +22,9 @@ import fr.jayasoft.ivy.util.Message;
public class IvyNode {
public static class EvictionData {
private IvyNode _node;
private ConflictManager _conflictManager;
private Collection _selected;
private IvyNode _node; // can be null in case of transitive eviction
private ConflictManager _conflictManager; // can be null in case of transitive eviction
private Collection _selected; // can be null in case of transitive eviction
private String _rootModuleConf;
public EvictionData(String rootModuleConf, IvyNode node, ConflictManager conflictManager, Collection selected) {
@ -35,7 +35,11 @@ public class IvyNode {
}
public String toString() {
return _selected + " in "+ _node+" ("+_conflictManager+") ["+_rootModuleConf+"]";
if (_selected != null) {
return _selected + " in "+ _node+" ("+_conflictManager+") ["+_rootModuleConf+"]";
} else {
return "transitively ["+_rootModuleConf+"]";
}
}
public ConflictManager getConflictManager() {
@ -292,12 +296,14 @@ public class IvyNode {
String rootModuleConf = (String)iter.next();
EvictionData ed = (EvictionData)_evicted.get(rootModuleConf);
Collection sel = ed.getSelected();
for (Iterator iterator = sel.iterator(); iterator.hasNext();) {
IvyNode n = (IvyNode)iterator.next();
if (n.getRealNode().equals(this)) {
// yes, we are the real node for a selected one !
// we are no more evicted in this conf !
iter.remove();
if (sel != null) {
for (Iterator iterator = sel.iterator(); iterator.hasNext();) {
IvyNode n = (IvyNode)iterator.next();
if (n.getRealNode().equals(this)) {
// yes, we are the real node for a selected one !
// we are no more evicted in this conf !
iter.remove();
}
}
}
}
@ -314,9 +320,11 @@ public class IvyNode {
}
// bug 105: update selected data with evicted one
for (Iterator iter = resolved.iterator(); iter.hasNext();) {
IvyNode selected = (IvyNode)iter.next();
selected.updateDataFrom(this, rootModuleConf);
if (resolved != null) {
for (Iterator iter = resolved.iterator(); iter.hasNext();) {
IvyNode selected = (IvyNode)iter.next();
selected.updateDataFrom(this, rootModuleConf);
}
}
}
private void updateDataFrom(IvyNode node, String rootModuleConf) {
@ -390,7 +398,10 @@ public class IvyNode {
Collection allEvictingNodes = new HashSet();
for (Iterator iter = _evicted.values().iterator(); iter.hasNext();) {
EvictionData ed = (EvictionData)iter.next();
allEvictingNodes.addAll(ed.getSelected());
Collection selected = ed.getSelected();
if (selected != null) {
allEvictingNodes.addAll(selected);
}
}
return allEvictingNodes;
}
@ -666,6 +677,15 @@ public class IvyNode {
return (Caller[])callers.values().toArray(new Caller[callers.values().size()]);
}
public Caller[] getAllCallers() {
Set all = new HashSet();
for (Iterator iter = _callersByRootConf.values().iterator(); iter.hasNext();) {
Map callers = (Map)iter.next();
all.addAll(callers.values());
}
return (Caller[])all.toArray(new Caller[all.size()]);
}
public String toString() {
return getResolvedId().toString();
}

View File

@ -7,6 +7,7 @@ package fr.jayasoft.ivy.report;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import fr.jayasoft.ivy.IvyNode;
import fr.jayasoft.ivy.util.Message;
@ -22,7 +23,12 @@ public class LogReportOutputter implements ReportOutputter {
if (evicted.length > 0) {
Message.info("\t:: evicted modules:");
for (int i = 0; i < evicted.length; i++) {
Message.info("\t"+evicted[i]+" by "+evicted[i].getAllEvictingNodes()+" in "+Arrays.asList(evicted[i].getEvictedConfs()));
Collection allEvictingNodes = evicted[i].getAllEvictingNodes();
if (allEvictingNodes.isEmpty()) {
Message.info("\t"+evicted[i]+" transitively in "+Arrays.asList(evicted[i].getEvictedConfs()));
} else {
Message.info("\t"+evicted[i]+" by "+allEvictingNodes+" in "+Arrays.asList(evicted[i].getEvictedConfs()));
}
String[] confs = evicted[i].getEvictedConfs();
for (int j = 0; j < confs.length; j++) {
IvyNode.EvictionData evictedData = evicted[i].getEvictedData(confs[j]);

View File

@ -9,6 +9,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
@ -69,7 +70,11 @@ public class XmlReportOutputter implements ReportOutputter {
}
if (dep.isEvicted(report.getConfiguration())) {
IvyNode.EvictionData ed = dep.getEvictedData(report.getConfiguration());
details += " evicted=\""+ed.getConflictManager()+"\"";
if (ed.getConflictManager() != null) {
details += " evicted=\""+ed.getConflictManager()+"\"";
} else {
details += " evicted=\"transitive\"";
}
}
if (dep.hasProblem()) {
details += " error=\""+dep.getProblem().getMessage()+"\"";
@ -96,9 +101,12 @@ public class XmlReportOutputter implements ReportOutputter {
}
if (dep.isEvicted(report.getConfiguration())) {
IvyNode.EvictionData ed = dep.getEvictedData(report.getConfiguration());
for (Iterator it3 = ed.getSelected().iterator(); it3.hasNext();) {
IvyNode sel = (IvyNode)it3.next();
out.println("\t\t\t\t<evicted-by rev=\""+sel.getResolvedId().getRevision()+"\"/>");
Collection selected = ed.getSelected();
if (selected != null) {
for (Iterator it3 = selected.iterator(); it3.hasNext();) {
IvyNode sel = (IvyNode)it3.next();
out.println("\t\t\t\t<evicted-by rev=\""+sel.getResolvedId().getRevision()+"\"/>");
}
}
}
IvyNode.Caller[] callers = dep.getCallers(report.getConfiguration());

View File

@ -352,6 +352,33 @@ public class ResolveTest extends TestCase {
assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.1", "mod1.2", "jar", "jar").exists());
}
public void testTransitiveEviction() throws Exception {
// mod7.3 depends on mod7.2 v1.0 and on mod7.1 v2.0
// mod7.2 v1.0 depends on mod7.1 v1.0 (which then should be evicted)
// mod7.1 v1.0 depends on mod 1.2 v1.0 (which should be evicted by transitivity)
ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod7.3/ivy-1.0.xml").toURL(),
null, new String[] {"*"}, _cache, null, true);
assertNotNull(report);
ModuleDescriptor md = report.getModuleDescriptor();
assertNotNull(md);
ModuleRevisionId mrid = ModuleRevisionId.newInstance("org7", "mod7.3", "1.0");
assertEquals(mrid, md.getModuleRevisionId());
assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists());
// dependencies
assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org7", "mod7.2", "1.0")).exists());
assertTrue(_ivy.getArchiveFileInCache(_cache, "org7", "mod7.2", "1.0", "mod7.2", "jar", "jar").exists());
assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org7", "mod7.1", "2.0")).exists());
assertTrue(_ivy.getArchiveFileInCache(_cache, "org7", "mod7.1", "2.0", "mod7.1", "jar", "jar").exists());
assertTrue(!_ivy.getArchiveFileInCache(_cache, "org7", "mod7.1", "1.0", "mod7.1", "jar", "jar").exists());
assertTrue(!_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists());
}
public void testResolveConflictInConf() throws Exception {
// conflicts in separate confs are not conflicts