diff --git a/main/commons/src/main/java/org/cryptomator/common/SemVerComparator.java b/main/commons/src/main/java/org/cryptomator/common/SemVerComparator.java
index 930e2e93d..e6975d1aa 100644
--- a/main/commons/src/main/java/org/cryptomator/common/SemVerComparator.java
+++ b/main/commons/src/main/java/org/cryptomator/common/SemVerComparator.java
@@ -12,12 +12,51 @@ import java.util.Comparator;
import org.apache.commons.lang3.StringUtils;
+/**
+ * Compares version strings according to SemVer 2.0.0.
+ */
public class SemVerComparator implements Comparator {
+ private static final char VERSION_SEP = '.'; // http://semver.org/spec/v2.0.0.html#spec-item-2
+ private static final String PRE_RELEASE_SEP = "-"; // http://semver.org/spec/v2.0.0.html#spec-item-9
+ private static final String BUILD_SEP = "+"; // http://semver.org/spec/v2.0.0.html#spec-item-10
+
@Override
public int compare(String version1, String version2) {
- final String[] vComps1 = StringUtils.split(version1, '.');
- final String[] vComps2 = StringUtils.split(version2, '.');
+ // "Build metadata SHOULD be ignored when determining version precedence.
+ // Thus two versions that differ only in the build metadata, have the same precedence."
+ String v1WithoutBuildMetadata = StringUtils.substringBefore(version1, BUILD_SEP);
+ String v2WithoutBuildMetadata = StringUtils.substringBefore(version2, BUILD_SEP);
+
+ if (v1WithoutBuildMetadata.equals(v2WithoutBuildMetadata)) {
+ return 0;
+ }
+
+ String v1MajorMinorPatch = StringUtils.substringBefore(v1WithoutBuildMetadata, PRE_RELEASE_SEP);
+ String v2MajorMinorPatch = StringUtils.substringBefore(v2WithoutBuildMetadata, PRE_RELEASE_SEP);
+ String v1PreReleaseVersion = StringUtils.substringAfter(v1WithoutBuildMetadata, PRE_RELEASE_SEP);
+ String v2PreReleaseVersion = StringUtils.substringAfter(v2WithoutBuildMetadata, PRE_RELEASE_SEP);
+ return compare(v1MajorMinorPatch, v1PreReleaseVersion, v2MajorMinorPatch, v2PreReleaseVersion);
+ }
+
+ private int compare(String v1MajorMinorPatch, String v1PreReleaseVersion, String v2MajorMinorPatch, String v2PreReleaseVersion) {
+ int comparisonResult = compareNumericallyThenLexicographically(v1MajorMinorPatch, v2MajorMinorPatch);
+ if (comparisonResult == 0) {
+ if (v1PreReleaseVersion.isEmpty()) {
+ return 1; // 1.0.0 > 1.0.0-BETA
+ } else if (v2PreReleaseVersion.isEmpty()) {
+ return -1; // 1.0.0-BETA < 1.0.0
+ } else {
+ return compareNumericallyThenLexicographically(v1PreReleaseVersion, v2PreReleaseVersion);
+ }
+ } else {
+ return comparisonResult;
+ }
+ }
+
+ private int compareNumericallyThenLexicographically(String version1, String version2) {
+ final String[] vComps1 = StringUtils.split(version1, VERSION_SEP);
+ final String[] vComps2 = StringUtils.split(version2, VERSION_SEP);
final int commonCompCount = Math.min(vComps1.length, vComps2.length);
for (int i = 0; i < commonCompCount; i++) {
@@ -35,7 +74,7 @@ public class SemVerComparator implements Comparator {
}
}
- // all in common so far? longest version string wins:
+ // all in common so far? longest version string is considered the higher version:
return vComps1.length - vComps2.length;
}
diff --git a/main/commons/src/test/java/org/cryptomator/common/SemVerComparatorTest.java b/main/commons/src/test/java/org/cryptomator/common/SemVerComparatorTest.java
index 859eb9471..f9c44c0b2 100644
--- a/main/commons/src/test/java/org/cryptomator/common/SemVerComparatorTest.java
+++ b/main/commons/src/test/java/org/cryptomator/common/SemVerComparatorTest.java
@@ -10,7 +10,6 @@ package org.cryptomator.common;
import java.util.Comparator;
-import org.cryptomator.common.SemVerComparator;
import org.junit.Assert;
import org.junit.Test;
@@ -22,8 +21,10 @@ public class SemVerComparatorTest {
@Test
public void compareEqualVersions() {
- final int comparisonResult = semVerComparator.compare("1.23.4", "1.23.4");
- Assert.assertEquals(0, Integer.signum(comparisonResult));
+ Assert.assertEquals(0, Integer.signum(semVerComparator.compare("1.23.4", "1.23.4")));
+ Assert.assertEquals(0, Integer.signum(semVerComparator.compare("1.23.4-alpha", "1.23.4-alpha")));
+ Assert.assertEquals(0, Integer.signum(semVerComparator.compare("1.23.4+20170101", "1.23.4+20171231")));
+ Assert.assertEquals(0, Integer.signum(semVerComparator.compare("1.23.4-alpha+20170101", "1.23.4-alpha+20171231")));
}
// newer versions in first argument
@@ -33,7 +34,11 @@ public class SemVerComparatorTest {
Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.5", "1.23.4")));
Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.24.4", "1.23.4")));
Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4", "1.23")));
- Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4a", "1.23.4")));
+ Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4", "1.23.4-SNAPSHOT")));
+ Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4", "1.23.4-56.78")));
+ Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4-beta", "1.23.4-alpha")));
+ Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4-alpha.1", "1.23.4-alpha")));
+ Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4-56.79", "1.23.4-56.78")));
}
// newer versions in second argument
@@ -43,7 +48,11 @@ public class SemVerComparatorTest {
Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4", "1.23.5")));
Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4", "1.24.4")));
Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23", "1.23.4")));
- Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4", "1.23.4a")));
+ Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4-SNAPSHOT", "1.23.4")));
+ Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4-56.78", "1.23.4")));
+ Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4-alpha", "1.23.4-beta")));
+ Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4-alpha", "1.23.4-alpha.1")));
+ Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4-56.78", "1.23.4-56.79")));
}
}