diff --git a/src/wurf/post_resolve_run.py b/src/wurf/post_resolve_run.py index 3820883..2111707 100644 --- a/src/wurf/post_resolve_run.py +++ b/src/wurf/post_resolve_run.py @@ -15,7 +15,6 @@ class PostResolveRun(object): """ def __init__(self, resolver, ctx, run, cwd): - """Construct a new instance. :param resolver: A resolver instance. diff --git a/src/wurf/semver_selector.py b/src/wurf/semver_selector.py index ff38bfc..e4ff9a6 100644 --- a/src/wurf/semver_selector.py +++ b/src/wurf/semver_selector.py @@ -1,6 +1,22 @@ #! /usr/bin/env python # encoding: utf-8 +import re + + +BASEVERSION = re.compile( + r"""[vV]? + (?P0|[1-9]\d*) + (\. + (?P0|[1-9]\d*) + (\. + (?P0|[1-9]\d*) + )? + )? + """, + re.VERBOSE, +) + class SemverSelector(object): """ @@ -27,32 +43,58 @@ def select_tag(self, major, tags): """ assert isinstance(major, int), "Major version is not an int" - valid_tags = [] + valid_tags_ver = dict() # Get tags with a matching major version - for tag in tags: + for tag_str in tags: try: - t = self.semver.parse(tag) - if t["major"] != major: - continue + tag_ver = self.semver.VersionInfo.parse(tag_str) + except ValueError: + # Version might be prefixed with `v` or otherwise not be semver + # compatible. Try to find a simpler `major.minor.patch` match + # somewhere in the tag as a last resort. + tag_ver = self._semver_coerce(tag_str) + if tag_ver and tag_ver.major == major: + valid_tags_ver[tag_ver] = tag_str - valid_tags.append(tag) - except ValueError: # ignore tags we cannot parse - pass - - if len(valid_tags) == 0: + if not valid_tags_ver: return None # Now figure out which version is the newest. # We only use tags that have the specified major version to ensure # compatibility, see rules at semver.org - best_match = valid_tags[0] + best_match_ver = max(valid_tags_ver.keys()) + + # Return original string representation of version tag. + return valid_tags_ver[best_match_ver] - for t in valid_tags: - if self.semver.match(best_match, "<" + t): - best_match = t + def _semver_coerce(self, version): + """Convert an incomplete version string into a semver-compatible Version + object + + * Tries to detect a "basic" version string (``major.minor.patch``). + * If not enough components can be found, missing components are + set to zero to obtain a valid semver version. + + Copyright (c) 2013, Konstantine Rybnikov + https://github.com/python-semver/python-semver/ + + :param str version: the version string to convert + :return: a :class:`Version` instance (or ``None`` if it's not a version) + :rtype: :class:`Version` | None + """ + # Changed: using `match` instead of `search` to avoid situation where + # a tag simply containing a number inside it is parsed as a major + # version. + match = BASEVERSION.match(version) + if not match: + return None - return best_match + ver = { + key: 0 if value is None else int(value) + for key, value in match.groupdict().items() + } + return self.semver.VersionInfo(**ver) def __repr__(self): """ diff --git a/src/wurf/waf_standalone_context.py b/src/wurf/waf_standalone_context.py index 42452fa..65abe93 100644 --- a/src/wurf/waf_standalone_context.py +++ b/src/wurf/waf_standalone_context.py @@ -33,7 +33,6 @@ def options(opt): class WafStandaloneContext(Dist): - """creates a standalone archive that contains all dependencies""" cmd = "standalone" diff --git a/test/python/test_semver_selector.py b/test/python/test_semver_selector.py index 114f442..f929729 100644 --- a/test/python/test_semver_selector.py +++ b/test/python/test_semver_selector.py @@ -17,6 +17,11 @@ def test_semver_selector(): "3.0.0", "3.0.0-lts.0", "3.0.0-lts.1", + "backups/3.1.0-lts.0", # Do not match non-toplevel tags. + "4.0.0", + "v4.0.1", + "5.0.0", + "5.1", ] # Select latest tag for major version 1 @@ -27,3 +32,9 @@ def test_semver_selector(): # Select latest tag for major version 3 (LTS tags should be ignored) assert selector.select_tag(major=3, tags=tags) == "3.0.0" + + # Select latest tag for major version 4 (v prefix should be ignored) + assert selector.select_tag(major=4, tags=tags) == "v4.0.1" + + # Select latest tag for major version 5 (missing minor should be ignored) + assert selector.select_tag(major=5, tags=tags) == "5.1"