diff --git a/src/main/java/com/spotify/reaper/cassandra/JmxProxy.java b/src/main/java/com/spotify/reaper/cassandra/JmxProxy.java index a2ec22bc2..f2f974867 100644 --- a/src/main/java/com/spotify/reaper/cassandra/JmxProxy.java +++ b/src/main/java/com/spotify/reaper/cassandra/JmxProxy.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.math.BigInteger; import java.net.MalformedURLException; +import java.text.NumberFormat; import java.util.AbstractMap; import java.util.Collection; import java.util.HashSet; @@ -385,7 +386,7 @@ public void close() throws ReaperException { } /** - * NOTICE: This code is copied from StackOverflow answer: + * NOTICE: This code is loosely based on StackOverflow answer: * http://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java * * Compares two version strings. @@ -402,24 +403,39 @@ public void close() throws ReaperException { */ public static Integer versionCompare(String str1, String str2) throws ReaperException { try { - str1 = str1.split(" ")[0].replaceAll("[^0-9.]", ""); - str2 = str2.split(" ")[0].replaceAll("[^0-9.]", "");; - String[] vals1 = str1.split("\\."); - String[] vals2 = str2.split("\\."); + str1 = str1.split(" ")[0].replaceAll("[-_~]", "."); + str2 = str2.split(" ")[0].replaceAll("[-_~]", "."); + String[] parts1 = str1.split("\\."); + String[] parts2 = str2.split("\\."); int i = 0; // set index to first non-equal ordinal or length of shortest version string - while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) { - i++; + while (i < parts1.length && i < parts2.length) { + try { + Integer.parseInt(parts1[i]); + Integer.parseInt(parts2[i]); + } catch (NumberFormatException ex) { + if (i == 0) { + throw ex; // just comparing two non-version strings should fail + } + // first non integer part, so let's just stop comparison here and ignore this part + i--; + break; + } + if (parts1[i].equals(parts2[i])) { + i++; + continue; + } + break; } // compare first non-equal ordinal number - if (i < vals1.length && i < vals2.length) { - int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i])); + if (i < parts1.length && i < parts2.length) { + int diff = Integer.valueOf(parts1[i]).compareTo(Integer.valueOf(parts2[i])); return Integer.signum(diff); } // the strings are equal or one string is a substring of the other // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" else { - return Integer.signum(vals1.length - vals2.length); + return Integer.signum(parts1.length - parts2.length); } } catch (Exception ex) { LOG.error("failed comparing strings for versions: '{}' '{}'", str1, str2); diff --git a/src/test/java/com/spotify/reaper/cassandra/JmxProxyTest.java b/src/test/java/com/spotify/reaper/cassandra/JmxProxyTest.java index d09dd49ea..5047e41bb 100644 --- a/src/test/java/com/spotify/reaper/cassandra/JmxProxyTest.java +++ b/src/test/java/com/spotify/reaper/cassandra/JmxProxyTest.java @@ -32,6 +32,8 @@ public void testVersionCompare() throws ReaperException { assertEquals(Integer.valueOf(1), JmxProxy.versionCompare("99.0.0", "9.0")); assertEquals(Integer.valueOf(1), JmxProxy.versionCompare("99.0.10", "99.0.1")); assertEquals(Integer.valueOf(-1), JmxProxy.versionCompare("99.0.10~1", "99.0.10~2")); + assertEquals(Integer.valueOf(0), JmxProxy.versionCompare("1.2.18-1~1.2.15.219.gec18fb4.9", + "1.2.18-1~1.2.15.219.gec17fb4.10")); } }