| # Copyright 2014 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| load( |
| "//go/private:common.bzl", |
| "executable_path", |
| ) |
| load( |
| "//go/private:nogo.bzl", |
| "go_register_nogo", |
| ) |
| load( |
| "//go/private/skylib/lib:versions.bzl", |
| "versions", |
| ) |
| |
| MIN_SUPPORTED_VERSION = (1, 14, 0) |
| |
| def _go_host_sdk_impl(ctx): |
| goroot = _detect_host_sdk(ctx) |
| platform = _detect_sdk_platform(ctx, goroot) |
| version = _detect_sdk_version(ctx, goroot) |
| _sdk_build_file(ctx, platform, version, experiments = ctx.attr.experiments) |
| _local_sdk(ctx, goroot) |
| |
| go_host_sdk_rule = repository_rule( |
| implementation = _go_host_sdk_impl, |
| environ = ["GOROOT"], |
| attrs = { |
| "version": attr.string(), |
| "experiments": attr.string_list( |
| doc = "Go experiments to enable via GOEXPERIMENT", |
| ), |
| "_sdk_build_file": attr.label( |
| default = Label("//go/private:BUILD.sdk.bazel"), |
| ), |
| }, |
| ) |
| |
| def go_host_sdk(name, register_toolchains = True, **kwargs): |
| go_host_sdk_rule(name = name, **kwargs) |
| _go_toolchains( |
| name = name + "_toolchains", |
| sdk_repo = name, |
| sdk_type = "host", |
| sdk_version = kwargs.get("version"), |
| goos = kwargs.get("goos"), |
| goarch = kwargs.get("goarch"), |
| ) |
| if register_toolchains: |
| _register_toolchains(name) |
| |
| def _go_download_sdk_impl(ctx): |
| if not ctx.attr.goos and not ctx.attr.goarch: |
| goos, goarch = detect_host_platform(ctx) |
| else: |
| if not ctx.attr.goos: |
| fail("goarch set but goos not set") |
| if not ctx.attr.goarch: |
| fail("goos set but goarch not set") |
| goos, goarch = ctx.attr.goos, ctx.attr.goarch |
| platform = goos + "_" + goarch |
| |
| version = ctx.attr.version |
| sdks = ctx.attr.sdks |
| |
| if not sdks: |
| # If sdks was unspecified, download a full list of files. |
| # If version was unspecified, pick the latest version. |
| # Even if version was specified, we need to download the file list |
| # to find the SHA-256 sum. If we don't have it, Bazel won't cache |
| # the downloaded archive. |
| if not version: |
| ctx.report_progress("Finding latest Go version") |
| else: |
| ctx.report_progress("Finding Go SHA-256 sums") |
| ctx.download( |
| url = [ |
| "https://go.dev/dl/?mode=json&include=all", |
| "https://golang.google.cn/dl/?mode=json&include=all", |
| ], |
| output = "versions.json", |
| ) |
| |
| data = ctx.read("versions.json") |
| sdks_by_version = _parse_versions_json(data) |
| |
| if not version: |
| highest_version = None |
| for v in sdks_by_version.keys(): |
| 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 _version_less(highest_version, pv): |
| highest_version = pv |
| if not highest_version: |
| fail("did not find any Go versions in https://go.dev/dl/?mode=json") |
| version = _version_string(highest_version) |
| if version not in sdks_by_version: |
| fail("did not find version {} in https://go.dev/dl/?mode=json".format(version)) |
| sdks = sdks_by_version[version] |
| |
| if platform not in sdks: |
| fail("unsupported platform {}".format(platform)) |
| filename, sha256 = sdks[platform] |
| _remote_sdk(ctx, [url.format(filename) for url in ctx.attr.urls], ctx.attr.strip_prefix, sha256) |
| |
| detected_version = _detect_sdk_version(ctx, ".") |
| _sdk_build_file(ctx, platform, detected_version, experiments = ctx.attr.experiments) |
| |
| if not ctx.attr.sdks and not ctx.attr.version: |
| # Returning this makes Bazel print a message that 'version' must be |
| # specified for a reproducible build. |
| return { |
| "name": ctx.attr.name, |
| "goos": ctx.attr.goos, |
| "goarch": ctx.attr.goarch, |
| "sdks": ctx.attr.sdks, |
| "urls": ctx.attr.urls, |
| "version": version, |
| "strip_prefix": ctx.attr.strip_prefix, |
| } |
| return None |
| |
| go_download_sdk_rule = repository_rule( |
| implementation = _go_download_sdk_impl, |
| attrs = { |
| "goos": attr.string(), |
| "goarch": attr.string(), |
| "sdks": attr.string_list_dict(), |
| "experiments": attr.string_list( |
| doc = "Go experiments to enable via GOEXPERIMENT", |
| ), |
| "urls": attr.string_list(default = ["https://dl.google.com/go/{}"]), |
| "version": attr.string(), |
| "strip_prefix": attr.string(default = "go"), |
| "_sdk_build_file": attr.label( |
| default = Label("//go/private:BUILD.sdk.bazel"), |
| ), |
| }, |
| ) |
| |
| def _define_version_constants(version, prefix = ""): |
| pv = parse_version(version) |
| if pv == None or len(pv) < 3: |
| fail("error parsing sdk version: " + version) |
| major, minor, patch = pv[0], pv[1], pv[2] |
| prerelease = pv[3] if len(pv) > 3 else "" |
| return """ |
| {prefix}MAJOR_VERSION = "{major}" |
| {prefix}MINOR_VERSION = "{minor}" |
| {prefix}PATCH_VERSION = "{patch}" |
| {prefix}PRERELEASE_SUFFIX = "{prerelease}" |
| """.format( |
| prefix = prefix, |
| major = major, |
| minor = minor, |
| patch = patch, |
| prerelease = prerelease, |
| ) |
| |
| def _to_constant_name(s): |
| # Prefix with _ as identifiers are not allowed to start with numbers. |
| return "_" + "".join([c if c.isalnum() else "_" for c in s.elems()]).upper() |
| |
| def go_toolchains_single_definition(ctx, *, prefix, goos, goarch, sdk_repo, sdk_type, sdk_version): |
| if not goos and not goarch: |
| goos, goarch = detect_host_platform(ctx) |
| else: |
| if not goos: |
| fail("goarch set but goos not set") |
| if not goarch: |
| fail("goos set but goarch not set") |
| |
| chunks = [] |
| loads = [] |
| identifier_prefix = _to_constant_name(prefix) |
| |
| # If a sdk_version attribute is provided, use that version. This avoids |
| # eagerly fetching the SDK repository. But if it's not provided, we have |
| # no choice and must load version constants from the version.bzl file that |
| # _sdk_build_file creates. This will trigger an eager fetch. |
| if sdk_version: |
| chunks.append(_define_version_constants(sdk_version, prefix = identifier_prefix)) |
| else: |
| loads.append("""load( |
| "@{sdk_repo}//:version.bzl", |
| {identifier_prefix}MAJOR_VERSION = "MAJOR_VERSION", |
| {identifier_prefix}MINOR_VERSION = "MINOR_VERSION", |
| {identifier_prefix}PATCH_VERSION = "PATCH_VERSION", |
| {identifier_prefix}PRERELEASE_SUFFIX = "PRERELEASE_SUFFIX", |
| ) |
| """.format( |
| sdk_repo = sdk_repo, |
| identifier_prefix = identifier_prefix, |
| )) |
| |
| chunks.append("""declare_bazel_toolchains( |
| prefix = "{prefix}", |
| go_toolchain_repo = "@{sdk_repo}", |
| host_goarch = "{goarch}", |
| host_goos = "{goos}", |
| major = {identifier_prefix}MAJOR_VERSION, |
| minor = {identifier_prefix}MINOR_VERSION, |
| patch = {identifier_prefix}PATCH_VERSION, |
| prerelease = {identifier_prefix}PRERELEASE_SUFFIX, |
| sdk_type = "{sdk_type}", |
| ) |
| """.format( |
| prefix = prefix, |
| identifier_prefix = identifier_prefix, |
| sdk_repo = sdk_repo, |
| goarch = goarch, |
| goos = goos, |
| sdk_type = sdk_type, |
| )) |
| |
| return struct( |
| loads = loads, |
| chunks = chunks, |
| ) |
| |
| def go_toolchains_build_file_content( |
| ctx, |
| prefixes, |
| geese, |
| goarchs, |
| sdk_repos, |
| sdk_types, |
| sdk_versions): |
| if not _have_same_length(prefixes, geese, goarchs, sdk_repos, sdk_types, sdk_versions): |
| fail("all lists must have the same length") |
| |
| loads = [ |
| """load("@io_bazel_rules_go//go/private:go_toolchain.bzl", "declare_bazel_toolchains")""", |
| ] |
| chunks = [ |
| """package(default_visibility = ["//visibility:public"])""", |
| ] |
| |
| for i in range(len(geese)): |
| definition = go_toolchains_single_definition( |
| ctx, |
| prefix = prefixes[i], |
| goos = geese[i], |
| goarch = goarchs[i], |
| sdk_repo = sdk_repos[i], |
| sdk_type = sdk_types[i], |
| sdk_version = sdk_versions[i], |
| ) |
| loads.extend(definition.loads) |
| chunks.extend(definition.chunks) |
| |
| return "\n".join(loads + chunks) |
| |
| def _go_multiple_toolchains_impl(ctx): |
| ctx.file( |
| "BUILD.bazel", |
| go_toolchains_build_file_content( |
| ctx, |
| prefixes = ctx.attr.prefixes, |
| geese = ctx.attr.geese, |
| goarchs = ctx.attr.goarchs, |
| sdk_repos = ctx.attr.sdk_repos, |
| sdk_types = ctx.attr.sdk_types, |
| sdk_versions = ctx.attr.sdk_versions, |
| ), |
| executable = False, |
| ) |
| |
| go_multiple_toolchains = repository_rule( |
| implementation = _go_multiple_toolchains_impl, |
| attrs = { |
| "prefixes": attr.string_list(mandatory = True), |
| "sdk_repos": attr.string_list(mandatory = True), |
| "sdk_types": attr.string_list(mandatory = True), |
| "sdk_versions": attr.string_list(mandatory = True), |
| "geese": attr.string_list(mandatory = True), |
| "goarchs": attr.string_list(mandatory = True), |
| }, |
| ) |
| |
| def _go_toolchains(name, sdk_repo, sdk_type, sdk_version = None, goos = None, goarch = None): |
| go_multiple_toolchains( |
| name = name, |
| prefixes = [""], |
| geese = [goos or ""], |
| goarchs = [goarch or ""], |
| sdk_repos = [sdk_repo], |
| sdk_types = [sdk_type], |
| sdk_versions = [sdk_version or ""], |
| ) |
| |
| def go_download_sdk(name, register_toolchains = True, **kwargs): |
| go_download_sdk_rule(name = name, **kwargs) |
| _go_toolchains( |
| name = name + "_toolchains", |
| sdk_repo = name, |
| sdk_type = "remote", |
| sdk_version = kwargs.get("version"), |
| goos = kwargs.get("goos"), |
| goarch = kwargs.get("goarch"), |
| ) |
| if register_toolchains: |
| _register_toolchains(name) |
| |
| def _go_local_sdk_impl(ctx): |
| goroot = ctx.attr.path |
| platform = _detect_sdk_platform(ctx, goroot) |
| version = _detect_sdk_version(ctx, goroot) |
| _sdk_build_file(ctx, platform, version, ctx.attr.experiments) |
| _local_sdk(ctx, goroot) |
| |
| _go_local_sdk = repository_rule( |
| implementation = _go_local_sdk_impl, |
| attrs = { |
| "path": attr.string(), |
| "version": attr.string(), |
| "experiments": attr.string_list( |
| doc = "Go experiments to enable via GOEXPERIMENT", |
| ), |
| "_sdk_build_file": attr.label( |
| default = Label("//go/private:BUILD.sdk.bazel"), |
| ), |
| }, |
| ) |
| |
| def go_local_sdk(name, register_toolchains = True, **kwargs): |
| _go_local_sdk(name = name, **kwargs) |
| _go_toolchains( |
| name = name + "_toolchains", |
| sdk_repo = name, |
| sdk_type = "remote", |
| sdk_version = kwargs.get("version"), |
| goos = kwargs.get("goos"), |
| goarch = kwargs.get("goarch"), |
| ) |
| if register_toolchains: |
| _register_toolchains(name) |
| |
| def _go_wrap_sdk_impl(ctx): |
| if not ctx.attr.root_file and not ctx.attr.root_files: |
| fail("either root_file or root_files must be provided") |
| if ctx.attr.root_file and ctx.attr.root_files: |
| fail("root_file and root_files cannot be both provided") |
| if ctx.attr.root_file: |
| root_file = ctx.attr.root_file |
| else: |
| goos, goarch = detect_host_platform(ctx) |
| platform = goos + "_" + goarch |
| if platform not in ctx.attr.root_files: |
| fail("unsupported platform {}".format(platform)) |
| root_file = Label(ctx.attr.root_files[platform]) |
| goroot = str(ctx.path(root_file).dirname) |
| platform = _detect_sdk_platform(ctx, goroot) |
| version = _detect_sdk_version(ctx, goroot) |
| _sdk_build_file(ctx, platform, version, ctx.attr.experiments) |
| _local_sdk(ctx, goroot) |
| |
| _go_wrap_sdk = repository_rule( |
| implementation = _go_wrap_sdk_impl, |
| attrs = { |
| "root_file": attr.label( |
| mandatory = False, |
| doc = "A file in the SDK root direcotry. Used to determine GOROOT.", |
| ), |
| "root_files": attr.string_dict( |
| mandatory = False, |
| doc = "A set of mappings from the host platform to a file in the SDK's root directory", |
| ), |
| "version": attr.string(), |
| "experiments": attr.string_list( |
| doc = "Go experiments to enable via GOEXPERIMENT", |
| ), |
| "_sdk_build_file": attr.label( |
| default = Label("//go/private:BUILD.sdk.bazel"), |
| ), |
| }, |
| ) |
| |
| def go_wrap_sdk(name, register_toolchains = True, **kwargs): |
| _go_wrap_sdk(name = name, **kwargs) |
| _go_toolchains( |
| name = name + "_toolchains", |
| sdk_repo = name, |
| sdk_type = "remote", |
| sdk_version = kwargs.get("version"), |
| goos = kwargs.get("goos"), |
| goarch = kwargs.get("goarch"), |
| ) |
| if register_toolchains: |
| _register_toolchains(name) |
| |
| def _register_toolchains(repo): |
| native.register_toolchains("@{}_toolchains//:all".format(repo)) |
| |
| def _remote_sdk(ctx, urls, strip_prefix, sha256): |
| if len(urls) == 0: |
| fail("no urls specified") |
| host_goos, _ = detect_host_platform(ctx) |
| |
| ctx.report_progress("Downloading and extracting Go toolchain") |
| |
| # TODO(#2771): After bazelbuild/bazel#18448 is merged and available in |
| # the minimum supported version of Bazel, remove the workarounds below. |
| # |
| # Go ships archives containing some non-ASCII file names, used in |
| # test cases for Go's build system. Bazel has a bug extracting these |
| # archives on certain file systems (macOS AFS at least, possibly also |
| # Docker on macOS with a bind mount). |
| # |
| # For .tar.gz files (available for most platforms), we work around this bug |
| # by using the system tar instead of ctx.download_and_extract. |
| # |
| # For .zip files, we use ctx.download_and_extract but with rename_files, |
| # changing certain paths that trigger the bug. This is only available |
| # in Bazel 6.0.0+ (bazelbuild/bazel#16052). The only situation where |
| # .zip files are needed seems to be a macOS host using a Windows toolchain |
| # for remote execution. |
| if urls[0].endswith(".tar.gz"): |
| if strip_prefix != "go": |
| fail("strip_prefix not supported") |
| ctx.download( |
| url = urls, |
| sha256 = sha256, |
| output = "go_sdk.tar.gz", |
| ) |
| res = ctx.execute(["tar", "-xf", "go_sdk.tar.gz", "--strip-components=1"]) |
| if res.return_code: |
| fail("error extracting Go SDK:\n" + res.stdout + res.stderr) |
| ctx.delete("go_sdk.tar.gz") |
| elif (urls[0].endswith(".zip") and |
| host_goos != "windows" and |
| # Development versions of Bazel have an empty version string. We assume that they are |
| # more recent than the version that introduced rename_files. |
| versions.is_at_least("6.0.0", versions.get() or "6.0.0")): |
| ctx.download_and_extract( |
| url = urls, |
| stripPrefix = strip_prefix, |
| sha256 = sha256, |
| rename_files = { |
| "go/test/fixedbugs/issue27836.dir/\336foo.go": "go/test/fixedbugs/issue27836.dir/thfoo.go", |
| "go/test/fixedbugs/issue27836.dir/\336main.go": "go/test/fixedbugs/issue27836.dir/thmain.go", |
| }, |
| ) |
| else: |
| ctx.download_and_extract( |
| url = urls, |
| stripPrefix = strip_prefix, |
| sha256 = sha256, |
| ) |
| |
| def _local_sdk(ctx, path): |
| for entry in ["src", "pkg", "bin", "lib", "misc"]: |
| ctx.symlink(path + "/" + entry, entry) |
| |
| def _sdk_build_file(ctx, platform, version, experiments): |
| ctx.file("ROOT") |
| goos, _, goarch = platform.partition("_") |
| |
| pv = parse_version(version) |
| if pv != None and pv[1] >= 20: |
| # Turn off coverageredesign GOEXPERIMENT on 1.20+ |
| # until rules_go is updated to work with the |
| # coverage redesign. |
| if not "nocoverageredesign" in experiments and not "coverageredesign" in experiments: |
| experiments = experiments + ["nocoverageredesign"] |
| |
| ctx.template( |
| "BUILD.bazel", |
| ctx.path(ctx.attr._sdk_build_file), |
| executable = False, |
| substitutions = { |
| "{goos}": goos, |
| "{goarch}": goarch, |
| "{exe}": ".exe" if goos == "windows" else "", |
| "{version}": version, |
| "{experiments}": repr(experiments), |
| }, |
| ) |
| |
| ctx.file( |
| "version.bzl", |
| executable = False, |
| content = _define_version_constants(version), |
| ) |
| |
| def detect_host_platform(ctx): |
| goos = ctx.os.name |
| if goos == "mac os x": |
| goos = "darwin" |
| elif goos.startswith("windows"): |
| goos = "windows" |
| |
| goarch = ctx.os.arch |
| if goarch == "aarch64": |
| goarch = "arm64" |
| elif goarch == "x86_64": |
| goarch = "amd64" |
| |
| return goos, goarch |
| |
| def _detect_host_sdk(ctx): |
| root = "@invalid@" |
| if "GOROOT" in ctx.os.environ: |
| return ctx.os.environ["GOROOT"] |
| res = ctx.execute([executable_path(ctx, "go"), "env", "GOROOT"]) |
| if res.return_code: |
| fail("Could not detect host go version") |
| root = res.stdout.strip() |
| if not root: |
| fail("host go version failed to report it's GOROOT") |
| return root |
| |
| def _detect_sdk_platform(ctx, goroot): |
| path = ctx.path(goroot + "/pkg/tool") |
| if not path.exists: |
| fail("Could not detect SDK platform: failed to find " + str(path)) |
| tool_entries = path.readdir() |
| |
| platforms = [] |
| for f in tool_entries: |
| if f.basename.find("_") >= 0: |
| platforms.append(f.basename) |
| |
| if len(platforms) == 0: |
| fail("Could not detect SDK platform: found no platforms in %s" % path) |
| if len(platforms) > 1: |
| fail("Could not detect SDK platform: found multiple platforms %s in %s" % (platforms, path)) |
| return platforms[0] |
| |
| def _detect_sdk_version(ctx, goroot): |
| version_file_path = goroot + "/VERSION" |
| if ctx.path(version_file_path).exists: |
| # VERSION file has version prefixed by go, eg. go1.18.3 |
| version = ctx.read(version_file_path)[2:] |
| if ctx.attr.version and ctx.attr.version != version: |
| fail("SDK is version %s, but version %s was expected" % (version, ctx.attr.version)) |
| return version |
| |
| # The top-level VERSION file does not exist in all Go SDK distributions, e.g. those shipped by Debian or Fedora. |
| # Falling back to running "go version" |
| go_binary_path = goroot + "/bin/go" |
| result = ctx.execute([go_binary_path, "version"]) |
| if result.return_code != 0: |
| fail("Could not detect SDK version: '%s version' exited with exit code %d" % (go_binary_path, result.return_code)) |
| |
| # go version output is of the form "go version go1.18.3 linux/amd64" or "go |
| # version devel go1.19-fd1b5904ae Tue Mar 22 21:38:10 2022 +0000 |
| # linux/amd64". See the following links for how this output is generated: |
| # - https://github.com/golang/go/blob/2bdb5c57f1efcbddab536028d053798e35de6226/src/cmd/go/internal/version/version.go#L75 |
| # - https://github.com/golang/go/blob/2bdb5c57f1efcbddab536028d053798e35de6226/src/cmd/dist/build.go#L333 |
| # |
| # Read the third word, or the fourth word if the third word is "devel", to |
| # find the version number. |
| output_parts = result.stdout.split(" ") |
| if len(output_parts) > 2 and output_parts[2].startswith("go"): |
| version = output_parts[2][len("go"):] |
| elif len(output_parts) > 3 and output_parts[2] == "devel" and output_parts[3].startswith("go"): |
| version = output_parts[3][len("go"):] |
| else: |
| fail("Could not parse SDK version from '%s version' output: %s" % (go_binary_path, result.stdout)) |
| if parse_version(version) == None: |
| fail("Could not parse SDK version from '%s version' output: %s" % (go_binary_path, result.stdout)) |
| if ctx.attr.version and ctx.attr.version != version: |
| fail("SDK is version %s, but version %s was expected" % (version, ctx.attr.version)) |
| return version |
| |
| def _parse_versions_json(data): |
| """Parses version metadata returned by go.dev. |
| |
| Args: |
| data: the contents of the file downloaded from |
| https://go.dev/dl/?mode=json. We assume the file is valid |
| JSON, is spaced and indented, and is in a particular format. |
| |
| Return: |
| A dict mapping version strings (like "1.15.5") to dicts mapping |
| platform names (like "linux_amd64") to pairs of filenames |
| (like "go1.15.5.linux-amd64.tar.gz") and hex-encoded SHA-256 sums. |
| """ |
| sdks = json.decode(data) |
| return { |
| sdk["version"][len("go"):]: { |
| "%s_%s" % (file["os"], file["arch"]): ( |
| file["filename"], |
| file["sha256"], |
| ) |
| for file in sdk["files"] |
| if file["kind"] == "archive" |
| } |
| for sdk in sdks |
| } |
| |
| 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 _have_same_length(*lists): |
| if not lists: |
| fail("expected at least one list") |
| return len({len(l): None for l in lists}) == 1 |
| |
| def go_register_toolchains(version = None, nogo = None, go_version = None, experiments = None): |
| """See /go/toolchains.rst#go-register-toolchains for full documentation.""" |
| if not version: |
| version = go_version # old name |
| |
| sdk_kinds = ("go_download_sdk_rule", "go_host_sdk_rule", "_go_local_sdk", "_go_wrap_sdk") |
| existing_rules = native.existing_rules() |
| sdk_rules = [r for r in existing_rules.values() if r["kind"] in sdk_kinds] |
| if len(sdk_rules) == 0 and "go_sdk" in existing_rules: |
| # may be local_repository in bazel_tests. |
| sdk_rules.append(existing_rules["go_sdk"]) |
| |
| if version and len(sdk_rules) > 0: |
| 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 a string like "1.15.5" or "host"') |
| elif version == "host": |
| go_host_sdk(name = "go_sdk", experiments = experiments) |
| else: |
| 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, |
| experiments = experiments, |
| ) |
| |
| if nogo: |
| # Override default definition in go_rules_dependencies(). |
| go_register_nogo( |
| name = "io_bazel_rules_nogo", |
| nogo = nogo, |
| ) |