Hello Loren, thanks for digging into all this.
It might not be a good thing for softwares like ivy which have a lot of users in the wild to change defaults - because people like to be able to upgrade and still have an old behavior, but making the needed behaviors possible at least should be done. Your point 2 makes sense to me though, if two artifacts have as version 1.0-SNAPSHOT we should compare their timestamp. Point 3 your help will be welcome. Best regards, Antoine On Mar 25, 2015, at 3:00 PM, Martin Gainty <mgai...@hotmail.com> wrote: > > > >> From: lkrat...@blueorigin.com >> To: dev@ant.apache.org >> Subject: RE: Possible Ivy bug (and suggested fix) in ChainResolver >> Date: Wed, 25 Mar 2015 18:16:08 +0000 >> >> I found the root cause of the fishiness. It was not a bug (and was not >> actually in ChainResolver) but is in my opinion a rather unfortunate and >> poorly chosen default setting that is to blame (the latest-strategy). >> >> During resolution in the chain resolver, the current sub-resolver tries to >> determine whether it should be skipped and the previous artifact be selected >> over the current artifact. Assuming that the "force" and "dynamic" tests do >> not result in an early rejection of the current artifact, the "latest" of >> the two artifacts is selected by sorting the artifacts in a List using a >> Comparator suited to the current latest-strategy (latest-revision, >> latest-time, etc). >> >> The problem here is quite simple. The default latest-strategy is >> "latest-revision". So when a second artifact has been resolved, and it is of >> the same revision as the first, nothing gets sorted. The result is that you >> will get the first artifact found based upon the ordering of your >> repositories in the chain instead of the newer of the two artifacts. >> >> I think that either latest-time needs to be the default strategy or the >> latest revision comparator needs to do a secondary sort to sort by >> lastModified time. >> >> Possibly allow configuration of this behavior (should there be a secondary >> sort by time to avoid stale artifacts, or not so that repository order >> breaks the tie). This is important (critical) behavior and should be >> configurable. >> >> Defaulting to latest-revision will not only deliver undesired stale >> artifacts, but it is unclear to the user why they are getting stale >> artifacts or how to make it stop happening. The latest-time strategy will >> give you the latest revision 99% of the time and the latest artifact 100% of >> the time. But the latest-revision strategy will give you the latest artifact >> 100%, 50%, 33%, or 25% of the time when the revision numbers are the same, >> depending upon how many resolvers you have (1/n), and assuming that any >> repository may contain the latest artifact. >> >> Furthermore, the docs do not give a great description of "force". I learned >> much about the actual behavior of this attribute while debugging. First >> thing I learned was that it is not a good name. >> >> What force actually does is it allows a resolver to be considered when a >> previous resolver has found an artifact. After the first artifact has been >> found, only repositories with force=true will have a chance of competing >> (for instance, they might have a newer version of 1.0.0-SNAPSHOT). >> Otherwise, they are discarded immediately and no date comparison is >> attempted. >> >> Force should actually be named "considerAlways" or "considerAnyway". That >> seems to be a more suitable name. No action requested here, but pointing out >> that this attribute has a misleading name. >> >> Summary: >> 1 - Please reconsider changing the default latest-strategy to be latest-time. >> >> 2 - Please consider adding a secondary "lastModified" sort to >> LatestRevisionStrategy.ArtifactInfoComparator whether or not you change the >> default latest-strategy to latest-time or not. >> >> 3 - Please document, illustrate, and demonstrate in one place the behaviors >> of chain resolver in combination with force, returnFirst, >> defaultLatestStrategy, ivy.resolver.default.check.modified, useOrigin, and >> other settings and attributes that affect resolution behavior. (I am working >> on this document now.) >> >> 4 - Please consider creating independent caches by default for each >> repository. I have not drilled down on this issue yet, but I suspect that it >> fixes serious cache collision issues that I think I saw while debugging >> (found and selected local repo artifact, checked cache before delivery, >> ended up delivering cached stale artifact that came from a totally different >> repo :( ). >> >> Thanks, >> >> L.K. > > MG>i think we can take hints from maven brothers on a tested strategy > MG>to referencing dev jars during development..their solution is to employ > SNAPSHOT version during CI cycles > MG>SNAPSHOTs are available until the jar is promoted to RELEASE at which > point a tag is assigned to version > MG>SNAPSHOT delivers ${project.id}-YYYYMMDD.hhmmss.jar so unless you have > multiple machines able to gen > MG>deployables within a second the last second is the arbiter which clearly > identifies the latest jar > MG>Snapshot versions are ephemeral until the next snapshot build so remote > lookup would not be implemented > http://books.sonatype.com/mvnref-book/reference/pom-relationships-sect-pom-syntax.html > > MG>repository caches when stored within a regular Nexus Repository are typed > as Proxy/Hosted/Virtual > MG>ProxyApache,ProxyCentral or ProxyCodehaus > MG>Hosted3rdParty,HostedRelease,HostedSnapshot > MG>VirtualRepo (Virtual repos are generally for OSGI bundles) > MG>Once you know the general type Proxy or Hosted or Virtual you can then > select sub-type (such as Hosted3rdParty,HostedRelease,HostedSnapshot) > https://books.sonatype.com/nexus-book/reference/confignx-sect-manage-repo.html > MG>thank you for taking the necessary time to think this through > >> >> From: Loren Kratzke >> Sent: Tuesday, March 24, 2015 1:09 PM >> To: 'dev@ant.apache.org' >> Subject: Possible Ivy bug (and suggested fix) in ChainResolver >> >> I have a some observations about how the chain resolver selects a >> dependency. I think this may be a bug but I am not sure because the intent >> of the source code is not entirely clear. It reads one way, but behaves in a >> different way. I have pinpointed the exact spots in code where this happens. >> >> Here is my simple test setup used to debug this issue. I have two resolvers >> (Filesystem and URL) configured in a ChainResolver in that order. I publish >> to one resolver and then the other repeatedly and consume the result in >> another project. I use checkModified=true and changingPattern=".*" on both >> resolvers. >> >> My artifact is simply a text file with the current date and time so it is >> easy to see whether you get fresh or stale artifacts from the repos. >> >> When I consume the published artifact from the other project, I will get the >> artifact from the first configured resolver in the chain (Filesystem in this >> case). But I know from debugging that the second resolver is also evaluated. >> So as an experiment, I added force="true" on the second resolver to see if I >> could force Ivy to ignore the first result and favor an artifact returned by >> the second resolver. Instead, Ivy returned the artifact from the first >> resolver even though the second artifact was newer AND the second resolver >> had force="true". >> >> When I debugged this to see why the first artifact was chosen over the >> second artifact, I found something very fishy. >> >> ChainResolver.getDependency() iterates over each resolver in the chain. >> First it found the Filesystem resolver and the artifact and next it found >> the URL resolver and artifact. Next it calls BasicResolver.getDependency() >> which will compare the previously resolved artifact with the current >> artifact. >> >> This is where it gets very fishy. At the end of the getDependency() method >> it calls AbstractResolver.checkLatest() which I assume is intended to return >> the latest of the two artifacts. But that comparison never happens. >> AbstractResolver.isAfter is invoked with two artifacts to be compared and a >> null Date. Since the date is null, the two artifacts are never compared and >> no matter what, the first artifact will be returned and the second one >> discarded and a verbose message will be emitted stating that the second >> artifact is older than the first artifact, every time. The message is on >> line 533 of AbstractResolver. (I am looking at Ivy-2.3.0 so if that line >> does not make sense on trunk then let me know.) >> >> Message.debug("\tmodule revision kept as younger: " + newModuleDesc); >> saveModuleRevisionIfNeeded(dd, newModuleFound); >> return newModuleFound; >> >> The message is not true. The artifact that was kept was the older of the two >> and a comparison of lastModified never happened (and never can happen in the >> current code as far as I can tell). >> >> So the actual logic in AbstractResolver.checkLatest() simply returns the >> first artifact found. While this is not a bad behavior, it does not seem >> like it is the intended behavior. I mean, why go through all the trouble of >> pretending to compare two artifacts using date methods when the logic never >> executes because the passed in Date object is null. And why emit a message >> stating that one was determined to be older than the other. That is super >> fishy. >> >> Furthermore, the next line in ChainResolver.getDependency() after >> resolver.getDependency() is called (ChainResolver line105) references >> isReturnFirst(). That is fishy because none of that matters any more. The >> current artifact was rejected on the previous line of code and the previous >> (aka first) artifact is now the current artifact and is the one that will be >> returned (without a date comparison, and for the arbitrary reason that is >> was found before the other one). >> >> I think that the intent of the null Date object is to compare each artifact >> to a static Date configured elsewhere (I have no idea where), but if the >> code were to actually compare the lastModified dates of the two artifacts, a >> useful result would happen - Ivy would return the latest artifact from >> across multiple repositories. >> >> That is huge because I have never been able to get Ivy to do this. I have >> never seen anybody get Ivy to search multiple repositories and return the >> latest artifact. This is useful for local development when you publish >> locally to consume locally modified artifacts. It would be nice to have the >> option of picking up newer artifacts from a central repo when those occur >> without having to blow away a local repository and its cache. >> >> (By the way, giving my local repo its own cache seems to have solved some >> other strange issues I was having. I recommend this to everybody and I think >> it should be a default in Ivy, but that is debatable and would need some >> more research and concensus.) >> >> I think that this is a good feature and should be configurable. I think >> possibly it was intended to be configured via >> ChainResolver.returnFirst="true|false" but that code executed when it was >> too late and the decision had already been made. If I were to make this a >> feature, and make it configurable, I would configure this using an attribute >> named returnFirst because that is the exact facet of functionality that we >> are talking about here. >> >> Thanks for your attention. Hope I am helping here. I am considering coding >> this to see if it works as expected. I would be happy to report my results >> and provide a patch if anybody is interested in evaluating this. >> >> L.K.