import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.Version;
import org.sonar.api.utils.log.Loggers;
import org.sonar.db.dialect.H2;
import org.sonar.db.dialect.MsSql;
// MsSQL 2012 is 11.x
// MsSQL 2014 is 12.x
// https://support.microsoft.com/en-us/kb/321185
- MsSql.ID, new Version(10, 0),
- MySql.ID, new Version(5, 6),
- Oracle.ID, new Version(11, 0),
- PostgreSql.ID, new Version(8, 0));
+ MsSql.ID, Version.create(10, 0, 0),
+ MySql.ID, Version.create(5, 6, 0),
+ Oracle.ID, Version.create(11, 0, 0),
+ PostgreSql.ID, Version.create(8, 0, 0));
private final Database db;
try (Connection connection = db.getDataSource().getConnection()) {
int dbMajorVersion = connection.getMetaData().getDatabaseMajorVersion();
int dbMinorVersion = connection.getMetaData().getDatabaseMinorVersion();
- Version dbVersion = new Version(dbMajorVersion, dbMinorVersion);
- if (!dbVersion.isGreaterThanOrEqual(minDbVersion)) {
+ Version dbVersion = Version.create(dbMajorVersion, dbMinorVersion, 0);
+ if (dbVersion.compareTo(minDbVersion) < 0) {
throw MessageException.of(String.format(
"Unsupported %s version: %s. Minimal supported version is %s.", db.getDialect().getId(), dbVersion, minDbVersion));
}
}
}
}
-
- private static class Version {
- private final int major;
- private final int minor;
-
- public Version(int major, int minor) {
- this.major = major;
- this.minor = minor;
- }
-
- public boolean isGreaterThanOrEqual(Version other) {
- return major >= other.major && (major != other.major || minor >= other.minor);
- }
-
- @Override
- public String toString() {
- return new StringBuilder().append(major).append(".").append(minor).toString();
- }
- }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.utils;
+
+import com.google.common.base.Splitter;
+import java.util.List;
+import javax.annotation.concurrent.Immutable;
+
+import static java.lang.Integer.parseInt;
+import static org.apache.commons.lang.StringUtils.substringAfter;
+import static org.apache.commons.lang.StringUtils.substringBefore;
+import static org.apache.commons.lang.StringUtils.trimToEmpty;
+
+/**
+ * TODO document equals/comparison without qualifier
+ * @since 5.5
+ */
+@Immutable
+public class Version implements Comparable<Version> {
+
+ private static final String QUALIFIER_SEPARATOR = "-";
+ private static final char SEQUENCE_SEPARATOR = '.';
+ private static final Splitter SEQUENCE_SPLITTER = Splitter.on(SEQUENCE_SEPARATOR);
+
+ private final int major;
+ private final int minor;
+ private final int patch;
+ private final String qualifier;
+
+ private Version(int major, int minor, int patch, String qualifier) {
+ this.major = major;
+ this.minor = minor;
+ this.patch = patch;
+ this.qualifier = qualifier;
+ }
+
+ public int major() {
+ return major;
+ }
+
+ public int minor() {
+ return minor;
+ }
+
+ public int patch() {
+ return patch;
+ }
+
+ /**
+ * @return non-null suffix
+ */
+ public String qualifier() {
+ return qualifier;
+ }
+
+ public static Version parse(String text) {
+ String s = trimToEmpty(text);
+ String qualifier = substringAfter(s, QUALIFIER_SEPARATOR);
+ if (!qualifier.isEmpty()) {
+ s = substringBefore(s, QUALIFIER_SEPARATOR);
+ }
+ List<String> split = SEQUENCE_SPLITTER.splitToList(s);
+ int major = 0;
+ int minor = 0;
+ int patch = 0;
+ if (split.size() > 0) {
+ major = parseSequence(split.get(0));
+ if (split.size() > 1) {
+ minor = parseSequence(split.get(1));
+ if (split.size() > 2) {
+ patch = parseSequence(split.get(2));
+ if (split.size() > 3) {
+ throw new IllegalArgumentException("Only 3 sequences are accepted");
+ }
+ }
+ }
+ }
+ return new Version(major, minor, patch, qualifier);
+ }
+
+ public static Version create(int major, int minor) {
+ return new Version(major, minor, 0, "");
+ }
+
+ public static Version create(int major, int minor, int patch) {
+ return new Version(major, minor, patch, "");
+ }
+
+ public static Version create(int major, int minor, int patch, String qualifier) {
+ return new Version(major, minor, patch, qualifier);
+ }
+
+ private static int parseSequence(String sequence) {
+ if (sequence.isEmpty()) {
+ return 0;
+ }
+ return parseInt(sequence);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Version)) {
+ return false;
+ }
+ Version other = (Version) o;
+ return major == other.major && minor == other.minor && patch == other.patch;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = major;
+ result = 31 * result + minor;
+ result = 31 * result + patch;
+ return result;
+ }
+
+ @Override
+ public int compareTo(Version other) {
+ int c = major - other.major;
+ if (c == 0) {
+ c = minor - other.minor;
+ if (c == 0) {
+ c = patch - other.patch;
+ }
+ }
+ return c;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(major).append(SEQUENCE_SEPARATOR).append(minor);
+ if (patch > 0) {
+ sb.append(SEQUENCE_SEPARATOR).append(patch);
+ }
+ if (!qualifier.isEmpty()) {
+ sb.append(QUALIFIER_SEPARATOR).append(qualifier);
+ }
+ return sb.toString();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.utils;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.utils.Version.parse;
+
+public class VersionTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void test_parse() {
+ assertVersion(parse(""), 0, 0, 0, "");
+ assertVersion(parse("1"), 1, 0, 0, "");
+ assertVersion(parse("1.2"), 1, 2, 0, "");
+ assertVersion(parse("1.2.3"), 1, 2, 3, "");
+ assertVersion(parse("1.2-beta-1"), 1, 2, 0, "beta-1");
+ assertVersion(parse("1.2.3-beta1"), 1, 2, 3, "beta1");
+ assertVersion(parse("1.2.3-beta-1"), 1, 2, 3, "beta-1");
+ }
+
+ @Test
+ public void parse_throws_IAE_if_more_than_3_sequences() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Only 3 sequences are accepted");
+ parse("1.2.3.4");
+ }
+
+ @Test
+ public void test_equals() {
+ Version one = parse("1");
+ assertThat(one).isEqualTo(one);
+ assertThat(one).isEqualTo(parse("1"));
+ assertThat(one).isEqualTo(parse("1.0"));
+ assertThat(one).isEqualTo(parse("1.0.0"));
+ assertThat(one).isNotEqualTo(parse("1.2.3"));
+
+ assertThat(parse("1.2.3")).isEqualTo(parse("1.2.3"));
+ assertThat(parse("1.2.3")).isNotEqualTo(parse("1.2.4"));
+ assertThat(parse("1.2.3")).isEqualTo(parse("1.2.3-b1"));
+ assertThat(parse("1.2.3-b1")).isEqualTo(parse("1.2.3-b2"));
+ }
+
+ @Test
+ public void test_hashCode() {
+ assertThat(parse("1").hashCode()).isEqualTo(parse("1").hashCode());
+ assertThat(parse("1").hashCode()).isEqualTo(parse("1.0.0").hashCode());
+ assertThat(parse("1.2.3-beta1").hashCode()).isEqualTo(parse("1.2.3").hashCode());
+ }
+
+ @Test
+ public void test_compareTo() {
+ assertThat(parse("1.2").compareTo(parse("1.2.0"))).isEqualTo(0);
+ assertThat(parse("1.2.3").compareTo(parse("1.2.3"))).isEqualTo(0);
+ assertThat(parse("1.2.3").compareTo(parse("1.2.4"))).isLessThan(0);
+ assertThat(parse("1.2.3").compareTo(parse("1.3"))).isLessThan(0);
+ assertThat(parse("1.2.3").compareTo(parse("2.1"))).isLessThan(0);
+ assertThat(parse("1.2.3").compareTo(parse("2.0.0"))).isLessThan(0);
+ assertThat(parse("2.0").compareTo(parse("1.2"))).isGreaterThan(0);
+ }
+
+ @Test
+ public void qualifier_is_ignored_from_comparison() {
+ assertThat(parse("1.2.3")).isEqualTo(parse("1.2.3-build1"));
+ assertThat(parse("1.2.3")).isEqualTo(parse("1.2.3-build1"));
+ assertThat(parse("1.2.3").compareTo(parse("1.2.3-build1"))).isEqualTo(0);
+ }
+
+ @Test
+ public void test_toString() {
+ assertThat(parse("1").toString()).isEqualTo("1.0");
+ assertThat(parse("1.2").toString()).isEqualTo("1.2");
+ assertThat(parse("1.2.3").toString()).isEqualTo("1.2.3");
+ assertThat(parse("1.2-b1").toString()).isEqualTo("1.2-b1");
+ assertThat(parse("1.2.3-b1").toString()).isEqualTo("1.2.3-b1");
+ }
+
+ private static void assertVersion(Version version,
+ int expectedMajor, int expectedMinor, int expectedPatch, String expectedQualifier) {
+ assertThat(version.major()).isEqualTo(expectedMajor);
+ assertThat(version.minor()).isEqualTo(expectedMinor);
+ assertThat(version.patch()).isEqualTo(expectedPatch);
+ assertThat(version.qualifier()).isEqualTo(expectedQualifier);
+ }
+}