Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce intdot versioning scheme #148

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions src/univers/intdot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# SPDX-License-Identifier: Apache-2.0
#
# Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download.

import re


class IntdotVersion:
"""
intdot version.

The regex pattern for the intdot version is any number (>0) of integers separated by dots, followed by an arbitrary number of other characters, e.g., 1.2.3.5543, 123.234-prerelease, 1.2.3alpha
"""

VERSION_PATTERN = r"^(\d+(\.\d+)*)(.*)$"

def __init__(self, version):
if not self.is_valid(version):
raise InvalidVersionError(version)

version = str(version).strip()
self.original = version

def __eq__(self, other):
return self.original == other.original

def __lt__(self, other):
return self.__cmp__(other) < 0

def __le__(self, other):
return self.__cmp__(other) <= 0

def __gt__(self, other):
return self.__cmp__(other) > 0

def __ge__(self, other):
return self.__cmp__(other) >= 0

@classmethod
def is_valid(cls, string):
return re.compile(IntdotVersion.VERSION_PATTERN).match(string)

def extract_numeric_labels(self, version):
"""
Check if the version matches the pattern; if it matches, extract the first group (identified by parentheses) which is the numeric part of the version
"""
match = re.match(IntdotVersion.VERSION_PATTERN, version)

if match:
version_labels = match.group(1)
return version_labels
else:
raise InvalidVersionError(version)

def __cmp__(self, other):
"""
Compare this version with ``other`` returning -1, 0, or 1 if the
other version is larger, the same, or smaller than this
one.
"""
if isinstance(other, str):
other = IntdotVersion(other)

if not isinstance(other, IntdotVersion):
raise InvalidVersionError

if self.original == other.original:
return 0

lhlabels = self.extract_numeric_labels(self.original)
rhlabels = self.extract_numeric_labels(other.original)

if lhlabels == rhlabels:
return 0

lhsize = len(lhlabels)
rhsize = len(rhlabels)

if lhsize > rhsize:
limit = lhsize
else:
limit = rhsize

limit -= 1

i = 0

while i <= limit:
try:
lhs = lhlabels[i]
except IndexError:
lhs = 0

try:
rhs = rhlabels[i]
except IndexError:
rhs = 0

i += 1

if lhs == rhs:
continue

if int(lhs) > int(rhs):
return 1
if int(lhs) < int(rhs):
return -1
return 0


class InvalidVersionError(ValueError):
pass
6 changes: 6 additions & 0 deletions src/univers/version_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,11 @@ class GolangVersionRange(VersionRange):
}


class IntdotVersionRange(VersionRange):
scheme = "intdot"
version_class = versions.IntdotVersion


class GenericVersionRange(VersionRange):
scheme = "generic"
version_class = versions.SemverVersion
Expand Down Expand Up @@ -1419,6 +1424,7 @@ def build_range_from_snyk_advisory_string(scheme: str, string: Union[str, List])
"openssl": OpensslVersionRange,
"mattermost": MattermostVersionRange,
"conan": ConanVersionRange,
"intdot": IntdotVersionRange,
}

PURL_TYPE_BY_GITLAB_SCHEME = {
Expand Down
12 changes: 12 additions & 0 deletions src/univers/versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from univers import debian
from univers import gem
from univers import gentoo
from univers import intdot
from univers import maven
from univers import nuget
from univers import rpm
Expand Down Expand Up @@ -133,6 +134,16 @@ def __str__(self):
return str(self.value)


class IntdotVersion(Version):
@classmethod
def build_value(cls, string):
return intdot.IntdotVersion(string)

@classmethod
def is_valid(cls, string):
return intdot.IntdotVersion.is_valid(string)


class GenericVersion(Version):
@classmethod
def is_valid(cls, string):
Expand Down Expand Up @@ -702,4 +713,5 @@ def bump(self, index):
OpensslVersion,
LegacyOpensslVersion,
AlpineLinuxVersion,
IntdotVersion,
]
11 changes: 11 additions & 0 deletions tests/test_version_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from univers.version_range import RANGE_CLASS_BY_SCHEMES
from univers.version_range import ConanVersionRange
from univers.version_range import GemVersionRange
from univers.version_range import IntdotVersionRange
from univers.version_range import InvalidVersionRange
from univers.version_range import MattermostVersionRange
from univers.version_range import NpmVersionRange
Expand All @@ -22,6 +23,7 @@
from univers.version_range import VersionRange
from univers.version_range import build_range_from_snyk_advisory_string
from univers.version_range import from_gitlab_native
from univers.versions import IntdotVersion
from univers.versions import InvalidVersion
from univers.versions import NugetVersion
from univers.versions import OpensslVersion
Expand Down Expand Up @@ -546,3 +548,12 @@ def test_version_range_normalize_case3():
nvr = vr.normalize(known_versions=known_versions)

assert str(nvr) == "vers:pypi/>=1.0.0|<=1.3.0|3.0.0"


def test_version_range_intdot():
intdot_range = IntdotVersionRange.from_string("vers:intdot/>1.2.3.4")
assert IntdotVersion("1.3.3") in intdot_range
assert IntdotVersion("0.3.3") not in intdot_range
assert IntdotVersion("1.3.3alpha") in intdot_range
assert IntdotVersion("1.2.2.pre") not in intdot_range
assert IntdotVersion("1010.23.234203.0") in IntdotVersionRange.from_string("vers:intdot/*")
12 changes: 12 additions & 0 deletions tests/test_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from univers.versions import EnhancedSemanticVersion
from univers.versions import GentooVersion
from univers.versions import GolangVersion
from univers.versions import IntdotVersion
from univers.versions import MavenVersion
from univers.versions import NginxVersion
from univers.versions import NugetVersion
Expand Down Expand Up @@ -218,3 +219,14 @@ def test_golang_version():
assert GolangVersion("v0.1.1") >= GolangVersion("v0.1.1")
assert GolangVersion("v0.1.1") <= GolangVersion("v0.1.1")
assert GolangVersion("v0.1.1") <= GolangVersion("v0.1.2")


def test_intdot_version():
assert IntdotVersion("1.2.3.4.5") == IntdotVersion("1.2.3.4.5")
assert IntdotVersion("1.2.3.4.6") > IntdotVersion("1.2.3.4.5")
assert IntdotVersion("1.2.3.4.6") < IntdotVersion("2.2.3.4.5")
assert IntdotVersion("1.2.3.4.6") <= IntdotVersion("2.2.3.4.5")
assert IntdotVersion("1.2.3.4.6-pre") <= IntdotVersion("2.2.3.4.5")
assert IntdotVersion("1.2.3.4.6-pre") <= IntdotVersion("2.2.3.4.5.pre")
assert IntdotVersion("1.2.3.4.6-pre") <= IntdotVersion("2.2.3.4.5-10")
assert IntdotVersion("1.2.3.4.6-pre") <= IntdotVersion("2.2.3.4.5-10")