diff --git a/CHANGES.txt b/CHANGES.txt index 155c024c..1441dafa 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +- new changing attribute on dependencies indicate that the dependency artifacts + may change even without revision change, but with only a new ivy file with new + publication date - new useRemoteConfig on conf tag in ivyconf.xml, tells to use remote configuration file for repository config - new type filtering in cachepath task diff --git a/src/java/fr/jayasoft/ivy/DefaultDependencyDescriptor.java b/src/java/fr/jayasoft/ivy/DefaultDependencyDescriptor.java index 55aeef19..535a49e7 100644 --- a/src/java/fr/jayasoft/ivy/DefaultDependencyDescriptor.java +++ b/src/java/fr/jayasoft/ivy/DefaultDependencyDescriptor.java @@ -35,17 +35,27 @@ public class DefaultDependencyDescriptor implements DependencyDescriptor { * of conflicts manager */ private boolean _force; - private ModuleRevisionId _parentId; + /** + * Used to indicate that the dependency is a changing one, i.e. that ivy should not rely on the version to know if it can trust artifacts in cache + */ + private boolean _changing; + private ModuleRevisionId _parentId; - public DefaultDependencyDescriptor(ModuleDescriptor md, ModuleRevisionId mrid, boolean force) { + public DefaultDependencyDescriptor(ModuleDescriptor md, ModuleRevisionId mrid, boolean force, boolean changing) { _parentId = md.getModuleRevisionId(); _revId = mrid; _force = force; + _changing = changing; } public DefaultDependencyDescriptor(ModuleRevisionId mrid, boolean force) { + this(mrid, force, false); + } + + public DefaultDependencyDescriptor(ModuleRevisionId mrid, boolean force, boolean changing) { _revId = mrid; _force = force; + _changing = changing; } public ModuleId getDependencyId() { @@ -188,5 +198,9 @@ public class DefaultDependencyDescriptor implements DependencyDescriptor { public ModuleRevisionId getParentRevisionId() { return _parentId; } - + + public boolean isChanging() { + return _changing; + } + } diff --git a/src/java/fr/jayasoft/ivy/DependencyDescriptor.java b/src/java/fr/jayasoft/ivy/DependencyDescriptor.java index 37f88891..4eaacad7 100644 --- a/src/java/fr/jayasoft/ivy/DependencyDescriptor.java +++ b/src/java/fr/jayasoft/ivy/DependencyDescriptor.java @@ -19,6 +19,15 @@ public interface DependencyDescriptor { * can do its work. */ boolean isForce(); + /** + * Used to indicate that this dependency is a changing one. + * A changing dependency in ivy means that the revision may have its artifacts modified + * without revision change. When new artifacts are published a new ivy file should also + * be published with a new publication date to indicate to ivy that artifacts have changed and that they + * should be downloaded again. + * @return true if this dependency is a changing one + */ + boolean isChanging(); ModuleRevisionId getParentRevisionId(); ModuleRevisionId getDependencyRevisionId(); String[] getModuleConfigurations(); diff --git a/src/java/fr/jayasoft/ivy/resolver/BasicResolver.java b/src/java/fr/jayasoft/ivy/resolver/BasicResolver.java index 8178a172..5e52876d 100644 --- a/src/java/fr/jayasoft/ivy/resolver/BasicResolver.java +++ b/src/java/fr/jayasoft/ivy/resolver/BasicResolver.java @@ -146,6 +146,7 @@ public abstract class BasicResolver extends AbstractResolver { _ivyattempts.clear(); boolean downloaded = false; boolean searched = false; + Date cachedPublicationDate = null; ModuleRevisionId mrid = dd.getDependencyRevisionId(); // check revision int index = mrid.getRevision().indexOf("@"); @@ -159,9 +160,9 @@ public abstract class BasicResolver extends AbstractResolver { return null; } - // if we do not have to check modified and if the revision is exact, we first - // search for it in cache - if (mrid.isExactRevision() && !isCheckmodified()) { + // if we do not have to check modified and if the revision is exact and not changing, + // we first search for it in cache + if (mrid.isExactRevision() && !isCheckmodified() && !dd.isChanging()) { ResolvedModuleRevision rmr = data.getIvy().findModuleInCache(mrid, data.getCache(), doValidate(data)); if (rmr != null) { Message.verbose("\t"+getName()+": revision in cache: "+mrid); @@ -214,17 +215,22 @@ public abstract class BasicResolver extends AbstractResolver { // now let's see if we can find it in cache and if it is up to date ResolvedModuleRevision rmr = data.getIvy().findModuleInCache(resolvedMrid, data.getCache(), doValidate(data)); if (rmr != null) { - if (!isCheckmodified()) { + if (!isCheckmodified() && !dd.isChanging()) { Message.verbose("\t"+getName()+": revision in cache: "+resolvedMrid); return searchedRmr(rmr); } long repLastModified = ivyRef.getLastModified(); long cacheLastModified = rmr.getDescriptor().getLastModified(); - if (rmr.getDescriptor().isDefault() || repLastModified <= cacheLastModified) { + if (repLastModified <= cacheLastModified) { Message.verbose("\t"+getName()+": revision in cache (not updated): "+resolvedMrid); return searchedRmr(rmr); } else { Message.verbose("\t"+getName()+": revision in cache is not up to date: "+resolvedMrid); + if (dd.isChanging()) { + // ivy file has been updated, we should see if it has a new publication date + // to see if a new download is required (in case the dependency is a changing one) + cachedPublicationDate = rmr.getDescriptor().getResolvedPublicationDate(); + } } } @@ -261,6 +267,25 @@ public abstract class BasicResolver extends AbstractResolver { !ivyRef.getRevision().equals(md.getModuleRevisionId().getRevision())) { throw new IllegalStateException("bad revision found in "+ivyRef.getResource()+": expected="+ivyRef.getRevision()+" found="+md.getModuleRevisionId().getRevision()); } + + // check if publication date has changed + if (cachedPublicationDate != null && !cachedPublicationDate.equals(md.getResolvedPublicationDate())) { + // artifacts have changed, they should be downloaded again + Message.verbose("dependency "+dd+" has changed: deleting old artifacts"); + String[] confs = rmr.getDescriptor().getConfigurationsNames(); + for (int i = 0; i < confs.length; i++) { + Artifact[] arts = rmr.getDescriptor().getArtifacts(confs[i]); + for (int j = 0; j < arts.length; j++) { + File artFile = data.getIvy().getArchiveFileInCache(data.getCache(), arts[j]); + if (artFile.exists()) { + Message.debug("deleting "+artFile); + artFile.delete(); + } + } + } + } else if (dd.isChanging()){ + Message.verbose("dependency "+dd+" is changing, but has not changed: will trust cached artifacts if any"); + } } catch (IOException ex) { Message.warn("io problem while parsing ivy file: "+ivyRef.getResource()+": "+ex.getMessage()); return null; diff --git a/src/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorParser.java b/src/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorParser.java index 6f4dd566..28fe38a4 100644 --- a/src/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorParser.java +++ b/src/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorParser.java @@ -50,7 +50,7 @@ import fr.jayasoft.ivy.util.XMLHelper; * */ public class XmlModuleDescriptorParser extends DefaultHandler { - private static final Collection ALLOWED_VERSIONS = Arrays.asList(new String[] {"1.0", "1.1"}); + private static final Collection ALLOWED_VERSIONS = Arrays.asList(new String[] {"1.0", "1.1", "1.2"}); private DefaultModuleDescriptor _md; private DefaultDependencyDescriptor _dd; @@ -229,9 +229,10 @@ public class XmlModuleDescriptorParser extends DefaultHandler { org = _md.getModuleRevisionId().getOrganisation(); } boolean force = Boolean.valueOf(attributes.getValue("force")).booleanValue(); + boolean changing = Boolean.valueOf(attributes.getValue("changing")).booleanValue(); String name = _ivy.substitute(attributes.getValue("name")); String rev = _ivy.substitute(attributes.getValue("rev")); - _dd = new DefaultDependencyDescriptor(_md, ModuleRevisionId.newInstance(org, name, rev), force); + _dd = new DefaultDependencyDescriptor(_md, ModuleRevisionId.newInstance(org, name, rev), force, changing); _md.addDependency(_dd); String confs = attributes.getValue("conf"); if (confs != null && confs.length() > 0) { diff --git a/src/java/fr/jayasoft/ivy/xml/ivy.xsd b/src/java/fr/jayasoft/ivy/xml/ivy.xsd index 4cb65b2d..5925096f 100644 --- a/src/java/fr/jayasoft/ivy/xml/ivy.xsd +++ b/src/java/fr/jayasoft/ivy/xml/ivy.xsd @@ -159,6 +159,7 @@ + diff --git a/test/java/fr/jayasoft/ivy/resolver/FileSystemResolverTest.java b/test/java/fr/jayasoft/ivy/resolver/FileSystemResolverTest.java index d138a775..30b53299 100644 --- a/test/java/fr/jayasoft/ivy/resolver/FileSystemResolverTest.java +++ b/test/java/fr/jayasoft/ivy/resolver/FileSystemResolverTest.java @@ -5,7 +5,10 @@ */ package fr.jayasoft.ivy.resolver; +import java.io.BufferedReader; import java.io.File; +import java.io.FileReader; +import java.io.Reader; import java.util.Date; import java.util.GregorianCalendar; @@ -155,6 +158,76 @@ public class FileSystemResolverTest extends TestCase { assertEquals(pubdate, rmr.getPublicationDate()); } + public void testChanging() throws Exception { + FileSystemResolver resolver = new FileSystemResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + _ivy.addResolver(resolver); + assertEquals("test", resolver.getName()); + + resolver.addIvyPattern("test"+FS+"repositories"+FS+"checkmodified"+FS+"ivy-[revision].xml"); + resolver.addArtifactPattern("test"+FS+"repositories"+FS+"checkmodified"+FS+"[artifact]-[revision].[ext]"); + File modify = new File("test/repositories/checkmodified/ivy-1.0.xml"); + File artifact = new File("test/repositories/checkmodified/mod1.1-1.0.jar"); + + // 'publish' 'before' version + FileUtil.copy(new File("test/repositories/checkmodified/ivy-1.0-before.xml"), modify, null); + FileUtil.copy(new File("test/repositories/checkmodified/mod1.1-1.0-before.jar"), artifact, null); + Date pubdate = new GregorianCalendar(2004, 10, 1, 11, 0, 0).getTime(); + modify.setLastModified(pubdate.getTime()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "1.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + assertEquals(pubdate, rmr.getPublicationDate()); + + Artifact[] artifacts = rmr.getDescriptor().getArtifacts("default"); + resolver.download(artifacts, _ivy, _cache); + File archiveFileInCache = _ivy.getArchiveFileInCache(_cache, artifacts[0]); + assertTrue(archiveFileInCache.exists()); + BufferedReader r = new BufferedReader(new FileReader(archiveFileInCache)); + assertEquals("before", r.readLine()); + r.close(); + + // updates ivy file and artifact in repository + FileUtil.copy(new File("test/repositories/checkmodified/ivy-1.0-after.xml"), modify, null); + FileUtil.copy(new File("test/repositories/checkmodified/mod1.1-1.0-after.jar"), artifact, null); + pubdate = new GregorianCalendar(2005, 4, 1, 11, 0, 0).getTime(); + modify.setLastModified(pubdate.getTime()); + // no need to update new artifact timestamp cause it isn't used + + // should not get the new version: checkmodified is false and edpendency is not told to be a changing one + resolver.setCheckmodified(false); + rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + assertEquals(new GregorianCalendar(2004, 10, 1, 11, 0, 0).getTime(), rmr.getPublicationDate()); + + assertTrue(archiveFileInCache.exists()); + r = new BufferedReader(new FileReader(archiveFileInCache)); + assertEquals("before", r.readLine()); + r.close(); + + // should now get the new version cause we say it's a changing one + rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false, true), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + assertEquals(pubdate, rmr.getPublicationDate()); + + assertFalse(archiveFileInCache.exists()); + + artifacts = rmr.getDescriptor().getArtifacts("default"); + resolver.download(artifacts, _ivy, _cache); + assertTrue(archiveFileInCache.exists()); + r = new BufferedReader(new FileReader(archiveFileInCache)); + assertEquals("after", r.readLine()); + r.close(); +} + public void testLatestTime() throws Exception { FileSystemResolver resolver = new FileSystemResolver(); resolver.setName("test"); diff --git a/test/repositories/checkmodified/mod1.1-1.0-after.jar b/test/repositories/checkmodified/mod1.1-1.0-after.jar new file mode 100644 index 00000000..5c80f32d --- /dev/null +++ b/test/repositories/checkmodified/mod1.1-1.0-after.jar @@ -0,0 +1 @@ +after \ No newline at end of file diff --git a/test/repositories/checkmodified/mod1.1-1.0-before.jar b/test/repositories/checkmodified/mod1.1-1.0-before.jar new file mode 100644 index 00000000..ee2363a4 --- /dev/null +++ b/test/repositories/checkmodified/mod1.1-1.0-before.jar @@ -0,0 +1 @@ +before \ No newline at end of file