Skip to content

Commit

Permalink
add custom comparator to corelogic to compare ubuntu version
Browse files Browse the repository at this point in the history
  • Loading branch information
feng-j678 committed Nov 25, 2024
1 parent 3269944 commit 93c8ceb
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 11 deletions.
78 changes: 78 additions & 0 deletions src/core/src/bootstrap/CoreUtility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Copyright 2020 Microsoft Corporation
#
# Licensed 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.
#
# Requires Python 2.7+
import re


class CoreUtility(object):

@staticmethod
def compare_version(version_a, version_b):
""" Compare two versions with handling numeric and string parts, return -1 (less), +1 (greater), 0 (equal) """

def split_version_components(version):
""" Split a version into numeric and non-numeric into components list: 27.13.4~18.04.1 -> [27][14][4]"""
#return [int(x) if x.isdigit() else x for x in re.split(r'(\d+)', version) if x]
return [int(x) if x.isdigit() else x for x in re.split(r'(\d+)', version) if x]

def parse_version(version_components):
""" Parse the split version list into list [27][14][4] -> [[27], [14], [4]]"""
return [split_version_components(x) for x in version_components.split(".")]

parse_version_a = parse_version(version_a)
parse_version_b = parse_version(version_b)

for v1, v2 in zip(parse_version_a, parse_version_b):
for sub_v1, sub_v2 in zip(v1, v2):
if sub_v1 < sub_v2:
return -1 # less
elif sub_v1 > sub_v2:
return 1 # greater

Check warning on line 42 in src/core/src/bootstrap/CoreUtility.py

View check run for this annotation

Codecov / codecov/patch

src/core/src/bootstrap/CoreUtility.py#L42

Added line #L42 was not covered by tests

# If equal 27.13.4 vs 27.13.4, return 0
return (len(parse_version_a) > len(parse_version_b)) - (len(parse_version_a) - len(parse_version_b))

@staticmethod
def extract_version(path):
"""
Extract the version part from a given path.
Input: /var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5/config
Return: 1.2.5
"""
match = re.search(r'([\d]+\.[\d]+\.[\d])', path)
return match.group(1) if match else ""

@staticmethod
def sort_versions(paths):
"""
Sort paths based on version numbers extracted from paths.
Input:
["Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001",
"Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100",
"Microsoft.CPlat.Core.LinuxPatchExtension-1.21.100"]
Return:
["Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001",
"Microsoft.CPlat.Core.LinuxPatchExtension-1.21.100",
"Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100"]
"""

def version_key(path):
version_numbers = CoreUtility.extract_version(path)
return tuple(map(int, version_numbers.split('.'))) if version_numbers else (0, 0, 0)

Check warning on line 73 in src/core/src/bootstrap/CoreUtility.py

View check run for this annotation

Codecov / codecov/patch

src/core/src/bootstrap/CoreUtility.py#L71-L73

Added lines #L71 - L73 were not covered by tests

return sorted(paths, key=version_key, reverse=True)

Check warning on line 75 in src/core/src/bootstrap/CoreUtility.py

View check run for this annotation

Codecov / codecov/patch

src/core/src/bootstrap/CoreUtility.py#L75

Added line #L75 was not covered by tests



11 changes: 9 additions & 2 deletions src/core/src/package_managers/UbuntuProClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

"""This is the Ubuntu Pro Client implementation"""
import json

from core.src.bootstrap.CoreUtility import CoreUtility
from core.src.bootstrap.Constants import Constants


Expand Down Expand Up @@ -50,10 +52,15 @@ def is_pro_working(self):
is_minimum_ubuntu_pro_version_installed = False
try:
from uaclient.api.u.pro.version.v1 import version
from distutils.version import LooseVersion # Importing this module here as there is conflict between "distutils.version" and "uaclient.api.u.pro.version.v1.version when 'LooseVersion' is called."
version_result = version()
ubuntu_pro_client_version = version_result.installed_version
is_minimum_ubuntu_pro_version_installed = LooseVersion(ubuntu_pro_client_version) >= LooseVersion(Constants.UbuntuProClientSettings.MINIMUM_CLIENT_VERSION)

# extract version from pro_client_verison 27.13.4~18.04.1 -> 27.13.4
extracted_ubuntu_pro_client_version = CoreUtility.extract_version(ubuntu_pro_client_version)

# use custom comparator output 0 (equal), -1 (less), +1 (greater)
is_minimum_ubuntu_pro_version_installed = CoreUtility.compare_version(extracted_ubuntu_pro_client_version, Constants.UbuntuProClientSettings.MINIMUM_CLIENT_VERSION) >= 0

if ubuntu_pro_client_version is not None and is_minimum_ubuntu_pro_version_installed:
is_ubuntu_pro_client_working = True
self.is_ubuntu_pro_client_attached = self.log_ubuntu_pro_client_attached()
Expand Down
6 changes: 2 additions & 4 deletions src/extension/src/ActionHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import os
import shutil
import time
#from distutils.version import LooseVersion

from extension.src.Constants import Constants
from extension.src.EnableCommandHandler import EnableCommandHandler
Expand Down Expand Up @@ -226,11 +225,10 @@ def update(self):
# identify the version preceding current
self.logger.log("Fetching the extension version preceding current from all available versions...")

# sort path based on version numbers
# use custom sort logic to sort path based on version numbers
sorted_versions = Utility.sort_versions(paths_to_all_versions)

#paths_to_all_versions.sort(reverse=True, key=LooseVersion)
preceding_version_path = sorted_versions[1]

if preceding_version_path is None or preceding_version_path == "" or not os.path.exists(preceding_version_path):
error_msg = "Could not find path where preceding extension version artifacts are stored. Hence, cannot copy the required artifacts to the latest version. "\
"[Preceding extension version path={0}]".format(str(preceding_version_path))
Expand Down
19 changes: 14 additions & 5 deletions src/extension/src/Utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,27 @@ def get_str_from_datetime(date):
def extract_version(path):
"""
Extract the version part from a given path.
Example: /var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5/config -> 1.2.5
Input: /var/lib/waagent/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5/config
Return: 1.2.5
"""
match = re.search(r'-([\d]+\.[\d]+\.[\d]+)', path)
match = re.search(r'([\d]+\.[\d]+\.[\d])', path)
return match.group(1) if match else ""

@staticmethod
def sort_versions(paths):
"""
Sort paths based on version numbers extracted from folder names.
Sort paths based on version numbers extracted from paths.
Input:
["Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001",
"Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100",
"Microsoft.CPlat.Core.LinuxPatchExtension-1.21.100"]
Return:
["Microsoft.CPlat.Core.LinuxPatchExtension-1.21.1001",
"Microsoft.CPlat.Core.LinuxPatchExtension-1.21.100",
"Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100"]
"""
def version_key(path):
version_str = Utility.extract_version(path)
return tuple(map(int, version_str.split('.'))) if version_str else (0,0,0)
version_numbers = Utility.extract_version(path)
return tuple(map(int, version_numbers.split('.'))) if version_numbers else (0,0,0)

return sorted(paths, key=version_key,reverse=True)

0 comments on commit 93c8ceb

Please sign in to comment.