Hi,
While working on the Bushel project (http://code.google.com/p/bushel/)
to add OSGi bundle support to Ivy, I stumbled across a limitation in
the LatestRevisionStrategy. The current implementation sorts OSGi
major.minor.micro[.qualifier] in what I think is the wrong order.
For example, from the LatestRevisionStrategyTest.testComparator()
test, the natural order of both OSGi and non-OSGi versions is:
0.2a, 0.2_b, 0.2rc1, 0.2-final, 1.0-dev1, 1.0-dev2, 1.0-alpha1,
1.0-alpha2, 1.0-beta1, 1.0-beta2, 1.0-gamma, 1.0-rc1, 1.0-rc2, 1.0,
1.0.1, 2.0, 2.0.0, 2.0.0.b006, 2.0.0.b012, 2.0.0.xyz
However, the current implementation produces the following, where the
last four elements are in the wrong order:
0.2a, 0.2_b, 0.2rc1, 0.2-final, 1.0-dev1, 1.0-dev2, 1.0-alpha1,
1.0-alpha2, 1.0-beta1, 1.0-beta2, 1.0-gamma, 1.0-rc1, 1.0-rc2, 1.0,
1.0.1, 2.0, 2.0.0.b006, 2.0.0.b012, 2.0.0.xyz, 2.0.0
This is because it currently gives equal weighting to the [._-+]
characters, instead of giving the '.' character precedence. I have
attached a patch the fixes this limitation, as well as updating the
unit test. I have also fixed a minor bug in the test where it assumed
the versions were shuffled, but they weren't.
The current way to work around this is to override all the
latest-strategies in the ivysettings.xml, which I'd like to avoid if
possible. For example:
...
...
I hope you can use this patch.
Cheers,
Alex
Index: test/java/org/apache/ivy/plugins/latest/LatestRevisionStrategyTest.java
===
--- test/java/org/apache/ivy/plugins/latest/LatestRevisionStrategyTest.java (revision 684210)
+++ test/java/org/apache/ivy/plugins/latest/LatestRevisionStrategyTest.java (working copy)
@@ -29,7 +29,8 @@
public void testComparator() {
ArtifactInfo[] revs = toMockAI(new String[] {"0.2a", "0.2_b", "0.2rc1", "0.2-final",
"1.0-dev1", "1.0-dev2", "1.0-alpha1", "1.0-alpha2", "1.0-beta1", "1.0-beta2",
-"1.0-gamma", "1.0-rc1", "1.0-rc2", "1.0", "1.0.1", "2.0"});
+"1.0-gamma", "1.0-rc1", "1.0-rc2", "1.0", "1.0.1",
+"2.0", "2.0.0", "2.0.0.b006","2.0.0.b012","2.0.0.xyz"});
List shuffled = new ArrayList(Arrays.asList(revs));
Collections.shuffle(shuffled);
@@ -57,6 +58,7 @@
"1.0-gamma", "1.0-rc1", "1.0-rc2", "1.0", "1.0.1", "2.0"});
List shuffled = new ArrayList(Arrays.asList(revs));
+Collections.shuffle(shuffled);
ArtifactInfo[] shuffledRevs = (ArtifactInfo[]) shuffled
.toArray(new ArtifactInfo[revs.length]);
Index: src/java/org/apache/ivy/plugins/latest/LatestRevisionStrategy.java
===
--- src/java/org/apache/ivy/plugins/latest/LatestRevisionStrategy.java (revision 684210)
+++ src/java/org/apache/ivy/plugins/latest/LatestRevisionStrategy.java (working copy)
@@ -21,12 +21,18 @@
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.regex.Pattern;
import org.apache.ivy.core.IvyContext;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.plugins.version.VersionMatcher;
public class LatestRevisionStrategy extends ComparatorLatestStrategy {
+
+private static final Pattern ALPHA_NUM_REGEX = Pattern.compile("([a-zA-Z])(\\d)");
+private static final Pattern NUM_ALPHA_REGEX = Pattern.compile("(\\d)([a-zA-Z])");
+private static final Pattern LABEL_REGEX = Pattern.compile("[_\\-\\+]");
+
/**
* Compares two ModuleRevisionId by their revision. Revisions are compared using an algorithm
* inspired by PHP version_compare one.
@@ -35,50 +41,68 @@
public int compare(Object o1, Object o2) {
String rev1 = ((ModuleRevisionId) o1).getRevision();
String rev2 = ((ModuleRevisionId) o2).getRevision();
-
-rev1 = rev1.replaceAll("([a-zA-Z])(\\d)", "$1.$2");
-rev1 = rev1.replaceAll("(\\d)([a-zA-Z])", "$1.$2");
-rev2 = rev2.replaceAll("([a-zA-Z])(\\d)", "$1.$2");
-rev2 = rev2.replaceAll("(\\d)([a-zA-Z])", "$1.$2");
-
-String[] parts1 = rev1.split("[\\._\\-\\+]");
-String[] parts2 = rev2.split("[\\._\\-\\+]");
-
-int i = 0;
-for (; i < parts1.length && i < parts2.length; i++) {
-if (parts1[i].equals(parts2[i])) {
+
+String[] outerParts1 = rev1.split("[\\.]");
+String[] outerParts2 = rev2.split("[\\.]");
+
+for (int i=0; i < outerParts1.length && i < outerParts2.length; i++) {
+String outerPart1 = outerParts1[i];
+String outerPart2 = outerParts2[i];
+
+if (outerPart1.equals(outerPart2)) {
continue;