blob: a2cc11ac83283b40bc7170957403809c7b02a159 [file]
"""Internal functions to parse versions."""
def _safe_int(s, v):
if not s.isdigit():
fail("invalid Bazel version '{}': non-numeric segment '{}'".format(v, s))
return int(s)
def _partition(s):
for i in range(len(s)):
c = s[i]
if c == "-":
return s[:i], s[i + 1:]
if not c.isdigit() and c != ".":
return s[:i], s[i:]
return s, ""
def _parse_prerelease(prerelease):
# Parses a SemVer prerelease string into a list of comparable identifiers, following the
# precedence rules at https://semver.org/#spec-item-11.
if not prerelease:
return []
identifiers = []
for ident in prerelease.split("."):
if ident.isdigit():
identifiers.append((0, int(ident)))
else:
identifiers.append((1, ident))
return identifiers
def parse_version(v):
"""Parses the given Bazel version string into a comparable value.
Args:
v (str): version string
Returns:
a triple ([major, minor, patch], is_released, prerelease)
"""
if not v:
# An empty string is treated as a "dev version", which is greater than anything.
v = "999999.999999.999999"
release, prerelease = _partition(v.partition(" ")[0])
segments = release.split(".")
if len(segments) != 3:
fail("invalid Bazel version '{}': got {} dot-separated segments, want 3".format(v, len(segments)))
if prerelease.startswith("rc") and len(prerelease) > 2 and prerelease[2:].isdigit():
# Release candidates are considered to be the same as the release version for the purpose of
# feature detection. This allows for realistic testing of candidates and avoids the need to
# specify "rc1" on every version.
prerelease = ""
return [_safe_int(s, v) for s in segments], not prerelease, _parse_prerelease(prerelease)