mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
SemVer: add support for prerelease segment
GitOrigin-RevId: a34541971cfddf8bd3feb9f9437595f9f392c960
This commit is contained in:
committed by
intellij-monorepo-bot
parent
7ee7b84af1
commit
b1b95561d8
@@ -2841,6 +2841,29 @@ public class StringUtil extends StringUtilRt {
|
||||
return ignoreCase ? s1.compareToIgnoreCase(s2) : s1.compareTo(s2);
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
public static int compare(@Nullable CharSequence s1, @Nullable CharSequence s2, boolean ignoreCase) {
|
||||
if (s1 == s2) return 0;
|
||||
if (s1 == null) return -1;
|
||||
if (s2 == null) return 1;
|
||||
|
||||
int length1 = s1.length();
|
||||
int length2 = s2.length();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (; i < length1 && j < length2; i++, j++) {
|
||||
int diff = compare(s1.charAt(i), s2.charAt(j), ignoreCase);
|
||||
if (diff != 0) {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
if (i < length1) return +1;
|
||||
if (j < length2) return -1;
|
||||
if (length1 != length2) return length1 - length2;
|
||||
|
||||
return ignoreCase ? compare(s1, s2, false) : 0;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
public static int comparePairs(@Nullable String s1, @Nullable String t1, @Nullable String s2, @Nullable String t2, boolean ignoreCase) {
|
||||
final int compare = compare(s1, s2, ignoreCase);
|
||||
@@ -3399,4 +3422,4 @@ public class StringUtil extends StringUtilRt {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,23 +19,34 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Holds <a href="http://semver.org">Semantic Version</a>.
|
||||
*/
|
||||
public final class SemVer implements Comparable<SemVer> {
|
||||
/** @deprecated */
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated public static final SemVer UNKNOWN = new SemVer("?", 0, 0, 0);
|
||||
|
||||
private final String myRawVersion;
|
||||
private final int myMajor;
|
||||
private final int myMinor;
|
||||
private final int myPatch;
|
||||
@Nullable
|
||||
private final String myPreRelease;
|
||||
|
||||
public SemVer(@NotNull String rawVersion, int major, int minor, int patch) {
|
||||
this(rawVersion, major, minor, patch, null);
|
||||
}
|
||||
|
||||
public SemVer(@NotNull String rawVersion, int major, int minor, int patch, @Nullable String preRelease) {
|
||||
myRawVersion = rawVersion;
|
||||
myMajor = major;
|
||||
myMinor = minor;
|
||||
myPatch = patch;
|
||||
myPreRelease = preRelease;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -55,9 +66,14 @@ public final class SemVer implements Comparable<SemVer> {
|
||||
return myPatch;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPreRelease() {
|
||||
return myPreRelease;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getParsedVersion() {
|
||||
return myMajor + "." + myMinor + "." + myPatch;
|
||||
return myMajor + "." + myMinor + "." + myPatch + (myPreRelease != null ? "-" + myPreRelease : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,7 +84,10 @@ public final class SemVer implements Comparable<SemVer> {
|
||||
diff = myMinor - other.myMinor;
|
||||
if (diff != 0) return diff;
|
||||
|
||||
return myPatch - other.myPatch;
|
||||
diff = myPatch - other.myPatch;
|
||||
if (diff != 0) return diff;
|
||||
|
||||
return comparePrerelease(myPreRelease, other.myPreRelease);
|
||||
}
|
||||
|
||||
public boolean isGreaterOrEqualThan(int major, int minor, int patch) {
|
||||
@@ -83,7 +102,10 @@ public final class SemVer implements Comparable<SemVer> {
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
SemVer semVer = (SemVer)o;
|
||||
return myMajor == semVer.myMajor && myMinor == semVer.myMinor && myPatch == semVer.myPatch;
|
||||
return myMajor == semVer.myMajor
|
||||
&& myMinor == semVer.myMinor
|
||||
&& myPatch == semVer.myPatch
|
||||
&& Objects.equals(myPreRelease, semVer.myPreRelease);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,6 +113,9 @@ public final class SemVer implements Comparable<SemVer> {
|
||||
int result = myMajor;
|
||||
result = 31 * result + myMinor;
|
||||
result = 31 * result + myPatch;
|
||||
if (myPreRelease != null) {
|
||||
result = 31 * result + myPreRelease.hashCode();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -99,6 +124,83 @@ public final class SemVer implements Comparable<SemVer> {
|
||||
return myRawVersion;
|
||||
}
|
||||
|
||||
private static int comparePrerelease(@Nullable String pre1, @Nullable String pre2) {
|
||||
if (pre1 == null) {
|
||||
return pre2 == null ? 0 : 1;
|
||||
}
|
||||
else if (pre2 == null) {
|
||||
return -1;
|
||||
}
|
||||
int length1 = pre1.length();
|
||||
int length2 = pre2.length();
|
||||
|
||||
if (length1 == length2 && pre1.equals(pre2)) return 0;
|
||||
|
||||
int start1 = 0;
|
||||
int start2 = 0;
|
||||
int diff;
|
||||
|
||||
// compare each segment separately
|
||||
do {
|
||||
int end1 = pre1.indexOf('.', start1);
|
||||
int end2 = pre2.indexOf('.', start2);
|
||||
|
||||
if (end1 < 0) end1 = length1;
|
||||
if (end2 < 0) end2 = length2;
|
||||
|
||||
|
||||
CharSequence segment1 = new CharSequenceSubSequence(pre1, start1, end1);
|
||||
CharSequence segment2 = new CharSequenceSubSequence(pre2, start2, end2);
|
||||
if (isNumeric(segment1)) {
|
||||
if (!isNumeric(segment2)) {
|
||||
return -1;
|
||||
}
|
||||
diff = compareNumeric(segment1, segment2);
|
||||
}
|
||||
else if (isNumeric(segment2)) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
diff = StringUtil.compare(segment1, segment2, false);
|
||||
}
|
||||
start1 = end1 + 1;
|
||||
start2 = end2 + 1;
|
||||
}
|
||||
while (diff == 0 && start1 < length1 && start2 < length2);
|
||||
|
||||
if (diff != 0) return diff;
|
||||
if (start1 >= length1) {
|
||||
if (start2 >= length2) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int compareNumeric(CharSequence segment1, CharSequence segment2) {
|
||||
int length1 = segment1.length();
|
||||
int length2 = segment2.length();
|
||||
int diff = Integer.compare(length1, length2);
|
||||
for (int i = 0; i <= length1 && diff == 0; i++) {
|
||||
diff = segment1.charAt(i) - segment2.charAt(i);
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
|
||||
private static boolean isNumeric(CharSequence segment) {
|
||||
int length = segment.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int ch = segment.charAt(i);
|
||||
if (ch < '0' || ch > '9') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SemVer parseFromText(@Nullable String text) {
|
||||
if (text != null) {
|
||||
@@ -106,14 +208,16 @@ public final class SemVer implements Comparable<SemVer> {
|
||||
if (majorEndIdx >= 0) {
|
||||
int minorEndIdx = text.indexOf('.', majorEndIdx + 1);
|
||||
if (minorEndIdx >= 0) {
|
||||
int patchEndIdx = text.indexOf('-', minorEndIdx + 1);
|
||||
if (patchEndIdx < 0) patchEndIdx = text.length();
|
||||
int preReleaseIdx = text.indexOf('-', minorEndIdx + 1);
|
||||
int patchEndIdx = preReleaseIdx >= 0 ? preReleaseIdx : text.length();
|
||||
|
||||
int major = StringUtil.parseInt(text.substring(0, majorEndIdx), -1);
|
||||
int minor = StringUtil.parseInt(text.substring(majorEndIdx + 1, minorEndIdx), -1);
|
||||
int patch = StringUtil.parseInt(text.substring(minorEndIdx + 1, patchEndIdx), -1);
|
||||
String preRelease = preReleaseIdx >= 0 ? text.substring(preReleaseIdx + 1) : null;
|
||||
|
||||
if (major >= 0 && minor >= 0 && patch >= 0) {
|
||||
return new SemVer(text, major, minor, patch);
|
||||
return new SemVer(text, major, minor, patch, preRelease);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.util.text;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -23,15 +24,15 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class SemVerTest {
|
||||
@Test
|
||||
public void parsing() {
|
||||
assertParsed("0.9.2", 0, 9, 2);
|
||||
assertParsed("0.9.2-", 0, 9, 2);
|
||||
assertParsed("0.9.2-dart", 0, 9, 2);
|
||||
assertParsed("4.0.0-alpha.1", 4, 0, 0);
|
||||
assertParsed("0.10.0-rc-1", 0, 10, 0);
|
||||
assertParsed("1.0.0-rc-1", 1, 0, 0);
|
||||
assertParsed("1.0.0-alpha", 1, 0, 0);
|
||||
assertParsed("1.0.0-0.3.7", 1, 0, 0);
|
||||
assertParsed("1.0.0-x.7.z.92", 1, 0, 0);
|
||||
assertParsed("0.9.2", 0, 9, 2, null);
|
||||
assertParsed("0.9.2-", 0, 9, 2, "");
|
||||
assertParsed("0.9.2-dart", 0, 9, 2, "dart");
|
||||
assertParsed("4.0.0-alpha.1", 4, 0, 0, "alpha.1");
|
||||
assertParsed("0.10.0-rc-1", 0, 10, 0, "rc-1");
|
||||
assertParsed("1.0.0-rc-1", 1, 0, 0, "rc-1");
|
||||
assertParsed("1.0.0-alpha", 1, 0, 0, "alpha");
|
||||
assertParsed("1.0.0-0.3.7", 1, 0, 0, "0.3.7");
|
||||
assertParsed("1.0.0-x.7.z.92", 1, 0, 0, "x.7.z.92");
|
||||
|
||||
assertNotParsed(null);
|
||||
assertNotParsed("");
|
||||
@@ -42,31 +43,60 @@ public class SemVerTest {
|
||||
|
||||
@Test
|
||||
public void comparing() {
|
||||
assertThat(parse("1.0.0")).isGreaterThan(parse("0.10.0"));
|
||||
assertThat(parse("1.0.0")).isLessThan(parse("2.10.0"));
|
||||
|
||||
assertThat(parse("0.30.0")).isGreaterThan(parse("0.5.1000"));
|
||||
assertThat(parse("0.30.10")).isLessThan(parse("0.100.0"));
|
||||
|
||||
assertThat(parse("2.9.123-test")).isGreaterThan(parse("2.9.100"));
|
||||
assertThat(parse("2.9.123-test")).isLessThan(parse("2.9.124"));
|
||||
|
||||
assertThat(parse("11.123.0")).isEqualTo(parse("11.123.0"));
|
||||
assertThat(parse("11.123.0")).isEqualByComparingTo(parse("11.123.0"));
|
||||
|
||||
assertThat(parse("11.123.0-a.b.c-1")).isEqualTo(parse("11.123.0-a.b.c-1"));
|
||||
assertThat(parse("11.123.0-a.b.c-1")).isEqualByComparingTo(parse("11.123.0-a.b.c-1"));
|
||||
|
||||
assertPrecedence("0.10.0", "1.0.0");
|
||||
assertPrecedence("1.0.0","2.10.0");
|
||||
assertPrecedence("0.5.1000", "0.30.0");
|
||||
assertPrecedence("0.30.10","0.100.0");
|
||||
|
||||
assertPrecedence("2.9.100", "2.9.123-test");
|
||||
assertPrecedence("2.9.123-test","2.9.124");
|
||||
assertPrecedence("2.9.123","2.9.124-test");
|
||||
|
||||
assertPrecedence("1.2.3-a","1.2.3");
|
||||
|
||||
assertPrecedence("1.2.3-12","1.2.3-a");
|
||||
assertPrecedence("1.2.3-22","1.2.3-100");
|
||||
assertPrecedence("1.2.3-22","1.2.3-31");
|
||||
|
||||
assertPrecedence("1.2.3-a.b.c","1.2.3-a.b.d");
|
||||
assertPrecedence("1.2.3-a.b.c","1.2.3-a.b.c.a");
|
||||
|
||||
assertPrecedence("1.2.3-a.b.1","1.2.3-a.b.c");
|
||||
assertPrecedence("1.2.3-a.b.1","1.2.3-a.c.1");
|
||||
assertPrecedence("1.2.3-a.cbc.100","1.2.3-a.cca.1");
|
||||
assertPrecedence("1.2.3-a.cb.1","1.2.3-a.cba.1");
|
||||
|
||||
Assert.assertTrue(parse("4.12.5").isGreaterOrEqualThan(4, 12, 5));
|
||||
Assert.assertTrue(parse("4.12.5-a").isGreaterOrEqualThan(4, 12, 5));
|
||||
Assert.assertTrue(parse("4.12.5").isGreaterOrEqualThan(4, 12, 4));
|
||||
Assert.assertTrue(parse("4.12.5-a").isGreaterOrEqualThan(4, 12, 4));
|
||||
Assert.assertTrue(parse("4.12.5").isGreaterOrEqualThan(4, 11, 0));
|
||||
Assert.assertTrue(parse("4.12.5").isGreaterOrEqualThan(4, 11, 9));
|
||||
Assert.assertTrue(parse("4.12.5").isGreaterOrEqualThan(3, 100, 100));
|
||||
|
||||
Assert.assertFalse(parse("4.12.5").isGreaterOrEqualThan(4, 12, 6));
|
||||
Assert.assertFalse(parse("4.12.5-a").isGreaterOrEqualThan(4, 12, 6));
|
||||
Assert.assertFalse(parse("4.12.5").isGreaterOrEqualThan(4, 13, 0));
|
||||
Assert.assertFalse(parse("4.12.5").isGreaterOrEqualThan(5, 1, 0));
|
||||
}
|
||||
|
||||
private static void assertParsed(String version, int expectedMajor, int expectedMinor, int expectedPatch) {
|
||||
assertThat(parse(version)).isEqualTo(new SemVer(version, expectedMajor, expectedMinor, expectedPatch));
|
||||
private static void assertPrecedence(String lesserVersion, String higherVersion) {
|
||||
SemVer v1 = parse(lesserVersion);
|
||||
SemVer v2 = parse(higherVersion);
|
||||
assertThat(v1).isLessThan(v2);
|
||||
assertThat(v2).isGreaterThan(v1);
|
||||
assertThat(v1).isNotEqualByComparingTo(v2);
|
||||
assertThat(v1).isNotEqualTo(v2);
|
||||
}
|
||||
|
||||
private static void assertParsed(String version, int expectedMajor, int expectedMinor, int expectedPatch, @Nullable String expectedPreRelease) {
|
||||
assertThat(parse(version)).isEqualTo(new SemVer(version, expectedMajor, expectedMinor, expectedPatch, expectedPreRelease));
|
||||
}
|
||||
|
||||
private static void assertNotParsed(String version) {
|
||||
@@ -78,4 +108,4 @@ public class SemVerTest {
|
||||
assertThat(semVer).describedAs(text).isNotNull();
|
||||
return semVer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user