diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java index 759b01b2a..8a6319cfa 100644 --- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java +++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java @@ -176,26 +176,33 @@ public String toString() { static final class Tokenizer { - private static final Integer QUALIFIER_ALPHA = -5; + private static final Integer QUALIFIER_ALPHA = -7; - private static final Integer QUALIFIER_BETA = -4; + private static final Integer QUALIFIER_BETA = -6; - private static final Integer QUALIFIER_MILESTONE = -3; + private static final Integer QUALIFIER_MILESTONE = -5; private static final Map QUALIFIERS; static { QUALIFIERS = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + // PRE RELEASE QUALIFIERS.put("alpha", QUALIFIER_ALPHA); QUALIFIERS.put("beta", QUALIFIER_BETA); QUALIFIERS.put("milestone", QUALIFIER_MILESTONE); - QUALIFIERS.put("cr", -2); - QUALIFIERS.put("rc", -2); + QUALIFIERS.put("pr", -4); + QUALIFIERS.put("pre", -4); + QUALIFIERS.put("preview", -4); + QUALIFIERS.put("rc", -3); + QUALIFIERS.put("cr", -3); + QUALIFIERS.put("dev", -2); QUALIFIERS.put("snapshot", -1); - QUALIFIERS.put("ga", 0); + // RELEASE + QUALIFIERS.put("", 0); QUALIFIERS.put("final", 0); + QUALIFIERS.put("ga", 0); QUALIFIERS.put("release", 0); - QUALIFIERS.put("", 0); + // POST RELEASE QUALIFIERS.put("sp", 1); } diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java index 32ba67f4b..3e8232ec7 100644 --- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java +++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersionScheme.java @@ -36,8 +36,9 @@ *

* Numeric segments are compared mathematically, alphabetic segments are compared lexicographically and * case-insensitively. However, the following qualifier strings are recognized and treated specially: "alpha" = "a" < - * "beta" = "b" < "milestone" = "m" < "cr" = "rc" < "snapshot" < "final" = "ga" < "sp". All of those - * well-known qualifiers are considered smaller/older than other strings. An empty segment/string is equivalent to 0. + * "beta" = "b" < "milestone" = "m" < "pr" = "pre" = "preview" < "rc" = "cr" < "dev" < "snapshot" < + * "final" = "ga" = "release" < "sp". All of those well-known qualifiers are considered smaller/older than other + * strings. An empty segment/string is equivalent to 0. *

*

* In addition to the above mentioned qualifiers, the tokens "min" and "max" may be used as final version segment to diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/package-info.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/package-info.java index ad3f40473..0a43a685b 100644 --- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/package-info.java +++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/package-info.java @@ -42,18 +42,20 @@ *

  • "alpha" (== "a" when immediately followed by number)
  • *
  • "beta" (== "b" when immediately followed by number)
  • *
  • "milestone" (== "m" when immediately followed by number)
  • - *
  • "rc" == "cr" (use of "cr" is discouraged)
  • + *
  • "pr" = "pre" = "preview" (use is discouraged)
  • + *
  • "rc" == "cr" (use of "cr" is discouraged, use rc instead)
  • + *
  • "dev" (use is discouraged)
  • *
  • "snapshot"
  • - *
  • "ga" == "final" == "release"
  • - *
  • "sp"
  • + *
  • "final" == "ga" == "release" (use is discouraged, use no qualifier instead)
  • + *
  • "sp" (use of "sp" is discouraged, increment patch version instead)
  • * * *
  • String segments are sorted lexicographically and case-insensitively per ROOT locale, ascending.
  • *
  • There are two special segments, {@code "min"} and {@code "max"} that represent absolute minimum and absolute maximum in comparisons. They can be used only as the trailing segment.
  • *
  • As last step, trailing "zero segments" are trimmed. Similarly, "zero segments" positioned before numeric and non-numeric transitions (either explicitly or implicitly delimited) are trimmed.
  • - *
  • When trimming, "zero segments" are qualifiers {@code "ga"}, {@code "final"}, {@code "release"} only if being last (right-most) segment, empty string and "0" always.
  • + *
  • When trimming, "zero segments" are qualifiers {@code "final"}, {@code "ga"}, {@code "release"} only if being last (right-most) segment, empty string and "0" always.
  • *
  • In comparison of same kind segments, the given type of segment determines comparison rules.
  • - *
  • In comparison of different kind of segments, following applies: {@code max > numeric > string > qualifier > min}.
  • + *
  • In comparison of different kind of segments, following applies: {@code min < qualifier < string < numeric < max}.
  • *
  • Any version can be considered to have an infinite number of invisible trailing "zero segments", for the purposes of comparison (in other words, "1" == "1.0.0.0.0.0.0.0.0....")
  • *
  • It is common that a version identifier starts with numeric segment (consider this "best practice").
  • * diff --git a/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java b/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java index cbcfe92f4..a3687e715 100644 --- a/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java +++ b/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java @@ -632,4 +632,98 @@ private Stream uuidVersionStringStream() { "f95e94f7-2443-4b2f-a10d-059d8d224dd9", "b558af80-78bc-43c7-b916-d635a23cc4b5"); } + + /** + * Test MNG-5568 edge case + * which was showing transitive inconsistency: since A > B and B > C then we should have A > C + * otherwise sorting a list of ComparableVersions() will in some cases throw runtime exception; + * see Netbeans issues 240845 and + * 226100 + */ + @Test + void testMng5568() { + assertOrder(X_LT_Y, "6.1.0rc3", "6.1H.5-beta"); + assertOrder(X_LT_Y, "6.1.0rc3", "6.1.0"); // classical + assertOrder(X_LT_Y, "6.1.0", "6.1H.5-beta"); // transitivity + } + + /** + * Test MNG-6572 optimization. + */ + @Test + void testMng6572() { + String a = "20190126.230843"; // resembles a SNAPSHOT + String b = "1234567890.12345"; // 10 digit number + String c = "123456789012345.1H.5-beta"; // 15 digit number + String d = "12345678901234567890.1H.5-beta"; // 20 digit number + + assertOrder(X_LT_Y, a, b); + assertOrder(X_LT_Y, b, c); + assertOrder(X_LT_Y, a, c); + assertOrder(X_LT_Y, c, d); + assertOrder(X_LT_Y, b, d); + assertOrder(X_LT_Y, a, d); + } + + /** + * Test MNG-6964 edge cases + * for qualifiers that start with "-0.", which was showing A == C and B == C but A < B. + */ + @Test + void testMng6964() { + String a = "1-0.alpha"; + String b = "1-0.beta"; + String c = "1"; + + assertOrder(X_LT_Y, a, c); // Now a < c, but before MNG-6964 they were equal + assertOrder(X_LT_Y, b, c); // Now b < c, but before MNG-6964 they were equal + assertOrder(X_LT_Y, a, b); // Should still be true + } + + /** + * Test MNG-7559 edge cases + * -pfd < final, ga, release + * 2.0.1.MR < 2.0.1 + * 9.4.1.jre16 > 9.4.1.jre16-preview + */ + @Test + void testMng7559() { + // checking general cases + // assertSequence("ab", "alpha", "beta", "cd", "ea", "milestone", "pfd", "preview", "RC"); + assertSequence("alpha", "beta", "milestone", "preview", "rc", "dev", "snapshot", ""); + // checking identified issues respect the general case + // assertOrder(X_LT_Y, "2.3-pfd", "2.3"); + // assertOrder(X_LT_Y, "2.0.1.MR", "2.0.1"); + assertOrder(X_LT_Y, "9.4.1.jre16-preview", "9.4.1.jre16"); + assertOrder(X_LT_Y, "1-ga-1", "1-sp-1"); + } + + /** + * Test MNG-7644 edge cases + * 1.0.0.RC1 < 1.0.0-RC2 and more generally: + * 1.0.0.X1 < 1.0.0-X2 for any string X + */ + @Test + void testMng7644() { + for (String x : new String[] {"abc", "alpha", "a", "beta", "b", "def", "m", "preview", "RC"}) { + // 1.0.0.X1 < 1.0.0-X2 for any string x + assertOrder(X_LT_Y, "1.0.0." + x + "1", "1.0.0-" + x + "2"); + // 2.0.X1 == 2-X1 == 2.0.0.X1 for any string x + assertOrder(X_EQ_Y, "2-" + x + "1", "2.0." + x + "1"); // previously ordered, now equals + assertOrder(X_EQ_Y, "2-" + x + "1", "2.0.0." + x + "1"); // previously ordered, now equals + assertOrder(X_EQ_Y, "2.0." + x + "1", "2.0.0." + x + "1"); // previously ordered, now equals + } + } + + @Test + public void testMng7714() { + String f = ("1.0.final-redhat"); + String sp1 = ("1.0-sp1-redhat"); + String sp2 = ("1.0-sp-1-redhat"); + String sp3 = ("1.0-sp.1-redhat"); + assertOrder(X_LT_Y, f, sp1); + assertOrder(X_LT_Y, f, sp2); + assertOrder(X_LT_Y, f, sp3); + } + }