From 694c23ab2e64ed48b9d0ac165eb9d93d60838213 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Wed, 2 Dec 2020 15:14:05 -0500 Subject: [PATCH] go_register_toolchains: improve version string parsing and comparison (#2745) --- go/private/sdk.bzl | 85 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 14 deletions(-) diff --git a/go/private/sdk.bzl b/go/private/sdk.bzl index 6fce53c454..c148c9e2ff 100644 --- a/go/private/sdk.bzl +++ b/go/private/sdk.bzl @@ -24,12 +24,8 @@ load( "//go/private:platforms.bzl", "generate_toolchain_names", ) -load( - "//go/private/skylib/lib:versions.bzl", - "versions", -) -MIN_SUPPORTED_VERSION = "1.14" +MIN_SUPPORTED_VERSION = (1, 14, 0) def _go_host_sdk_impl(ctx): goroot = _detect_host_sdk(ctx) @@ -85,15 +81,17 @@ def _go_download_sdk_impl(ctx): if not version: highest_version = None for v in sdks_by_version.keys(): - sv = versions.parse(v) - if v != ".".join([str(d) for d in sv]): - # skip pre-release versions + pv = _parse_version(v) + if not pv or _version_is_prerelease(pv): + # skip parse errors and pre-release versions continue - if not highest_version or sv > highest_version: - highest_version = sv + if not highest_version or _version_less(highest_version, pv): + highest_version = pv if not highest_version: fail("did not find any Go versions in https://golang.org/dl/?mode=json") - version = ".".join([str(d) for d in highest_version]) + version = _version_string(highest_version) + if version not in sdks_by_version: + fail("did not find version {} in https://golang.org/dl/?mode=json".format(version)) sdks = sdks_by_version[version] if platform not in sdks: @@ -335,6 +333,62 @@ def _parse_versions_json_field(line): return "", "" return k[1:], v[:-1] +def _parse_version(version): + """Parses a version string like "1.15.5" and returns a tuple of numbers or None""" + l, r = 0, 0 + parsed = [] + for c in version.elems(): + if c == ".": + if l == r: + # empty component + return None + parsed.append(int(version[l:r])) + r += 1 + l = r + continue + + if c.isdigit(): + r += 1 + continue + + # pre-release suffix + break + + if l == r: + # empty component + return None + parsed.append(int(version[l:r])) + if len(parsed) == 2: + # first minor version, like (1, 15) + parsed.append(0) + if len(parsed) != 3: + # too many or too few components + return None + if r < len(version): + # pre-release suffix + parsed.append(version[r:]) + return tuple(parsed) + +def _version_is_prerelease(v): + return len(v) > 3 + +def _version_less(a, b): + if a[:3] < b[:3]: + return True + if a[:3] > b[:3]: + return False + if len(a) > len(b): + return True + if len(a) < len(b) or len(a) == 3: + return False + return a[3:] < b[3:] + +def _version_string(v): + suffix = v[3] if _version_is_prerelease(v) else "" + if v[-1] == 0: + v = v[:-1] + return ".".join([str(n) for n in v]) + suffix + def go_register_toolchains(version = None, nogo = None, go_version = None): """See /go/toolchains.rst#go-register-toolchains for full documentation.""" if not version: @@ -351,12 +405,15 @@ def go_register_toolchains(version = None, nogo = None, go_version = None): fail("go_register_toolchains: version set after go sdk rule declared ({})".format(", ".join([r["name"] for r in sdk_rules]))) if len(sdk_rules) == 0: if not version: - fail('go_register_toolchains: version must be set to a string like "1.15.5" or "host"') + fail('go_register_toolchains: version must be a string like "1.15.5" or "host"') elif version == "host": go_host_sdk(name = "go_sdk") else: - if not versions.is_at_least(MIN_SUPPORTED_VERSION, version): - print("DEPRECATED: Go versions before {} are not supported and may not work".format(MIN_SUPPORTED_VERSION)) + pv = _parse_version(version) + if not pv: + fail('go_register_toolchains: version must be a string like "1.15.5" or "host"') + if _version_less(pv, MIN_SUPPORTED_VERSION): + print("DEPRECATED: Go versions before {} are not supported and may not work".format(_version_string(MIN_SUPPORTED_VERSION))) go_download_sdk( name = "go_sdk", version = version,