From b3451d3bc727cea47743f58e68947cbda7a35fa1 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Thu, 7 Mar 2019 23:53:01 +0100 Subject: [PATCH] Tidying up --- repo2docker/buildpacks/julia/semver.py | 159 ++++++++++++------------- 1 file changed, 75 insertions(+), 84 deletions(-) diff --git a/repo2docker/buildpacks/julia/semver.py b/repo2docker/buildpacks/julia/semver.py index 0203f064..53789906 100644 --- a/repo2docker/buildpacks/julia/semver.py +++ b/repo2docker/buildpacks/julia/semver.py @@ -1,15 +1,16 @@ -# This file implements the julia-specific logic for handling SemVer (Semantic -# Versioning) strings in .toml files. -# -# It uses the python "semver" package to do most version string comparisons, but -# the places where julia's SemVer handling differs from the semver package have -# been implemented directly. -# -# Here, we use tuples to represent a Version, and functors as "matchers". The matcher -# functors take a version string and return true if it passes its constraints. +""" +Julia specific handling of SemVer strings + +It uses the python "semver" package to do most version string comparisons, but +the places where julia's SemVer handling differs from the semver package have +been implemented directly. +""" + +# We use tuples to represent a Version, and functors as "matchers". The +# matcher functors take a version string and return True if it passes its +# constraints. import re -from enum import Enum import semver @@ -29,70 +30,6 @@ def str_to_version(vstr): return tuple([int(n) for n in vstr.split(".")]) -# --- Matcher interface ------------------------------------------- - - -class AbstractMatcher: - def match(self, v): - pass - - -class SemverMatcher(AbstractMatcher): - """ Match a version tuple to a given constraint_str using the `semver` package. """ - - def __init__(self, constraint_str): - self.constraint_str = constraint_str - - def match(self, v): - while len(v) < 3: - v = v + (0,) - v_str = ".".join(map(str, v)) - return semver.match(v_str, self.constraint_str) - - def __eq__(self, rhs): - return self.constraint_str == rhs.constraint_str - - def __repr__(self): - return self.constraint_str - - -# --- Custom matcher for julia-specific SemVer handling: --------- -class Exclusivity(Enum): - EXCLUSIVE = 1 - INCLUSIVE = 2 - - -class VersionRange(AbstractMatcher): - """Match a version tuple between lower and upper bounds""" - - def __init__(self, lower, upper, upper_exclusivity): - self.lower = lower - self.upper = upper - self.upper_exclusivity = upper_exclusivity - - def match(self, v): - if self.upper_exclusivity == Exclusivity.EXCLUSIVE: - return self.lower <= v < self.upper - else: - return self.lower <= v <= self.upper - - def __eq__(self, rhs): - return ( - self.lower == rhs.lower - and self.upper == rhs.upper - and self.upper_exclusivity == rhs.upper_exclusivity - ) - - def __repr__(self): - return ( - "[" - + ".".join(map(str, self.lower)) - + "-" - + ".".join(map(str, self.upper)) - + (")" if self.upper_exclusivity == Exclusivity.EXCLUSIVE else "]") - ) - - # Helpers def major(v): return v[0] @@ -106,13 +43,10 @@ def patch(v): return v[2] if len(v) >= 3 else 0 -# --- main constraint parser function ------------------------------------ - - def create_semver_matcher(constraint_str): - """ - Returns a derived-class instance of AbstractMatcher that matches version - tuples against the provided constraint_str. + """Create a matcher that can be used to match version tuples + + Version tuples are matched against the provided `constraint_str`. """ constraint_str = constraint_str.strip() first_digit = re.search(r"\d", constraint_str) @@ -129,17 +63,18 @@ def create_semver_matcher(constraint_str): # Also, julia treats pre-1.0 releases specially, as if the first # non-zero number is actually a major number: # https://docs.julialang.org/en/latest/stdlib/Pkg/#Caret-specifiers-1 - # So we need to handle it separately by bumping the first non-zero number. + # So we need to handle it separately by bumping the first non-zero + # enumber. for i, n in enumerate(constraint): if ( n != 0 or i == len(constraint) - 1 ): # (using the last existing number handles situations like "^0.0" or "^0") upper = constraint[0:i] + (n + 1,) break - return VersionRange(constraint, upper, Exclusivity.EXCLUSIVE) + return VersionRange(constraint, upper, True) else: return VersionRange( - constraint, (major(constraint) + 1,), Exclusivity.EXCLUSIVE + constraint, (major(constraint) + 1,), True ) # '~' matching (only allowed to bump the last present number by one) @@ -147,7 +82,7 @@ def create_semver_matcher(constraint_str): return VersionRange( constraint, constraint[:-1] + (constraint[-1] + 1,), - Exclusivity.INCLUSIVE, + upper_exclusivity=False ) # Use semver package's comparisons for everything else: @@ -165,3 +100,59 @@ def create_semver_matcher(constraint_str): constraint_str = re.sub(r"(^|\b)=\b", "==", constraint_str) return SemverMatcher(constraint_str) + + +class SemverMatcher: + """Match a version tuple to a given `constraint_str` + + The matching is handled via the `semver` package. + """ + + def __init__(self, constraint_str): + self.constraint_str = constraint_str + + def match(self, v): + while len(v) < 3: + v = v + (0,) + v_str = ".".join(map(str, v)) + return semver.match(v_str, self.constraint_str) + + def __eq__(self, rhs): + return self.constraint_str == rhs.constraint_str + + def __repr__(self): + return self.constraint_str + + +class VersionRange: + """Match a version tuple between lower and upper bounds + + `upper_exclusivity` specifies if the upper bound is inclusive or exclusive. + """ + + def __init__(self, lower, upper, upper_exclusivity): + self.lower = lower + self.upper = upper + self.upper_exclusivity = upper_exclusivity + + def match(self, v): + if self.upper_exclusivity: + return self.lower <= v < self.upper + else: + return self.lower <= v <= self.upper + + def __eq__(self, rhs): + return ( + self.lower == rhs.lower + and self.upper == rhs.upper + and self.upper_exclusivity == rhs.upper_exclusivity + ) + + def __repr__(self): + return ( + "[" + + ".".join(map(str, self.lower)) + + "-" + + ".".join(map(str, self.upper)) + + (")" if self.upper_exclusivity else "]") + )