From c894120c016e3ed0a45e9a70c1cb6073514bf7d5 Mon Sep 17 00:00:00 2001 From: Vitaly Brodetskyi Date: Fri, 19 Jan 2018 19:02:28 +0200 Subject: [PATCH 1/6] AMBARI-22817. Update backend code to handle new versioning schema.(vbrodetskyi) --- .../libraries/functions/module_version.py | 152 +++++++++++++ .../libraries/functions/mpack_version.py | 200 ++++++++++++++++++ .../ambari/server/utils/ModuleVersion.java | 110 ++++++++++ .../ambari/server/utils/MpackVersion.java | 130 ++++++++++++ .../ambari/server/utils/TestVersionUtils.java | 97 ++++++++- ambari-server/src/test/python/TestVersion.py | 100 ++++++++- 6 files changed, 785 insertions(+), 4 deletions(-) create mode 100644 ambari-common/src/main/python/resource_management/libraries/functions/module_version.py create mode 100644 ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py create mode 100644 ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java create mode 100644 ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/module_version.py b/ambari-common/src/main/python/resource_management/libraries/functions/module_version.py new file mode 100644 index 00000000000..9853bb7027f --- /dev/null +++ b/ambari-common/src/main/python/resource_management/libraries/functions/module_version.py @@ -0,0 +1,152 @@ +""" + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import re + + +class ModuleVersion(object): + __module_version_pattern = "(?P[0-9]+).(?P[0-9]+).(?P[0-9]+).(?P[0-9]+)(-h(?P[0-9]+))*-b(?P[0-9]+)" + __module_version_regex = re.compile(__module_version_pattern) + + def __init__(self, apache_major, apache_minor, internal_minor, internal_maint, hotfix, build): + """ + :type apache_major int + :type apache_minor int + :type internal_maint int + :type internal_minor int + :type hotfix int + :type build int + """ + self.__apache_major = int(apache_major) + self.__apache_minor = int(apache_minor) + self.__internal_maint = int(internal_maint) + self.__internal_minor = int(internal_minor) + self.__hotfix = int(hotfix) if hotfix else 0 # hotfix is optional group + self.__build = int(build) + + def __repr__(self): + return "{0}.{1}.{2}.{3}-h{4}-b{5}".format(*self.to_list()) + + def to_list(self): + """ + Return version elements as list + + :rtype list + """ + return [ + self.__apache_major, + self.__apache_minor, + self.__internal_minor, + self.__internal_maint, + self.__hotfix, + self.__build + ] + + def __cmp__(self, other): + """ + :type other ModuleVersion + + :raise TypeError + """ + if other and not isinstance(other, self.__class__): + raise TypeError("Operand type is different from {0}".format(self.__class__.__name__)) + + r = 0 + x = self.to_list() + y = other.to_list() + + for i in range(0, len(x)): + r = x[i] - y[i] + if r != 0: + break + + return 1 if r > 0 else -1 if r < 0 else 0 + + @classmethod + def parse(cls, module_version): + """ + Parse string to module version + + :type module_version str + :rtype ModuleVersion + """ + matcher = cls.validate(module_version) + return ModuleVersion( + matcher.group("aMajor"), + matcher.group("aMinor"), + matcher.group("iMinor"), + matcher.group("iMaint"), + matcher.group("hotfix"), + matcher.group("build") + ) + + @classmethod + def validate(cls, module_version): + """ + Check if provided version is valid. If version is valid will return match object + or will raise exception. + + :param module_version version to check + :type module_version str + + :rtype __Match[T] | None + + :raise ValueError + """ + + if not module_version: + raise ValueError("Module version can't be empty or null") + + version = module_version.strip() + + if not version: + raise ValueError("Module version can't be empty or null") + + matcher = cls.__module_version_regex.match(version) + + if not matcher: + raise ValueError("{0} is not a valid {1}".format(version, cls.__name__)) + + return matcher + + @property + def apache_major(self): + return self.__apache_major + + @property + def apache_minor(self): + return self.__apache_minor + + @property + def internal_minor(self): + return self.__internal_minor + + @property + def internal_maint(self): + return self.__internal_maint + + @property + def hotfix(self): + return self.__hotfix + + @property + def build(self): + return self.__build + + + diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py b/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py new file mode 100644 index 00000000000..5d8a15b5086 --- /dev/null +++ b/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py @@ -0,0 +1,200 @@ +""" + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import re + + +class MpackVersion(object): + __module_version_pattern = "(?P[0-9]+).(?P[0-9]+).(?P[0-9]+)(-h(?P[0-9]+))*-b(?P[0-9]+)" + __module_legacy_stack_version_pattern = "(?P[0-9]+).(?P[0-9]+).(?P[0-9]+).(?P[0-9]+)(-(?P[0-9]+))" + __module_version_regex = re.compile(__module_version_pattern) + __module_legacy_stack_version_regex = re.compile(__module_legacy_stack_version_pattern) + + def __init__(self, major, minor, maint, hotfix, build): + """ + :type major int + :type minor int + :type maint int + :type hotfix int + :type build int + """ + self.__major = int(major) + self.__minor = int(minor) + self.__maint = int(maint) + self.__hotfix = int(hotfix) if hotfix else 0 # hotfix is optional group + self.__build = int(build) + + def __repr__(self): + return "{0}.{1}.{2}-h{3}-b{4}".format(*self.to_list()) + + def to_list(self): + """ + Return version elements as list + + :rtype list + """ + return [ + self.__major, + self.__minor, + self.__maint, + self.__hotfix, + self.__build + ] + + def __cmp__(self, other): + """ + :type other MpackVersion + + :raise TypeError + """ + if other and not isinstance(other, self.__class__): + raise TypeError("Operand type is different from {0}".format(self.__class__.__name__)) + + r = 0 + x = self.to_list() + y = other.to_list() + + for i in range(0, len(x)): + r = x[i] - y[i] + if r != 0: + break + + return 1 if r > 0 else -1 if r < 0 else 0 + + @classmethod + def parse(cls, mpack_version): + """ + Parse string to mpack version + + :type mpack_version str + :rtype MpackVersion + """ + matcher = cls.validate(mpack_version) + return MpackVersion( + matcher.group("major"), + matcher.group("minor"), + matcher.group("maint"), + matcher.group("hotfix"), + matcher.group("build") + ) + + + @classmethod + def parse_stack_version(cls, stack_version): + """ + Parse string to mpack version + + :type stack_version str + :rtype MpackVersion + """ + matcher = cls.validate_stack_version(stack_version) + return MpackVersion( + matcher.group("major"), + matcher.group("minor"), + matcher.group("maint"), + matcher.group("hotfix"), + matcher.group("build") + ) + + + @classmethod + def validate_stack_version(cls, stack_version): + """ + Check if provided version is valid. If version is valid will return match object + or will raise exception. + + :param stack_version version to check + :type stack_version str + + :rtype __Match[T] | None + + :raise ValueError + """ + + if not stack_version: + raise ValueError("Module version can't be empty or null") + + version = stack_version.strip() + + if not version: + raise ValueError("Module version can't be empty or null") + + matcher = cls.__module_version_regex.match(version) + + if not matcher: + matcher = cls.__module_legacy_stack_version_regex.match(version) + if not matcher: + raise ValueError("{0} is not a valid {1}".format(version, cls.__name__)) + else: + if not matcher.group("hotfix"): + raise ValueError("{0} is not a valid {1}".format(version, cls.__name__)) + + return matcher + + + @classmethod + def validate(cls, mpack_version): + """ + Check if provided version is valid. If version is valid will return match object + or will raise exception. + + :param module_version version to check + :type module_version str + + :rtype __Match[T] | None + + :raise ValueError + """ + + if not mpack_version: + raise ValueError("Module version can't be empty or null") + + version = mpack_version.strip() + + if not version: + raise ValueError("Module version can't be empty or null") + + matcher = cls.__module_version_regex.match(version) + + if not matcher: + raise ValueError("{0} is not a valid {1}".format(version, cls.__name__)) + + return matcher + + @property + def major(self): + return self.__major + + @property + def minor(self): + return self.__minor + + @property + def maint(self): + return self.__maint + + @property + def hotfix(self): + return self.__hotfix + + @property + def build(self): + return self.__build + + + diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java new file mode 100644 index 00000000000..260d551c24b --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.utils; + + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; + +public class ModuleVersion implements Comparable { + + private static final String versionWithHotfixAndBuildPattern = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-h([0-9]+)-b([0-9]+)"; + private static final String versionWithBuildPattern = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-b([0-9]+)"; + + private int apacheMajor; + private int apacheMinor; + private int internalMinor; + private int internalMaint; + private int hotfix; + private int build; + + + public ModuleVersion(int apacheMajor, int apacheMinor, int internalMinor, int internalMaint, int hotfix, int build) { + this.apacheMajor = apacheMajor; + this.apacheMinor = apacheMinor; + this.internalMinor = internalMinor; + this.internalMaint = internalMaint; + this.hotfix = hotfix; + this.build = build; + } + + public static ModuleVersion parse(String moduleVersion) { + Matcher versionMatcher = validateModuleVersion(moduleVersion); + ModuleVersion result = null; + + if (versionMatcher.pattern().pattern().equals(versionWithHotfixAndBuildPattern)) { + result = new ModuleVersion(Integer.parseInt(versionMatcher.group(1)), Integer.parseInt(versionMatcher.group(2)), + Integer.parseInt(versionMatcher.group(3)), Integer.parseInt(versionMatcher.group(4)), + Integer.parseInt(versionMatcher.group(5)), Integer.parseInt(versionMatcher.group(6))); + + } else { + result = new ModuleVersion(Integer.parseInt(versionMatcher.group(1)), Integer.parseInt(versionMatcher.group(2)), + Integer.parseInt(versionMatcher.group(3)), Integer.parseInt(versionMatcher.group(4)), 0, + Integer.parseInt(versionMatcher.group(5))); + + } + + return result; + } + + + private static Matcher validateModuleVersion(String version) { + if (StringUtils.isEmpty(version)) { + throw new IllegalArgumentException("Module version can't be empty or null"); + } + + String moduleVersion = StringUtils.trim(version); + + Pattern patternWithHotfix = Pattern.compile(versionWithHotfixAndBuildPattern); + Pattern patternWithoutHotfix = Pattern.compile(versionWithBuildPattern); + + Matcher versionMatcher = patternWithHotfix.matcher(moduleVersion); + if (!versionMatcher.find()) { + versionMatcher = patternWithoutHotfix.matcher(moduleVersion); + if (!versionMatcher.find()) { + throw new IllegalArgumentException("Wrong format for module version, should be N.N.N.N-bN or N.N.N-hN-bN"); + } + } + + return versionMatcher; + } + + @Override + public int compareTo(ModuleVersion other) { + int result = this.apacheMajor - other.apacheMajor; + if(result == 0) { + result = this.apacheMinor - other.apacheMinor; + if(result == 0) { + result = this.internalMinor - other.internalMinor; + if(result == 0) { + result = this.internalMaint - other.internalMaint; + if(result == 0) { + result = this.hotfix - other.hotfix; + if(result == 0) { + result = this.build - other.build; + } + } + } + } + } + return result > 0 ? 1 : result < 0 ? -1 : 0; + } + + +} diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java new file mode 100644 index 00000000000..83d6ec90b23 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.utils; + + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; + +public class MpackVersion implements Comparable { + + private final static String versionWithHotfixAndBuildPattern = "^([0-9]+).([0-9]+).([0-9]+)-h([0-9]+)-b([0-9]+)"; + private final static String versionWithBuildPattern = "^([0-9]+).([0-9]+).([0-9]+)-b([0-9]+)"; + private final static String legacyStackVersionPattern = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-([0-9]+)"; + + private int major; + private int minor; + private int maint; + private int hotfix; + private int build; + + + public MpackVersion(int major, int minor, int maint, int hotfix, int build) { + this.major = major; + this.minor = minor; + this.maint = maint; + this.hotfix = hotfix; + this.build = build; + } + + public static MpackVersion parse(String mpackVersion) { + Matcher versionMatcher = validateMpackVersion(mpackVersion); + MpackVersion result = null; + + if (versionMatcher.pattern().pattern().equals(versionWithBuildPattern)) { + result = new MpackVersion(Integer.parseInt(versionMatcher.group(1)), Integer.parseInt(versionMatcher.group(2)), + Integer.parseInt(versionMatcher.group(3)), 0, Integer.parseInt(versionMatcher.group(4))); + + } else { + result = new MpackVersion(Integer.parseInt(versionMatcher.group(1)), Integer.parseInt(versionMatcher.group(2)), + Integer.parseInt(versionMatcher.group(3)), Integer.parseInt(versionMatcher.group(4)), Integer.parseInt(versionMatcher.group(5))); + + } + + return result; + } + + public static MpackVersion parseStackVersion(String stackVersion) { + Matcher versionMatcher = validateStackVersion(stackVersion); + MpackVersion result = new MpackVersion(Integer.parseInt(versionMatcher.group(1)), Integer.parseInt(versionMatcher.group(2)), + Integer.parseInt(versionMatcher.group(3)), Integer.parseInt(versionMatcher.group(4)), Integer.parseInt(versionMatcher.group(5))); + + return result; + } + + private static Matcher validateStackVersion(String version) { + if (StringUtils.isEmpty(version)) { + throw new IllegalArgumentException("Stack version can't be empty or null"); + } + + String stackVersion = StringUtils.trim(version); + + Pattern patternWithHotfix = Pattern.compile(versionWithHotfixAndBuildPattern); + Pattern patternLegacyStackVersion = Pattern.compile(legacyStackVersionPattern); + + Matcher versionMatcher = patternWithHotfix.matcher(stackVersion); + if (!versionMatcher.find()) { + versionMatcher = patternLegacyStackVersion.matcher(stackVersion); + if (!versionMatcher.find()) { + throw new IllegalArgumentException("Wrong format for stack version, should be N.N.N.N-N or N.N.N-hN-bN"); + } + } + + return versionMatcher; + } + + private static Matcher validateMpackVersion(String version) { + if (StringUtils.isEmpty(version)) { + throw new IllegalArgumentException("Mpack version can't be empty or null"); + } + + String mpackVersion = StringUtils.trim(version); + + Pattern patternWithHotfix = Pattern.compile(versionWithHotfixAndBuildPattern); + Pattern patternWithoutHotfix = Pattern.compile(versionWithBuildPattern); + + Matcher versionMatcher = patternWithHotfix.matcher(mpackVersion); + if (!versionMatcher.find()) { + versionMatcher = patternWithoutHotfix.matcher(mpackVersion); + if (!versionMatcher.find()) { + throw new IllegalArgumentException("Wrong format for mpack version, should be N.N.N-bN or N.N.N-hN-bN"); + } + } + + return versionMatcher; + } + + @Override + public int compareTo(MpackVersion other) { + int result = this.major - other.major; + if(result == 0) { + result = this.minor - other.minor; + if(result == 0) { + result = this.maint - other.maint; + if(result == 0) { + result = this.hotfix - other.hotfix; + if(result == 0) { + result = this.build - other.build; + } + } + } + } + return result > 0 ? 1 : result < 0 ? -1 : 0; + } +} diff --git a/ambari-server/src/test/java/org/apache/ambari/server/utils/TestVersionUtils.java b/ambari-server/src/test/java/org/apache/ambari/server/utils/TestVersionUtils.java index 42d321a7d3a..c328a942376 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/utils/TestVersionUtils.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/utils/TestVersionUtils.java @@ -17,13 +17,12 @@ */ package org.apache.ambari.server.utils; +import junit.framework.Assert; import org.apache.ambari.server.bootstrap.BootStrapImpl; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import junit.framework.Assert; - public class TestVersionUtils { @Rule @@ -168,4 +167,98 @@ public void testVersionCompareError() { expectedException.expectMessage("maxLengthToCompare cannot be less than 0"); VersionUtils.compareVersions("2", "1", -1); } + + @Test + public void testCompareVersionsWithHotfixAndBuildNumber() { + String errMessage = null; + try { + MpackVersion.parse(null); + } catch (IllegalArgumentException e) { + errMessage = e.getMessage(); + } + Assert.assertTrue("Mpack version can't be empty or null".equals(errMessage)); + + + try { + errMessage = null; + MpackVersion.parse(""); + } catch (IllegalArgumentException e) { + errMessage = e.getMessage(); + } + Assert.assertTrue("Mpack version can't be empty or null".equals(errMessage)); + + + try { + errMessage = null; + MpackVersion.parseStackVersion(null); + } catch (IllegalArgumentException e) { + errMessage = e.getMessage(); + } + Assert.assertTrue("Stack version can't be empty or null".equals(errMessage)); + + + try { + errMessage = null; + MpackVersion.parseStackVersion(""); + } catch (IllegalArgumentException e) { + errMessage = e.getMessage(); + } + Assert.assertTrue("Stack version can't be empty or null".equals(errMessage)); + + + try { + errMessage = null; + ModuleVersion.parse(null); + } catch (IllegalArgumentException e) { + errMessage = e.getMessage(); + } + Assert.assertTrue("Module version can't be empty or null".equals(errMessage)); + + + try { + errMessage = null; + ModuleVersion.parse(""); + } catch (IllegalArgumentException e) { + errMessage = e.getMessage(); + } + Assert.assertTrue("Module version can't be empty or null".equals(errMessage)); + + + try { + errMessage = null; + MpackVersion.parse("1.2.3.4-b10"); + } catch (IllegalArgumentException e) { + errMessage = e.getMessage(); + } + Assert.assertTrue("Wrong format for mpack version, should be N.N.N-bN or N.N.N-hN-bN".equals(errMessage)); + + + try { + errMessage = null; + MpackVersion.parseStackVersion("1.2.3-10"); + } catch (IllegalArgumentException e) { + errMessage = e.getMessage(); + } + Assert.assertTrue("Wrong format for stack version, should be N.N.N.N-N or N.N.N-hN-bN".equals(errMessage)); + + + try { + errMessage = null; + ModuleVersion.parse("1.2.3-10"); + } catch (IllegalArgumentException e) { + errMessage = e.getMessage(); + } + Assert.assertTrue("Wrong format for module version, should be N.N.N.N-bN or N.N.N-hN-bN".equals(errMessage)); + + + Assert.assertEquals(1, MpackVersion.parse("1.2.3-h10-b10").compareTo(MpackVersion.parseStackVersion("1.2.3.4-888"))); + Assert.assertEquals(1, MpackVersion.parse("1.2.3-h10-b10").compareTo(MpackVersion.parse("1.2.3-b888"))); + Assert.assertEquals(0, MpackVersion.parse("1.2.3-h0-b10").compareTo(MpackVersion.parse("1.2.3-b10"))); + + + Assert.assertEquals(1, ModuleVersion.parse("1.2.3.4-h10-b10").compareTo(ModuleVersion.parse("1.2.3.4-b888"))); + Assert.assertEquals(1, ModuleVersion.parse("1.2.3.5-h10-b10").compareTo(ModuleVersion.parse("1.2.3.4-b888"))); + Assert.assertEquals(0, ModuleVersion.parse("1.2.3.4-h0-b10").compareTo(ModuleVersion.parse("1.2.3.4-b10"))); + + } } diff --git a/ambari-server/src/test/python/TestVersion.py b/ambari-server/src/test/python/TestVersion.py index a8f4c650729..0b66478f826 100644 --- a/ambari-server/src/test/python/TestVersion.py +++ b/ambari-server/src/test/python/TestVersion.py @@ -16,8 +16,10 @@ limitations under the License. ''' -from unittest import TestCase import os +from unittest import TestCase +from resource_management.libraries.functions.mpack_version import MpackVersion +from resource_management.libraries.functions.module_version import ModuleVersion class TestVersion(TestCase): @@ -80,4 +82,98 @@ def test_comparison(self): except ValueError: pass else: - self.fail("Did not raise exception") \ No newline at end of file + self.fail("Did not raise exception") + + + def test_mpack_version(self): + try: + MpackVersion.parse("") + except ValueError: + pass + else: + self.fail("Did not raise exception") + + try: + MpackVersion.parse(None) + except ValueError: + pass + else: + self.fail("Did not raise exception") + + try: + MpackVersion.parse_stack_version("") + except ValueError: + pass + else: + self.fail("Did not raise exception") + + try: + MpackVersion.parse_stack_version(None) + except ValueError: + pass + else: + self.fail("Did not raise exception") + + try: + ModuleVersion.parse("") + except ValueError: + pass + else: + self.fail("Did not raise exception") + + try: + ModuleVersion.parse(None) + except ValueError: + pass + else: + self.fail("Did not raise exception") + + + try: + MpackVersion.parse("1.2.3.4-h1-b1") + except ValueError: + pass + else: + self.fail("Did not raise exception") + + try: + MpackVersion.parse_stack_version("1.1.1.1.1-1") + except ValueError: + pass + else: + self.fail("Did not raise exception") + + + try: + ModuleVersion.parse("1.1.1.1-h1") + except ValueError: + pass + else: + self.fail("Did not raise exception") + + m1 = MpackVersion.parse("1.2.3-h1-b2") + m2 = MpackVersion.parse("1.2.3-b2") + self.assertTrue(m1 > m2) + + m1 = MpackVersion.parse("1.2.3-h1-b2") + m2 = MpackVersion.parse_stack_version("1.2.3.4-33") + self.assertTrue(m1 < m2) + + m1 = MpackVersion.parse("1.2.3-h0-b10") + m2 = MpackVersion.parse("1.2.3-b10") + self.assertTrue(m1 == m2) + + m1 = ModuleVersion.parse("1.2.3.4-h10-b10") + m2 = ModuleVersion.parse("1.2.3.4-b888") + self.assertTrue(m1 > m2) + + m1 = ModuleVersion.parse("1.2.3.5-h10-b10") + m2 = ModuleVersion.parse("1.2.3.4-b888") + self.assertTrue(m1 > m2) + + m1 = ModuleVersion.parse("1.2.3.4-h0-b10") + m2 = ModuleVersion.parse("1.2.3.4-b10") + self.assertTrue(m1 == m2) + + + From 8bd252ce1c88ad1797101953e26f565d5eae0476 Mon Sep 17 00:00:00 2001 From: Vitaly Brodetskyi Date: Mon, 22 Jan 2018 18:17:40 +0200 Subject: [PATCH 2/6] AMBARI-22817. Update backend code to handle new versioning schema.(vbrodetskyi) --- .../ambari/server/utils/ModuleVersion.java | 39 ++++++-- .../ambari/server/utils/MpackVersion.java | 45 +++++++-- .../ambari/server/utils/TestVersionUtils.java | 97 ++++++++++++++----- 3 files changed, 141 insertions(+), 40 deletions(-) diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java index 260d551c24b..91d973c9e42 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java @@ -20,12 +20,16 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; + import org.apache.commons.lang.StringUtils; public class ModuleVersion implements Comparable { - private static final String versionWithHotfixAndBuildPattern = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-h([0-9]+)-b([0-9]+)"; - private static final String versionWithBuildPattern = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-b([0-9]+)"; + private static final String VERSION_WITH_HOTFIX_AND_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-h([0-9]+)-b([0-9]+)"; + private static final String VERSION_WITH_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-b([0-9]+)"; + + private static final Pattern patternWithHotfix = Pattern.compile(VERSION_WITH_HOTFIX_AND_BUILD_PATTERN); + private static final Pattern patternWithoutHotfix = Pattern.compile(VERSION_WITH_BUILD_PATTERN); private int apacheMajor; private int apacheMinor; @@ -48,7 +52,7 @@ public static ModuleVersion parse(String moduleVersion) { Matcher versionMatcher = validateModuleVersion(moduleVersion); ModuleVersion result = null; - if (versionMatcher.pattern().pattern().equals(versionWithHotfixAndBuildPattern)) { + if (versionMatcher.pattern().pattern().equals(VERSION_WITH_HOTFIX_AND_BUILD_PATTERN)) { result = new ModuleVersion(Integer.parseInt(versionMatcher.group(1)), Integer.parseInt(versionMatcher.group(2)), Integer.parseInt(versionMatcher.group(3)), Integer.parseInt(versionMatcher.group(4)), Integer.parseInt(versionMatcher.group(5)), Integer.parseInt(versionMatcher.group(6))); @@ -71,9 +75,6 @@ private static Matcher validateModuleVersion(String version) { String moduleVersion = StringUtils.trim(version); - Pattern patternWithHotfix = Pattern.compile(versionWithHotfixAndBuildPattern); - Pattern patternWithoutHotfix = Pattern.compile(versionWithBuildPattern); - Matcher versionMatcher = patternWithHotfix.matcher(moduleVersion); if (!versionMatcher.find()) { versionMatcher = patternWithoutHotfix.matcher(moduleVersion); @@ -106,5 +107,31 @@ public int compareTo(ModuleVersion other) { return result > 0 ? 1 : result < 0 ? -1 : 0; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ModuleVersion that = (ModuleVersion) o; + + if (apacheMajor != that.apacheMajor) return false; + if (apacheMinor != that.apacheMinor) return false; + if (build != that.build) return false; + if (hotfix != that.hotfix) return false; + if (internalMaint != that.internalMaint) return false; + if (internalMinor != that.internalMinor) return false; + return true; + } + + @Override + public int hashCode() { + int result = apacheMajor; + result = 31 * result + apacheMinor; + result = 31 * result + internalMinor; + result = 31 * result + internalMaint; + result = 31 * result + hotfix; + result = 31 * result + build; + return result; + } } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java index 83d6ec90b23..974cc7351d5 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java @@ -20,13 +20,18 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; + import org.apache.commons.lang.StringUtils; public class MpackVersion implements Comparable { - private final static String versionWithHotfixAndBuildPattern = "^([0-9]+).([0-9]+).([0-9]+)-h([0-9]+)-b([0-9]+)"; - private final static String versionWithBuildPattern = "^([0-9]+).([0-9]+).([0-9]+)-b([0-9]+)"; - private final static String legacyStackVersionPattern = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-([0-9]+)"; + private final static String VERSION_WITH_HOTFIX_AND_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+)-h([0-9]+)-b([0-9]+)"; + private final static String VERSION_WITH_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+)-b([0-9]+)"; + private final static String LEGACY_STACK_VERSION_PATTERN = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-([0-9]+)"; + + private final static Pattern patternWithHotfix = Pattern.compile(VERSION_WITH_HOTFIX_AND_BUILD_PATTERN); + private final static Pattern patternLegacyStackVersion = Pattern.compile(LEGACY_STACK_VERSION_PATTERN); + private final static Pattern patternWithoutHotfix = Pattern.compile(VERSION_WITH_BUILD_PATTERN); private int major; private int minor; @@ -47,7 +52,7 @@ public static MpackVersion parse(String mpackVersion) { Matcher versionMatcher = validateMpackVersion(mpackVersion); MpackVersion result = null; - if (versionMatcher.pattern().pattern().equals(versionWithBuildPattern)) { + if (versionMatcher.pattern().pattern().equals(VERSION_WITH_BUILD_PATTERN)) { result = new MpackVersion(Integer.parseInt(versionMatcher.group(1)), Integer.parseInt(versionMatcher.group(2)), Integer.parseInt(versionMatcher.group(3)), 0, Integer.parseInt(versionMatcher.group(4))); @@ -75,9 +80,6 @@ private static Matcher validateStackVersion(String version) { String stackVersion = StringUtils.trim(version); - Pattern patternWithHotfix = Pattern.compile(versionWithHotfixAndBuildPattern); - Pattern patternLegacyStackVersion = Pattern.compile(legacyStackVersionPattern); - Matcher versionMatcher = patternWithHotfix.matcher(stackVersion); if (!versionMatcher.find()) { versionMatcher = patternLegacyStackVersion.matcher(stackVersion); @@ -96,9 +98,6 @@ private static Matcher validateMpackVersion(String version) { String mpackVersion = StringUtils.trim(version); - Pattern patternWithHotfix = Pattern.compile(versionWithHotfixAndBuildPattern); - Pattern patternWithoutHotfix = Pattern.compile(versionWithBuildPattern); - Matcher versionMatcher = patternWithHotfix.matcher(mpackVersion); if (!versionMatcher.find()) { versionMatcher = patternWithoutHotfix.matcher(mpackVersion); @@ -127,4 +126,30 @@ public int compareTo(MpackVersion other) { } return result > 0 ? 1 : result < 0 ? -1 : 0; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MpackVersion that = (MpackVersion) o; + + if (build != that.build) return false; + if (hotfix != that.hotfix) return false; + if (maint != that.maint) return false; + if (major != that.major) return false; + if (minor != that.minor) return false; + + return true; + } + + @Override + public int hashCode() { + int result = major; + result = 31 * result + minor; + result = 31 * result + maint; + result = 31 * result + hotfix; + result = 31 * result + build; + return result; + } } diff --git a/ambari-server/src/test/java/org/apache/ambari/server/utils/TestVersionUtils.java b/ambari-server/src/test/java/org/apache/ambari/server/utils/TestVersionUtils.java index c328a942376..08c0a06e498 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/utils/TestVersionUtils.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/utils/TestVersionUtils.java @@ -17,14 +17,19 @@ */ package org.apache.ambari.server.utils; -import junit.framework.Assert; import org.apache.ambari.server.bootstrap.BootStrapImpl; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import junit.framework.Assert; + public class TestVersionUtils { + private static final String MODULE_ERR_MESSAGE = "Module version can't be empty or null"; + private static final String STACK_ERR_MESSAGE = "Stack version can't be empty or null"; + private static final String MPACK_ERR_MESSAGE = "Mpack version can't be empty or null"; + @Rule public ExpectedException expectedException = ExpectedException.none(); @@ -169,14 +174,14 @@ public void testVersionCompareError() { } @Test - public void testCompareVersionsWithHotfixAndBuildNumber() { + public void testMpackVersionWithNotValidVersions() { String errMessage = null; try { MpackVersion.parse(null); } catch (IllegalArgumentException e) { errMessage = e.getMessage(); } - Assert.assertTrue("Mpack version can't be empty or null".equals(errMessage)); + Assert.assertEquals(MPACK_ERR_MESSAGE, errMessage); try { @@ -185,61 +190,67 @@ public void testCompareVersionsWithHotfixAndBuildNumber() { } catch (IllegalArgumentException e) { errMessage = e.getMessage(); } - Assert.assertTrue("Mpack version can't be empty or null".equals(errMessage)); - + Assert.assertEquals(MPACK_ERR_MESSAGE, errMessage); try { errMessage = null; - MpackVersion.parseStackVersion(null); + MpackVersion.parse("1.2.3.4-b10"); } catch (IllegalArgumentException e) { errMessage = e.getMessage(); } - Assert.assertTrue("Stack version can't be empty or null".equals(errMessage)); + Assert.assertEquals("Wrong format for mpack version, should be N.N.N-bN or N.N.N-hN-bN", errMessage); + } + @Test + public void testStackVersionWithNotValidVersions() { + String errMessage = null; try { errMessage = null; - MpackVersion.parseStackVersion(""); + MpackVersion.parseStackVersion(null); } catch (IllegalArgumentException e) { errMessage = e.getMessage(); } - Assert.assertTrue("Stack version can't be empty or null".equals(errMessage)); + Assert.assertEquals(STACK_ERR_MESSAGE, errMessage); try { errMessage = null; - ModuleVersion.parse(null); + MpackVersion.parseStackVersion(""); } catch (IllegalArgumentException e) { errMessage = e.getMessage(); } - Assert.assertTrue("Module version can't be empty or null".equals(errMessage)); - + Assert.assertEquals(STACK_ERR_MESSAGE, errMessage); try { errMessage = null; - ModuleVersion.parse(""); + MpackVersion.parseStackVersion("1.2.3-10"); } catch (IllegalArgumentException e) { errMessage = e.getMessage(); } - Assert.assertTrue("Module version can't be empty or null".equals(errMessage)); + Assert.assertEquals("Wrong format for stack version, should be N.N.N.N-N or N.N.N-hN-bN", errMessage); + } + @Test + public void testModuleVersionWithNotValidVersions() { + String errMessage = null; try { errMessage = null; - MpackVersion.parse("1.2.3.4-b10"); + ModuleVersion.parse(null); } catch (IllegalArgumentException e) { errMessage = e.getMessage(); } - Assert.assertTrue("Wrong format for mpack version, should be N.N.N-bN or N.N.N-hN-bN".equals(errMessage)); + Assert.assertEquals(MODULE_ERR_MESSAGE, errMessage); try { errMessage = null; - MpackVersion.parseStackVersion("1.2.3-10"); + ModuleVersion.parse(""); } catch (IllegalArgumentException e) { errMessage = e.getMessage(); } - Assert.assertTrue("Wrong format for stack version, should be N.N.N.N-N or N.N.N-hN-bN".equals(errMessage)); + Assert.assertEquals(MODULE_ERR_MESSAGE, errMessage); try { @@ -248,17 +259,55 @@ public void testCompareVersionsWithHotfixAndBuildNumber() { } catch (IllegalArgumentException e) { errMessage = e.getMessage(); } - Assert.assertTrue("Wrong format for module version, should be N.N.N.N-bN or N.N.N-hN-bN".equals(errMessage)); - + Assert.assertEquals("Wrong format for module version, should be N.N.N.N-bN or N.N.N-hN-bN", errMessage); + } - Assert.assertEquals(1, MpackVersion.parse("1.2.3-h10-b10").compareTo(MpackVersion.parseStackVersion("1.2.3.4-888"))); + @Test + public void testMpackVersionWithValidVersions() { Assert.assertEquals(1, MpackVersion.parse("1.2.3-h10-b10").compareTo(MpackVersion.parse("1.2.3-b888"))); + Assert.assertEquals(1, MpackVersion.parse("2.2.3-h0-b10").compareTo(MpackVersion.parse("1.2.3-b888"))); + Assert.assertEquals(1, MpackVersion.parse("1.3.3-h0-b10").compareTo(MpackVersion.parse("1.2.3-b888"))); + Assert.assertEquals(1, MpackVersion.parse("1.2.4-h0-b10").compareTo(MpackVersion.parse("1.2.3-b888"))); + Assert.assertEquals(1, MpackVersion.parse("1.2.3-h0-b1000").compareTo(MpackVersion.parse("1.2.3-b888"))); Assert.assertEquals(0, MpackVersion.parse("1.2.3-h0-b10").compareTo(MpackVersion.parse("1.2.3-b10"))); + Assert.assertEquals(0, MpackVersion.parse("1.2.3-b10").compareTo(MpackVersion.parse("1.2.3-b10"))); + Assert.assertEquals(0, MpackVersion.parse("1.2.3-h0-b10").compareTo(MpackVersion.parse("1.2.3-h0-b10"))); + Assert.assertEquals(-1, MpackVersion.parse("1.2.3-h0-b10").compareTo(MpackVersion.parse("1.2.4-b10"))); + Assert.assertEquals(-1, MpackVersion.parse("1.2.3-h0-b10").compareTo(MpackVersion.parse("1.3.3-b10"))); + Assert.assertEquals(-1, MpackVersion.parse("1.2.3-h0-b10").compareTo(MpackVersion.parse("2.2.3-b10"))); + Assert.assertEquals(-1, MpackVersion.parse("1.2.3-h0-b10").compareTo(MpackVersion.parse("1.2.3-h1-b10"))); + Assert.assertEquals(-1, MpackVersion.parse("1.2.3-h0-b10").compareTo(MpackVersion.parse("1.2.3-h0-b11"))); + } + + @Test + public void testStackVersionWithValidVersions() { + Assert.assertEquals(1, MpackVersion.parse("1.2.3-h10-b10").compareTo(MpackVersion.parseStackVersion("1.2.3.4-888"))); + Assert.assertEquals(1, MpackVersion.parseStackVersion("1.2.3-h10-b10").compareTo(MpackVersion.parseStackVersion("1.2.3.4-888"))); + Assert.assertEquals(-1, MpackVersion.parse("1.2.3-h10-b10").compareTo(MpackVersion.parseStackVersion("1.2.3.11-888"))); + Assert.assertEquals(1, MpackVersion.parseStackVersion("1.2.3.4-999").compareTo(MpackVersion.parseStackVersion("1.2.3.4-888"))); + Assert.assertEquals(0, MpackVersion.parseStackVersion("1.2.3-h10-b10").compareTo(MpackVersion.parseStackVersion("1.2.3-h10-b10"))); + Assert.assertEquals(0, MpackVersion.parseStackVersion("1.2.3-h10-b10").compareTo(MpackVersion.parseStackVersion("1.2.3.10-10"))); + Assert.assertEquals(-1, MpackVersion.parse("1.2.3-h10-b10").compareTo(MpackVersion.parseStackVersion("2.2.3.4-888"))); + } + @Test + public void testModuleVersionWithValidVersions() { + Assert.assertEquals(1, ModuleVersion.parse("1.2.3.4-h10-b888").compareTo(ModuleVersion.parse("1.2.3.4-b888"))); + Assert.assertEquals(1, ModuleVersion.parse("1.2.3.5-h0-b10").compareTo(ModuleVersion.parse("1.2.3.4-b10"))); + Assert.assertEquals(1, ModuleVersion.parse("1.2.4.4-h0-b10").compareTo(ModuleVersion.parse("1.2.3.4-b10"))); + Assert.assertEquals(1, ModuleVersion.parse("1.3.3.4-h0-b10").compareTo(ModuleVersion.parse("1.2.3.4-b10"))); + Assert.assertEquals(1, ModuleVersion.parse("2.2.3.4-h0-b10").compareTo(ModuleVersion.parse("1.2.3.4-b10"))); + Assert.assertEquals(1, ModuleVersion.parse("1.2.3.4-h0-b11").compareTo(ModuleVersion.parse("1.2.3.4-b10"))); - Assert.assertEquals(1, ModuleVersion.parse("1.2.3.4-h10-b10").compareTo(ModuleVersion.parse("1.2.3.4-b888"))); - Assert.assertEquals(1, ModuleVersion.parse("1.2.3.5-h10-b10").compareTo(ModuleVersion.parse("1.2.3.4-b888"))); Assert.assertEquals(0, ModuleVersion.parse("1.2.3.4-h0-b10").compareTo(ModuleVersion.parse("1.2.3.4-b10"))); - + Assert.assertEquals(0, ModuleVersion.parse("1.2.3.4-h0-b10").compareTo(ModuleVersion.parse("1.2.3.4-h0-b10"))); + Assert.assertEquals(0, ModuleVersion.parse("1.2.3.4-b10").compareTo(ModuleVersion.parse("1.2.3.4-b10"))); + Assert.assertEquals(0, ModuleVersion.parse("1.2.3.4-b10").compareTo(ModuleVersion.parse("1.2.3.4-h0-b10"))); + + Assert.assertEquals(-1, ModuleVersion.parse("1.2.3.4-h0-b10").compareTo(ModuleVersion.parse("1.2.3.4-b888"))); + Assert.assertEquals(-1, ModuleVersion.parse("1.2.3.4-h0-b10").compareTo(ModuleVersion.parse("1.2.3.5-b10"))); + Assert.assertEquals(-1, ModuleVersion.parse("1.2.3.4-h0-b10").compareTo(ModuleVersion.parse("1.2.4.4-b10"))); + Assert.assertEquals(-1, ModuleVersion.parse("1.2.3.4-h0-b10").compareTo(ModuleVersion.parse("1.3.3.4-b10"))); + Assert.assertEquals(-1, ModuleVersion.parse("1.2.3.4-h0-b10").compareTo(ModuleVersion.parse("2.2.3.4-b10"))); } } From a085655ddd911752e873969390abbd61116f99a6 Mon Sep 17 00:00:00 2001 From: Vitaly Brodetskyi Date: Tue, 23 Jan 2018 00:11:47 +0200 Subject: [PATCH 3/6] AMBARI-22817. Update backend code to handle new versioning schema.(vbrodetskyi) --- .../apache/ambari/server/utils/ModuleVersion.java | 8 ++++---- .../apache/ambari/server/utils/MpackVersion.java | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java index 91d973c9e42..e5be3be85fd 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java @@ -28,8 +28,8 @@ public class ModuleVersion implements Comparable { private static final String VERSION_WITH_HOTFIX_AND_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-h([0-9]+)-b([0-9]+)"; private static final String VERSION_WITH_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-b([0-9]+)"; - private static final Pattern patternWithHotfix = Pattern.compile(VERSION_WITH_HOTFIX_AND_BUILD_PATTERN); - private static final Pattern patternWithoutHotfix = Pattern.compile(VERSION_WITH_BUILD_PATTERN); + private static final Pattern PATTERN_WITH_HOTFIX = Pattern.compile(VERSION_WITH_HOTFIX_AND_BUILD_PATTERN); + private static final Pattern PATTERN_WITHOUT_HOTFIX = Pattern.compile(VERSION_WITH_BUILD_PATTERN); private int apacheMajor; private int apacheMinor; @@ -75,9 +75,9 @@ private static Matcher validateModuleVersion(String version) { String moduleVersion = StringUtils.trim(version); - Matcher versionMatcher = patternWithHotfix.matcher(moduleVersion); + Matcher versionMatcher = PATTERN_WITH_HOTFIX.matcher(moduleVersion); if (!versionMatcher.find()) { - versionMatcher = patternWithoutHotfix.matcher(moduleVersion); + versionMatcher = PATTERN_WITHOUT_HOTFIX.matcher(moduleVersion); if (!versionMatcher.find()) { throw new IllegalArgumentException("Wrong format for module version, should be N.N.N.N-bN or N.N.N-hN-bN"); } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java index 974cc7351d5..07d283977f9 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java @@ -29,9 +29,9 @@ public class MpackVersion implements Comparable { private final static String VERSION_WITH_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+)-b([0-9]+)"; private final static String LEGACY_STACK_VERSION_PATTERN = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-([0-9]+)"; - private final static Pattern patternWithHotfix = Pattern.compile(VERSION_WITH_HOTFIX_AND_BUILD_PATTERN); - private final static Pattern patternLegacyStackVersion = Pattern.compile(LEGACY_STACK_VERSION_PATTERN); - private final static Pattern patternWithoutHotfix = Pattern.compile(VERSION_WITH_BUILD_PATTERN); + private final static Pattern PATTERN_WITH_HOTFIX = Pattern.compile(VERSION_WITH_HOTFIX_AND_BUILD_PATTERN); + private final static Pattern PATTERN_LEGACY_STACK_VERSION = Pattern.compile(LEGACY_STACK_VERSION_PATTERN); + private final static Pattern PATTERN_WITHOUT_HOTFIX = Pattern.compile(VERSION_WITH_BUILD_PATTERN); private int major; private int minor; @@ -80,9 +80,9 @@ private static Matcher validateStackVersion(String version) { String stackVersion = StringUtils.trim(version); - Matcher versionMatcher = patternWithHotfix.matcher(stackVersion); + Matcher versionMatcher = PATTERN_WITH_HOTFIX.matcher(stackVersion); if (!versionMatcher.find()) { - versionMatcher = patternLegacyStackVersion.matcher(stackVersion); + versionMatcher = PATTERN_LEGACY_STACK_VERSION.matcher(stackVersion); if (!versionMatcher.find()) { throw new IllegalArgumentException("Wrong format for stack version, should be N.N.N.N-N or N.N.N-hN-bN"); } @@ -98,9 +98,9 @@ private static Matcher validateMpackVersion(String version) { String mpackVersion = StringUtils.trim(version); - Matcher versionMatcher = patternWithHotfix.matcher(mpackVersion); + Matcher versionMatcher = PATTERN_WITH_HOTFIX.matcher(mpackVersion); if (!versionMatcher.find()) { - versionMatcher = patternWithoutHotfix.matcher(mpackVersion); + versionMatcher = PATTERN_WITHOUT_HOTFIX.matcher(mpackVersion); if (!versionMatcher.find()) { throw new IllegalArgumentException("Wrong format for mpack version, should be N.N.N-bN or N.N.N-hN-bN"); } From 6669e63d903289c68b07afc2a8a7cf747e6f4f6c Mon Sep 17 00:00:00 2001 From: Vitaly Brodetskyi Date: Wed, 24 Jan 2018 00:24:16 +0200 Subject: [PATCH 4/6] AMBARI-22817. Update backend code to handle new versioning schema.(vbrodetskyi) --- .../ambari/server/utils/ModuleVersion.java | 27 +++++++++++- .../ambari/server/utils/MpackVersion.java | 42 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java index e5be3be85fd..520eac7855f 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/ModuleVersion.java @@ -23,14 +23,25 @@ import org.apache.commons.lang.StringUtils; +/** + * This class should be used to compare module(service) versions. + * Base method which should be used is parse(..), This method will validate and parse + * version which you will pass as parameter, and return object of current class with + * parsed version. Same thing you should do with another version, with which you are + * planning to compare previous one. After that, use method compare to get final result. + */ + public class ModuleVersion implements Comparable { + // RE for different version formats like N.N.N.N-bN, N.N.N-hN-bN private static final String VERSION_WITH_HOTFIX_AND_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-h([0-9]+)-b([0-9]+)"; private static final String VERSION_WITH_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-b([0-9]+)"; + // Patterns for previous RE private static final Pattern PATTERN_WITH_HOTFIX = Pattern.compile(VERSION_WITH_HOTFIX_AND_BUILD_PATTERN); private static final Pattern PATTERN_WITHOUT_HOTFIX = Pattern.compile(VERSION_WITH_BUILD_PATTERN); + // Parts of version private int apacheMajor; private int apacheMinor; private int internalMinor; @@ -48,6 +59,13 @@ public ModuleVersion(int apacheMajor, int apacheMinor, int internalMinor, int in this.build = build; } + /** + * Method which will parse module version + * which user passed as parameter. Also + * in this method version will be validated. + * @param moduleVersion string + * @return MpackVersion instance which contains parsed version + * */ public static ModuleVersion parse(String moduleVersion) { Matcher versionMatcher = validateModuleVersion(moduleVersion); ModuleVersion result = null; @@ -67,7 +85,14 @@ public static ModuleVersion parse(String moduleVersion) { return result; } - + /** + * Method validate module version not to be + * empty or null. Also check if passed version + * has valid format. + * @param version string + * @return Matcher for passed version + * @throws IllegalArgumentException() if version empty/null/not valid + */ private static Matcher validateModuleVersion(String version) { if (StringUtils.isEmpty(version)) { throw new IllegalArgumentException("Module version can't be empty or null"); diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java index 07d283977f9..ad3fdc8e5f0 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/MpackVersion.java @@ -23,16 +23,28 @@ import org.apache.commons.lang.StringUtils; +/** + * This class should be used to compare mpack and stack versions. + * Base method which should be used is parse/parseStackVersion, depends + * on which versions you want to compare. This method will validate and parse + * version which you will pass as parameter, and return object of current class with + * parsed version. Same thing you should do with another version, with which you are + * planning to compare previous one. After that, use method compare to get final result. + */ + public class MpackVersion implements Comparable { + // RE for different version formats like N.N.N-hN-bN, N.N.N-bN, N.N.N.N-N private final static String VERSION_WITH_HOTFIX_AND_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+)-h([0-9]+)-b([0-9]+)"; private final static String VERSION_WITH_BUILD_PATTERN = "^([0-9]+).([0-9]+).([0-9]+)-b([0-9]+)"; private final static String LEGACY_STACK_VERSION_PATTERN = "^([0-9]+).([0-9]+).([0-9]+).([0-9]+)-([0-9]+)"; + // Patterns for previous RE private final static Pattern PATTERN_WITH_HOTFIX = Pattern.compile(VERSION_WITH_HOTFIX_AND_BUILD_PATTERN); private final static Pattern PATTERN_LEGACY_STACK_VERSION = Pattern.compile(LEGACY_STACK_VERSION_PATTERN); private final static Pattern PATTERN_WITHOUT_HOTFIX = Pattern.compile(VERSION_WITH_BUILD_PATTERN); + // Parts of version private int major; private int minor; private int maint; @@ -48,6 +60,13 @@ public MpackVersion(int major, int minor, int maint, int hotfix, int build) { this.build = build; } + /** + * Method which will parse mpack version + * which user passed as parameter. Also + * in this method version will be validated. + * @param mpackVersion string + * @return MpackVersion instance which contains parsed version + * */ public static MpackVersion parse(String mpackVersion) { Matcher versionMatcher = validateMpackVersion(mpackVersion); MpackVersion result = null; @@ -65,6 +84,13 @@ public static MpackVersion parse(String mpackVersion) { return result; } + /** + * Method which will parse stack version + * which user passed as parameter. Also + * in this method version will be validated. + * @param stackVersion string + * @return MpackVersion instance which contains parsed version + * */ public static MpackVersion parseStackVersion(String stackVersion) { Matcher versionMatcher = validateStackVersion(stackVersion); MpackVersion result = new MpackVersion(Integer.parseInt(versionMatcher.group(1)), Integer.parseInt(versionMatcher.group(2)), @@ -73,6 +99,14 @@ public static MpackVersion parseStackVersion(String stackVersion) { return result; } + /** + * Method validate stack version not to be + * empty or null. Also check if passed version + * has valid format. + * @param version string + * @return Matcher for passed version + * @throws IllegalArgumentException() if version empty/null/not valid + */ private static Matcher validateStackVersion(String version) { if (StringUtils.isEmpty(version)) { throw new IllegalArgumentException("Stack version can't be empty or null"); @@ -91,6 +125,14 @@ private static Matcher validateStackVersion(String version) { return versionMatcher; } + /** + * Method validate mpack version not to be + * empty or null. Also check if passed version + * has valid format. + * @param version string + * @return Matcher for passed version + * @throws IllegalArgumentException() if version empty/null/not valid + */ private static Matcher validateMpackVersion(String version) { if (StringUtils.isEmpty(version)) { throw new IllegalArgumentException("Mpack version can't be empty or null"); From d52a8d89d58e7127dee33d3c78af9e5a9ceb9c4f Mon Sep 17 00:00:00 2001 From: Vitaly Brodetskyi Date: Wed, 24 Jan 2018 00:37:47 +0200 Subject: [PATCH 5/6] AMBARI-22817. Update backend code to handle new versioning schema.(vbrodetskyi) --- .../libraries/functions/module_version.py | 8 +++++++- .../libraries/functions/mpack_version.py | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/module_version.py b/ambari-common/src/main/python/resource_management/libraries/functions/module_version.py index 9853bb7027f..6ec4ba33cee 100644 --- a/ambari-common/src/main/python/resource_management/libraries/functions/module_version.py +++ b/ambari-common/src/main/python/resource_management/libraries/functions/module_version.py @@ -18,7 +18,13 @@ import re - +""" + This class should be used to compare module(service) versions. + Base method which should be used is parse(..), This method will validate and parse + version which you will pass as parameter, and return object of current class with + parsed version. Same thing you should do with another version, with which you are + planning to compare previous one. After that, use "==", "<", ">" to get final result. +""" class ModuleVersion(object): __module_version_pattern = "(?P[0-9]+).(?P[0-9]+).(?P[0-9]+).(?P[0-9]+)(-h(?P[0-9]+))*-b(?P[0-9]+)" __module_version_regex = re.compile(__module_version_pattern) diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py b/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py index 5d8a15b5086..6edfd39a2d3 100644 --- a/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py +++ b/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py @@ -18,7 +18,14 @@ import re - +""" + This class should be used to compare mpack and stack versions. + Base method which should be used is parse/parse_stack_version, depends + on which versions you want to compare. This method will validate and parse + version which you will pass as parameter, and return object of current class with + parsed version. Same thing you should do with another version, with which you are + planning to compare previous one. After that, use "==", ">", "<" to get final result. +""" class MpackVersion(object): __module_version_pattern = "(?P[0-9]+).(?P[0-9]+).(?P[0-9]+)(-h(?P[0-9]+))*-b(?P[0-9]+)" __module_legacy_stack_version_pattern = "(?P[0-9]+).(?P[0-9]+).(?P[0-9]+).(?P[0-9]+)(-(?P[0-9]+))" From bc5b94c975b1e15bc5c014a993bd9acf4950ff4e Mon Sep 17 00:00:00 2001 From: Vitaly Brodetskyi Date: Wed, 24 Jan 2018 13:58:18 +0200 Subject: [PATCH 6/6] AMBARI-22817. Update backend code to handle new versioning schema.(vbrodetskyi) --- .../libraries/functions/mpack_version.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py b/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py index 6edfd39a2d3..664f9fee25c 100644 --- a/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py +++ b/ambari-common/src/main/python/resource_management/libraries/functions/mpack_version.py @@ -27,10 +27,10 @@ planning to compare previous one. After that, use "==", ">", "<" to get final result. """ class MpackVersion(object): - __module_version_pattern = "(?P[0-9]+).(?P[0-9]+).(?P[0-9]+)(-h(?P[0-9]+))*-b(?P[0-9]+)" - __module_legacy_stack_version_pattern = "(?P[0-9]+).(?P[0-9]+).(?P[0-9]+).(?P[0-9]+)(-(?P[0-9]+))" - __module_version_regex = re.compile(__module_version_pattern) - __module_legacy_stack_version_regex = re.compile(__module_legacy_stack_version_pattern) + __mpack_version_pattern = "(?P[0-9]+).(?P[0-9]+).(?P[0-9]+)(-h(?P[0-9]+))*-b(?P[0-9]+)" + __mpack_legacy_stack_version_pattern = "(?P[0-9]+).(?P[0-9]+).(?P[0-9]+).(?P[0-9]+)(-(?P[0-9]+))" + __mpack_version_regex = re.compile(__mpack_version_pattern) + __mpack_legacy_stack_version_regex = re.compile(__mpack_legacy_stack_version_pattern) def __init__(self, major, minor, maint, hotfix, build): """ @@ -141,10 +141,10 @@ def validate_stack_version(cls, stack_version): if not version: raise ValueError("Module version can't be empty or null") - matcher = cls.__module_version_regex.match(version) + matcher = cls.__mpack_version_regex.match(version) if not matcher: - matcher = cls.__module_legacy_stack_version_regex.match(version) + matcher = cls.__mpack_legacy_stack_version_regex.match(version) if not matcher: raise ValueError("{0} is not a valid {1}".format(version, cls.__name__)) else: @@ -176,7 +176,7 @@ def validate(cls, mpack_version): if not version: raise ValueError("Module version can't be empty or null") - matcher = cls.__module_version_regex.match(version) + matcher = cls.__mpack_version_regex.match(version) if not matcher: raise ValueError("{0} is not a valid {1}".format(version, cls.__name__))