xref: /aosp_15_r20/external/bazelbuild-rules_go/go/private/sdk.bzl (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1*9bb1b549SSpandan Das# Copyright 2014 The Bazel Authors. All rights reserved.
2*9bb1b549SSpandan Das#
3*9bb1b549SSpandan Das# Licensed under the Apache License, Version 2.0 (the "License");
4*9bb1b549SSpandan Das# you may not use this file except in compliance with the License.
5*9bb1b549SSpandan Das# You may obtain a copy of the License at
6*9bb1b549SSpandan Das#
7*9bb1b549SSpandan Das#    http://www.apache.org/licenses/LICENSE-2.0
8*9bb1b549SSpandan Das#
9*9bb1b549SSpandan Das# Unless required by applicable law or agreed to in writing, software
10*9bb1b549SSpandan Das# distributed under the License is distributed on an "AS IS" BASIS,
11*9bb1b549SSpandan Das# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9bb1b549SSpandan Das# See the License for the specific language governing permissions and
13*9bb1b549SSpandan Das# limitations under the License.
14*9bb1b549SSpandan Das
15*9bb1b549SSpandan Dasload(
16*9bb1b549SSpandan Das    "//go/private:common.bzl",
17*9bb1b549SSpandan Das    "executable_path",
18*9bb1b549SSpandan Das)
19*9bb1b549SSpandan Dasload(
20*9bb1b549SSpandan Das    "//go/private:nogo.bzl",
21*9bb1b549SSpandan Das    "go_register_nogo",
22*9bb1b549SSpandan Das)
23*9bb1b549SSpandan Dasload(
24*9bb1b549SSpandan Das    "//go/private/skylib/lib:versions.bzl",
25*9bb1b549SSpandan Das    "versions",
26*9bb1b549SSpandan Das)
27*9bb1b549SSpandan Das
28*9bb1b549SSpandan DasMIN_SUPPORTED_VERSION = (1, 14, 0)
29*9bb1b549SSpandan Das
30*9bb1b549SSpandan Dasdef _go_host_sdk_impl(ctx):
31*9bb1b549SSpandan Das    goroot = _detect_host_sdk(ctx)
32*9bb1b549SSpandan Das    platform = _detect_sdk_platform(ctx, goroot)
33*9bb1b549SSpandan Das    version = _detect_sdk_version(ctx, goroot)
34*9bb1b549SSpandan Das    _sdk_build_file(ctx, platform, version, experiments = ctx.attr.experiments)
35*9bb1b549SSpandan Das    _local_sdk(ctx, goroot)
36*9bb1b549SSpandan Das
37*9bb1b549SSpandan Dasgo_host_sdk_rule = repository_rule(
38*9bb1b549SSpandan Das    implementation = _go_host_sdk_impl,
39*9bb1b549SSpandan Das    environ = ["GOROOT"],
40*9bb1b549SSpandan Das    attrs = {
41*9bb1b549SSpandan Das        "version": attr.string(),
42*9bb1b549SSpandan Das        "experiments": attr.string_list(
43*9bb1b549SSpandan Das            doc = "Go experiments to enable via GOEXPERIMENT",
44*9bb1b549SSpandan Das        ),
45*9bb1b549SSpandan Das        "_sdk_build_file": attr.label(
46*9bb1b549SSpandan Das            default = Label("//go/private:BUILD.sdk.bazel"),
47*9bb1b549SSpandan Das        ),
48*9bb1b549SSpandan Das    },
49*9bb1b549SSpandan Das)
50*9bb1b549SSpandan Das
51*9bb1b549SSpandan Dasdef go_host_sdk(name, register_toolchains = True, **kwargs):
52*9bb1b549SSpandan Das    go_host_sdk_rule(name = name, **kwargs)
53*9bb1b549SSpandan Das    _go_toolchains(
54*9bb1b549SSpandan Das        name = name + "_toolchains",
55*9bb1b549SSpandan Das        sdk_repo = name,
56*9bb1b549SSpandan Das        sdk_type = "host",
57*9bb1b549SSpandan Das        sdk_version = kwargs.get("version"),
58*9bb1b549SSpandan Das        goos = kwargs.get("goos"),
59*9bb1b549SSpandan Das        goarch = kwargs.get("goarch"),
60*9bb1b549SSpandan Das    )
61*9bb1b549SSpandan Das    if register_toolchains:
62*9bb1b549SSpandan Das        _register_toolchains(name)
63*9bb1b549SSpandan Das
64*9bb1b549SSpandan Dasdef _go_download_sdk_impl(ctx):
65*9bb1b549SSpandan Das    if not ctx.attr.goos and not ctx.attr.goarch:
66*9bb1b549SSpandan Das        goos, goarch = detect_host_platform(ctx)
67*9bb1b549SSpandan Das    else:
68*9bb1b549SSpandan Das        if not ctx.attr.goos:
69*9bb1b549SSpandan Das            fail("goarch set but goos not set")
70*9bb1b549SSpandan Das        if not ctx.attr.goarch:
71*9bb1b549SSpandan Das            fail("goos set but goarch not set")
72*9bb1b549SSpandan Das        goos, goarch = ctx.attr.goos, ctx.attr.goarch
73*9bb1b549SSpandan Das    platform = goos + "_" + goarch
74*9bb1b549SSpandan Das
75*9bb1b549SSpandan Das    version = ctx.attr.version
76*9bb1b549SSpandan Das    sdks = ctx.attr.sdks
77*9bb1b549SSpandan Das
78*9bb1b549SSpandan Das    if not sdks:
79*9bb1b549SSpandan Das        # If sdks was unspecified, download a full list of files.
80*9bb1b549SSpandan Das        # If version was unspecified, pick the latest version.
81*9bb1b549SSpandan Das        # Even if version was specified, we need to download the file list
82*9bb1b549SSpandan Das        # to find the SHA-256 sum. If we don't have it, Bazel won't cache
83*9bb1b549SSpandan Das        # the downloaded archive.
84*9bb1b549SSpandan Das        if not version:
85*9bb1b549SSpandan Das            ctx.report_progress("Finding latest Go version")
86*9bb1b549SSpandan Das        else:
87*9bb1b549SSpandan Das            ctx.report_progress("Finding Go SHA-256 sums")
88*9bb1b549SSpandan Das        ctx.download(
89*9bb1b549SSpandan Das            url = [
90*9bb1b549SSpandan Das                "https://go.dev/dl/?mode=json&include=all",
91*9bb1b549SSpandan Das                "https://golang.google.cn/dl/?mode=json&include=all",
92*9bb1b549SSpandan Das            ],
93*9bb1b549SSpandan Das            output = "versions.json",
94*9bb1b549SSpandan Das        )
95*9bb1b549SSpandan Das
96*9bb1b549SSpandan Das        data = ctx.read("versions.json")
97*9bb1b549SSpandan Das        sdks_by_version = _parse_versions_json(data)
98*9bb1b549SSpandan Das
99*9bb1b549SSpandan Das        if not version:
100*9bb1b549SSpandan Das            highest_version = None
101*9bb1b549SSpandan Das            for v in sdks_by_version.keys():
102*9bb1b549SSpandan Das                pv = parse_version(v)
103*9bb1b549SSpandan Das                if not pv or _version_is_prerelease(pv):
104*9bb1b549SSpandan Das                    # skip parse errors and pre-release versions
105*9bb1b549SSpandan Das                    continue
106*9bb1b549SSpandan Das                if not highest_version or _version_less(highest_version, pv):
107*9bb1b549SSpandan Das                    highest_version = pv
108*9bb1b549SSpandan Das            if not highest_version:
109*9bb1b549SSpandan Das                fail("did not find any Go versions in https://go.dev/dl/?mode=json")
110*9bb1b549SSpandan Das            version = _version_string(highest_version)
111*9bb1b549SSpandan Das        if version not in sdks_by_version:
112*9bb1b549SSpandan Das            fail("did not find version {} in https://go.dev/dl/?mode=json".format(version))
113*9bb1b549SSpandan Das        sdks = sdks_by_version[version]
114*9bb1b549SSpandan Das
115*9bb1b549SSpandan Das    if platform not in sdks:
116*9bb1b549SSpandan Das        fail("unsupported platform {}".format(platform))
117*9bb1b549SSpandan Das    filename, sha256 = sdks[platform]
118*9bb1b549SSpandan Das    _remote_sdk(ctx, [url.format(filename) for url in ctx.attr.urls], ctx.attr.strip_prefix, sha256)
119*9bb1b549SSpandan Das
120*9bb1b549SSpandan Das    detected_version = _detect_sdk_version(ctx, ".")
121*9bb1b549SSpandan Das    _sdk_build_file(ctx, platform, detected_version, experiments = ctx.attr.experiments)
122*9bb1b549SSpandan Das
123*9bb1b549SSpandan Das    if not ctx.attr.sdks and not ctx.attr.version:
124*9bb1b549SSpandan Das        # Returning this makes Bazel print a message that 'version' must be
125*9bb1b549SSpandan Das        # specified for a reproducible build.
126*9bb1b549SSpandan Das        return {
127*9bb1b549SSpandan Das            "name": ctx.attr.name,
128*9bb1b549SSpandan Das            "goos": ctx.attr.goos,
129*9bb1b549SSpandan Das            "goarch": ctx.attr.goarch,
130*9bb1b549SSpandan Das            "sdks": ctx.attr.sdks,
131*9bb1b549SSpandan Das            "urls": ctx.attr.urls,
132*9bb1b549SSpandan Das            "version": version,
133*9bb1b549SSpandan Das            "strip_prefix": ctx.attr.strip_prefix,
134*9bb1b549SSpandan Das        }
135*9bb1b549SSpandan Das    return None
136*9bb1b549SSpandan Das
137*9bb1b549SSpandan Dasgo_download_sdk_rule = repository_rule(
138*9bb1b549SSpandan Das    implementation = _go_download_sdk_impl,
139*9bb1b549SSpandan Das    attrs = {
140*9bb1b549SSpandan Das        "goos": attr.string(),
141*9bb1b549SSpandan Das        "goarch": attr.string(),
142*9bb1b549SSpandan Das        "sdks": attr.string_list_dict(),
143*9bb1b549SSpandan Das        "experiments": attr.string_list(
144*9bb1b549SSpandan Das            doc = "Go experiments to enable via GOEXPERIMENT",
145*9bb1b549SSpandan Das        ),
146*9bb1b549SSpandan Das        "urls": attr.string_list(default = ["https://dl.google.com/go/{}"]),
147*9bb1b549SSpandan Das        "version": attr.string(),
148*9bb1b549SSpandan Das        "strip_prefix": attr.string(default = "go"),
149*9bb1b549SSpandan Das        "_sdk_build_file": attr.label(
150*9bb1b549SSpandan Das            default = Label("//go/private:BUILD.sdk.bazel"),
151*9bb1b549SSpandan Das        ),
152*9bb1b549SSpandan Das    },
153*9bb1b549SSpandan Das)
154*9bb1b549SSpandan Das
155*9bb1b549SSpandan Dasdef _define_version_constants(version, prefix = ""):
156*9bb1b549SSpandan Das    pv = parse_version(version)
157*9bb1b549SSpandan Das    if pv == None or len(pv) < 3:
158*9bb1b549SSpandan Das        fail("error parsing sdk version: " + version)
159*9bb1b549SSpandan Das    major, minor, patch = pv[0], pv[1], pv[2]
160*9bb1b549SSpandan Das    prerelease = pv[3] if len(pv) > 3 else ""
161*9bb1b549SSpandan Das    return """
162*9bb1b549SSpandan Das{prefix}MAJOR_VERSION = "{major}"
163*9bb1b549SSpandan Das{prefix}MINOR_VERSION = "{minor}"
164*9bb1b549SSpandan Das{prefix}PATCH_VERSION = "{patch}"
165*9bb1b549SSpandan Das{prefix}PRERELEASE_SUFFIX = "{prerelease}"
166*9bb1b549SSpandan Das""".format(
167*9bb1b549SSpandan Das        prefix = prefix,
168*9bb1b549SSpandan Das        major = major,
169*9bb1b549SSpandan Das        minor = minor,
170*9bb1b549SSpandan Das        patch = patch,
171*9bb1b549SSpandan Das        prerelease = prerelease,
172*9bb1b549SSpandan Das    )
173*9bb1b549SSpandan Das
174*9bb1b549SSpandan Dasdef _to_constant_name(s):
175*9bb1b549SSpandan Das    # Prefix with _ as identifiers are not allowed to start with numbers.
176*9bb1b549SSpandan Das    return "_" + "".join([c if c.isalnum() else "_" for c in s.elems()]).upper()
177*9bb1b549SSpandan Das
178*9bb1b549SSpandan Dasdef go_toolchains_single_definition(ctx, *, prefix, goos, goarch, sdk_repo, sdk_type, sdk_version):
179*9bb1b549SSpandan Das    if not goos and not goarch:
180*9bb1b549SSpandan Das        goos, goarch = detect_host_platform(ctx)
181*9bb1b549SSpandan Das    else:
182*9bb1b549SSpandan Das        if not goos:
183*9bb1b549SSpandan Das            fail("goarch set but goos not set")
184*9bb1b549SSpandan Das        if not goarch:
185*9bb1b549SSpandan Das            fail("goos set but goarch not set")
186*9bb1b549SSpandan Das
187*9bb1b549SSpandan Das    chunks = []
188*9bb1b549SSpandan Das    loads = []
189*9bb1b549SSpandan Das    identifier_prefix = _to_constant_name(prefix)
190*9bb1b549SSpandan Das
191*9bb1b549SSpandan Das    # If a sdk_version attribute is provided, use that version. This avoids
192*9bb1b549SSpandan Das    # eagerly fetching the SDK repository. But if it's not provided, we have
193*9bb1b549SSpandan Das    # no choice and must load version constants from the version.bzl file that
194*9bb1b549SSpandan Das    # _sdk_build_file creates. This will trigger an eager fetch.
195*9bb1b549SSpandan Das    if sdk_version:
196*9bb1b549SSpandan Das        chunks.append(_define_version_constants(sdk_version, prefix = identifier_prefix))
197*9bb1b549SSpandan Das    else:
198*9bb1b549SSpandan Das        loads.append("""load(
199*9bb1b549SSpandan Das    "@{sdk_repo}//:version.bzl",
200*9bb1b549SSpandan Das    {identifier_prefix}MAJOR_VERSION = "MAJOR_VERSION",
201*9bb1b549SSpandan Das    {identifier_prefix}MINOR_VERSION = "MINOR_VERSION",
202*9bb1b549SSpandan Das    {identifier_prefix}PATCH_VERSION = "PATCH_VERSION",
203*9bb1b549SSpandan Das    {identifier_prefix}PRERELEASE_SUFFIX = "PRERELEASE_SUFFIX",
204*9bb1b549SSpandan Das)
205*9bb1b549SSpandan Das""".format(
206*9bb1b549SSpandan Das            sdk_repo = sdk_repo,
207*9bb1b549SSpandan Das            identifier_prefix = identifier_prefix,
208*9bb1b549SSpandan Das        ))
209*9bb1b549SSpandan Das
210*9bb1b549SSpandan Das    chunks.append("""declare_bazel_toolchains(
211*9bb1b549SSpandan Das    prefix = "{prefix}",
212*9bb1b549SSpandan Das    go_toolchain_repo = "@{sdk_repo}",
213*9bb1b549SSpandan Das    host_goarch = "{goarch}",
214*9bb1b549SSpandan Das    host_goos = "{goos}",
215*9bb1b549SSpandan Das    major = {identifier_prefix}MAJOR_VERSION,
216*9bb1b549SSpandan Das    minor = {identifier_prefix}MINOR_VERSION,
217*9bb1b549SSpandan Das    patch = {identifier_prefix}PATCH_VERSION,
218*9bb1b549SSpandan Das    prerelease = {identifier_prefix}PRERELEASE_SUFFIX,
219*9bb1b549SSpandan Das    sdk_type = "{sdk_type}",
220*9bb1b549SSpandan Das)
221*9bb1b549SSpandan Das""".format(
222*9bb1b549SSpandan Das        prefix = prefix,
223*9bb1b549SSpandan Das        identifier_prefix = identifier_prefix,
224*9bb1b549SSpandan Das        sdk_repo = sdk_repo,
225*9bb1b549SSpandan Das        goarch = goarch,
226*9bb1b549SSpandan Das        goos = goos,
227*9bb1b549SSpandan Das        sdk_type = sdk_type,
228*9bb1b549SSpandan Das    ))
229*9bb1b549SSpandan Das
230*9bb1b549SSpandan Das    return struct(
231*9bb1b549SSpandan Das        loads = loads,
232*9bb1b549SSpandan Das        chunks = chunks,
233*9bb1b549SSpandan Das    )
234*9bb1b549SSpandan Das
235*9bb1b549SSpandan Dasdef go_toolchains_build_file_content(
236*9bb1b549SSpandan Das        ctx,
237*9bb1b549SSpandan Das        prefixes,
238*9bb1b549SSpandan Das        geese,
239*9bb1b549SSpandan Das        goarchs,
240*9bb1b549SSpandan Das        sdk_repos,
241*9bb1b549SSpandan Das        sdk_types,
242*9bb1b549SSpandan Das        sdk_versions):
243*9bb1b549SSpandan Das    if not _have_same_length(prefixes, geese, goarchs, sdk_repos, sdk_types, sdk_versions):
244*9bb1b549SSpandan Das        fail("all lists must have the same length")
245*9bb1b549SSpandan Das
246*9bb1b549SSpandan Das    loads = [
247*9bb1b549SSpandan Das        """load("@io_bazel_rules_go//go/private:go_toolchain.bzl", "declare_bazel_toolchains")""",
248*9bb1b549SSpandan Das    ]
249*9bb1b549SSpandan Das    chunks = [
250*9bb1b549SSpandan Das        """package(default_visibility = ["//visibility:public"])""",
251*9bb1b549SSpandan Das    ]
252*9bb1b549SSpandan Das
253*9bb1b549SSpandan Das    for i in range(len(geese)):
254*9bb1b549SSpandan Das        definition = go_toolchains_single_definition(
255*9bb1b549SSpandan Das            ctx,
256*9bb1b549SSpandan Das            prefix = prefixes[i],
257*9bb1b549SSpandan Das            goos = geese[i],
258*9bb1b549SSpandan Das            goarch = goarchs[i],
259*9bb1b549SSpandan Das            sdk_repo = sdk_repos[i],
260*9bb1b549SSpandan Das            sdk_type = sdk_types[i],
261*9bb1b549SSpandan Das            sdk_version = sdk_versions[i],
262*9bb1b549SSpandan Das        )
263*9bb1b549SSpandan Das        loads.extend(definition.loads)
264*9bb1b549SSpandan Das        chunks.extend(definition.chunks)
265*9bb1b549SSpandan Das
266*9bb1b549SSpandan Das    return "\n".join(loads + chunks)
267*9bb1b549SSpandan Das
268*9bb1b549SSpandan Dasdef _go_multiple_toolchains_impl(ctx):
269*9bb1b549SSpandan Das    ctx.file(
270*9bb1b549SSpandan Das        "BUILD.bazel",
271*9bb1b549SSpandan Das        go_toolchains_build_file_content(
272*9bb1b549SSpandan Das            ctx,
273*9bb1b549SSpandan Das            prefixes = ctx.attr.prefixes,
274*9bb1b549SSpandan Das            geese = ctx.attr.geese,
275*9bb1b549SSpandan Das            goarchs = ctx.attr.goarchs,
276*9bb1b549SSpandan Das            sdk_repos = ctx.attr.sdk_repos,
277*9bb1b549SSpandan Das            sdk_types = ctx.attr.sdk_types,
278*9bb1b549SSpandan Das            sdk_versions = ctx.attr.sdk_versions,
279*9bb1b549SSpandan Das        ),
280*9bb1b549SSpandan Das        executable = False,
281*9bb1b549SSpandan Das    )
282*9bb1b549SSpandan Das
283*9bb1b549SSpandan Dasgo_multiple_toolchains = repository_rule(
284*9bb1b549SSpandan Das    implementation = _go_multiple_toolchains_impl,
285*9bb1b549SSpandan Das    attrs = {
286*9bb1b549SSpandan Das        "prefixes": attr.string_list(mandatory = True),
287*9bb1b549SSpandan Das        "sdk_repos": attr.string_list(mandatory = True),
288*9bb1b549SSpandan Das        "sdk_types": attr.string_list(mandatory = True),
289*9bb1b549SSpandan Das        "sdk_versions": attr.string_list(mandatory = True),
290*9bb1b549SSpandan Das        "geese": attr.string_list(mandatory = True),
291*9bb1b549SSpandan Das        "goarchs": attr.string_list(mandatory = True),
292*9bb1b549SSpandan Das    },
293*9bb1b549SSpandan Das)
294*9bb1b549SSpandan Das
295*9bb1b549SSpandan Dasdef _go_toolchains(name, sdk_repo, sdk_type, sdk_version = None, goos = None, goarch = None):
296*9bb1b549SSpandan Das    go_multiple_toolchains(
297*9bb1b549SSpandan Das        name = name,
298*9bb1b549SSpandan Das        prefixes = [""],
299*9bb1b549SSpandan Das        geese = [goos or ""],
300*9bb1b549SSpandan Das        goarchs = [goarch or ""],
301*9bb1b549SSpandan Das        sdk_repos = [sdk_repo],
302*9bb1b549SSpandan Das        sdk_types = [sdk_type],
303*9bb1b549SSpandan Das        sdk_versions = [sdk_version or ""],
304*9bb1b549SSpandan Das    )
305*9bb1b549SSpandan Das
306*9bb1b549SSpandan Dasdef go_download_sdk(name, register_toolchains = True, **kwargs):
307*9bb1b549SSpandan Das    go_download_sdk_rule(name = name, **kwargs)
308*9bb1b549SSpandan Das    _go_toolchains(
309*9bb1b549SSpandan Das        name = name + "_toolchains",
310*9bb1b549SSpandan Das        sdk_repo = name,
311*9bb1b549SSpandan Das        sdk_type = "remote",
312*9bb1b549SSpandan Das        sdk_version = kwargs.get("version"),
313*9bb1b549SSpandan Das        goos = kwargs.get("goos"),
314*9bb1b549SSpandan Das        goarch = kwargs.get("goarch"),
315*9bb1b549SSpandan Das    )
316*9bb1b549SSpandan Das    if register_toolchains:
317*9bb1b549SSpandan Das        _register_toolchains(name)
318*9bb1b549SSpandan Das
319*9bb1b549SSpandan Dasdef _go_local_sdk_impl(ctx):
320*9bb1b549SSpandan Das    goroot = ctx.attr.path
321*9bb1b549SSpandan Das    platform = _detect_sdk_platform(ctx, goroot)
322*9bb1b549SSpandan Das    version = _detect_sdk_version(ctx, goroot)
323*9bb1b549SSpandan Das    _sdk_build_file(ctx, platform, version, ctx.attr.experiments)
324*9bb1b549SSpandan Das    _local_sdk(ctx, goroot)
325*9bb1b549SSpandan Das
326*9bb1b549SSpandan Das_go_local_sdk = repository_rule(
327*9bb1b549SSpandan Das    implementation = _go_local_sdk_impl,
328*9bb1b549SSpandan Das    attrs = {
329*9bb1b549SSpandan Das        "path": attr.string(),
330*9bb1b549SSpandan Das        "version": attr.string(),
331*9bb1b549SSpandan Das        "experiments": attr.string_list(
332*9bb1b549SSpandan Das            doc = "Go experiments to enable via GOEXPERIMENT",
333*9bb1b549SSpandan Das        ),
334*9bb1b549SSpandan Das        "_sdk_build_file": attr.label(
335*9bb1b549SSpandan Das            default = Label("//go/private:BUILD.sdk.bazel"),
336*9bb1b549SSpandan Das        ),
337*9bb1b549SSpandan Das    },
338*9bb1b549SSpandan Das)
339*9bb1b549SSpandan Das
340*9bb1b549SSpandan Dasdef go_local_sdk(name, register_toolchains = True, **kwargs):
341*9bb1b549SSpandan Das    _go_local_sdk(name = name, **kwargs)
342*9bb1b549SSpandan Das    _go_toolchains(
343*9bb1b549SSpandan Das        name = name + "_toolchains",
344*9bb1b549SSpandan Das        sdk_repo = name,
345*9bb1b549SSpandan Das        sdk_type = "remote",
346*9bb1b549SSpandan Das        sdk_version = kwargs.get("version"),
347*9bb1b549SSpandan Das        goos = kwargs.get("goos"),
348*9bb1b549SSpandan Das        goarch = kwargs.get("goarch"),
349*9bb1b549SSpandan Das    )
350*9bb1b549SSpandan Das    if register_toolchains:
351*9bb1b549SSpandan Das        _register_toolchains(name)
352*9bb1b549SSpandan Das
353*9bb1b549SSpandan Dasdef _go_wrap_sdk_impl(ctx):
354*9bb1b549SSpandan Das    if not ctx.attr.root_file and not ctx.attr.root_files:
355*9bb1b549SSpandan Das        fail("either root_file or root_files must be provided")
356*9bb1b549SSpandan Das    if ctx.attr.root_file and ctx.attr.root_files:
357*9bb1b549SSpandan Das        fail("root_file and root_files cannot be both provided")
358*9bb1b549SSpandan Das    if ctx.attr.root_file:
359*9bb1b549SSpandan Das        root_file = ctx.attr.root_file
360*9bb1b549SSpandan Das    else:
361*9bb1b549SSpandan Das        goos, goarch = detect_host_platform(ctx)
362*9bb1b549SSpandan Das        platform = goos + "_" + goarch
363*9bb1b549SSpandan Das        if platform not in ctx.attr.root_files:
364*9bb1b549SSpandan Das            fail("unsupported platform {}".format(platform))
365*9bb1b549SSpandan Das        root_file = Label(ctx.attr.root_files[platform])
366*9bb1b549SSpandan Das    goroot = str(ctx.path(root_file).dirname)
367*9bb1b549SSpandan Das    platform = _detect_sdk_platform(ctx, goroot)
368*9bb1b549SSpandan Das    version = _detect_sdk_version(ctx, goroot)
369*9bb1b549SSpandan Das    _sdk_build_file(ctx, platform, version, ctx.attr.experiments)
370*9bb1b549SSpandan Das    _local_sdk(ctx, goroot)
371*9bb1b549SSpandan Das
372*9bb1b549SSpandan Das_go_wrap_sdk = repository_rule(
373*9bb1b549SSpandan Das    implementation = _go_wrap_sdk_impl,
374*9bb1b549SSpandan Das    attrs = {
375*9bb1b549SSpandan Das        "root_file": attr.label(
376*9bb1b549SSpandan Das            mandatory = False,
377*9bb1b549SSpandan Das            doc = "A file in the SDK root direcotry. Used to determine GOROOT.",
378*9bb1b549SSpandan Das        ),
379*9bb1b549SSpandan Das        "root_files": attr.string_dict(
380*9bb1b549SSpandan Das            mandatory = False,
381*9bb1b549SSpandan Das            doc = "A set of mappings from the host platform to a file in the SDK's root directory",
382*9bb1b549SSpandan Das        ),
383*9bb1b549SSpandan Das        "version": attr.string(),
384*9bb1b549SSpandan Das        "experiments": attr.string_list(
385*9bb1b549SSpandan Das            doc = "Go experiments to enable via GOEXPERIMENT",
386*9bb1b549SSpandan Das        ),
387*9bb1b549SSpandan Das        "_sdk_build_file": attr.label(
388*9bb1b549SSpandan Das            default = Label("//go/private:BUILD.sdk.bazel"),
389*9bb1b549SSpandan Das        ),
390*9bb1b549SSpandan Das    },
391*9bb1b549SSpandan Das)
392*9bb1b549SSpandan Das
393*9bb1b549SSpandan Dasdef go_wrap_sdk(name, register_toolchains = True, **kwargs):
394*9bb1b549SSpandan Das    _go_wrap_sdk(name = name, **kwargs)
395*9bb1b549SSpandan Das    _go_toolchains(
396*9bb1b549SSpandan Das        name = name + "_toolchains",
397*9bb1b549SSpandan Das        sdk_repo = name,
398*9bb1b549SSpandan Das        sdk_type = "remote",
399*9bb1b549SSpandan Das        sdk_version = kwargs.get("version"),
400*9bb1b549SSpandan Das        goos = kwargs.get("goos"),
401*9bb1b549SSpandan Das        goarch = kwargs.get("goarch"),
402*9bb1b549SSpandan Das    )
403*9bb1b549SSpandan Das    if register_toolchains:
404*9bb1b549SSpandan Das        _register_toolchains(name)
405*9bb1b549SSpandan Das
406*9bb1b549SSpandan Dasdef _register_toolchains(repo):
407*9bb1b549SSpandan Das    native.register_toolchains("@{}_toolchains//:all".format(repo))
408*9bb1b549SSpandan Das
409*9bb1b549SSpandan Dasdef _remote_sdk(ctx, urls, strip_prefix, sha256):
410*9bb1b549SSpandan Das    if len(urls) == 0:
411*9bb1b549SSpandan Das        fail("no urls specified")
412*9bb1b549SSpandan Das    host_goos, _ = detect_host_platform(ctx)
413*9bb1b549SSpandan Das
414*9bb1b549SSpandan Das    ctx.report_progress("Downloading and extracting Go toolchain")
415*9bb1b549SSpandan Das
416*9bb1b549SSpandan Das    # TODO(#2771): After bazelbuild/bazel#18448 is merged and available in
417*9bb1b549SSpandan Das    # the minimum supported version of Bazel, remove the workarounds below.
418*9bb1b549SSpandan Das    #
419*9bb1b549SSpandan Das    # Go ships archives containing some non-ASCII file names, used in
420*9bb1b549SSpandan Das    # test cases for Go's build system. Bazel has a bug extracting these
421*9bb1b549SSpandan Das    # archives on certain file systems (macOS AFS at least, possibly also
422*9bb1b549SSpandan Das    # Docker on macOS with a bind mount).
423*9bb1b549SSpandan Das    #
424*9bb1b549SSpandan Das    # For .tar.gz files (available for most platforms), we work around this bug
425*9bb1b549SSpandan Das    # by using the system tar instead of ctx.download_and_extract.
426*9bb1b549SSpandan Das    #
427*9bb1b549SSpandan Das    # For .zip files, we use ctx.download_and_extract but with rename_files,
428*9bb1b549SSpandan Das    # changing certain paths that trigger the bug. This is only available
429*9bb1b549SSpandan Das    # in Bazel 6.0.0+ (bazelbuild/bazel#16052). The only situation where
430*9bb1b549SSpandan Das    # .zip files are needed seems to be a macOS host using a Windows toolchain
431*9bb1b549SSpandan Das    # for remote execution.
432*9bb1b549SSpandan Das    if urls[0].endswith(".tar.gz"):
433*9bb1b549SSpandan Das        if strip_prefix != "go":
434*9bb1b549SSpandan Das            fail("strip_prefix not supported")
435*9bb1b549SSpandan Das        ctx.download(
436*9bb1b549SSpandan Das            url = urls,
437*9bb1b549SSpandan Das            sha256 = sha256,
438*9bb1b549SSpandan Das            output = "go_sdk.tar.gz",
439*9bb1b549SSpandan Das        )
440*9bb1b549SSpandan Das        res = ctx.execute(["tar", "-xf", "go_sdk.tar.gz", "--strip-components=1"])
441*9bb1b549SSpandan Das        if res.return_code:
442*9bb1b549SSpandan Das            fail("error extracting Go SDK:\n" + res.stdout + res.stderr)
443*9bb1b549SSpandan Das        ctx.delete("go_sdk.tar.gz")
444*9bb1b549SSpandan Das    elif (urls[0].endswith(".zip") and
445*9bb1b549SSpandan Das          host_goos != "windows" and
446*9bb1b549SSpandan Das          # Development versions of Bazel have an empty version string. We assume that they are
447*9bb1b549SSpandan Das          # more recent than the version that introduced rename_files.
448*9bb1b549SSpandan Das          versions.is_at_least("6.0.0", versions.get() or "6.0.0")):
449*9bb1b549SSpandan Das        ctx.download_and_extract(
450*9bb1b549SSpandan Das            url = urls,
451*9bb1b549SSpandan Das            stripPrefix = strip_prefix,
452*9bb1b549SSpandan Das            sha256 = sha256,
453*9bb1b549SSpandan Das            rename_files = {
454*9bb1b549SSpandan Das                "go/test/fixedbugs/issue27836.dir/\336foo.go": "go/test/fixedbugs/issue27836.dir/thfoo.go",
455*9bb1b549SSpandan Das                "go/test/fixedbugs/issue27836.dir/\336main.go": "go/test/fixedbugs/issue27836.dir/thmain.go",
456*9bb1b549SSpandan Das            },
457*9bb1b549SSpandan Das        )
458*9bb1b549SSpandan Das    else:
459*9bb1b549SSpandan Das        ctx.download_and_extract(
460*9bb1b549SSpandan Das            url = urls,
461*9bb1b549SSpandan Das            stripPrefix = strip_prefix,
462*9bb1b549SSpandan Das            sha256 = sha256,
463*9bb1b549SSpandan Das        )
464*9bb1b549SSpandan Das
465*9bb1b549SSpandan Dasdef _local_sdk(ctx, path):
466*9bb1b549SSpandan Das    for entry in ["src", "pkg", "bin", "lib", "misc"]:
467*9bb1b549SSpandan Das        ctx.symlink(path + "/" + entry, entry)
468*9bb1b549SSpandan Das
469*9bb1b549SSpandan Dasdef _sdk_build_file(ctx, platform, version, experiments):
470*9bb1b549SSpandan Das    ctx.file("ROOT")
471*9bb1b549SSpandan Das    goos, _, goarch = platform.partition("_")
472*9bb1b549SSpandan Das
473*9bb1b549SSpandan Das    pv = parse_version(version)
474*9bb1b549SSpandan Das    if pv != None and pv[1] >= 20:
475*9bb1b549SSpandan Das        # Turn off coverageredesign GOEXPERIMENT on 1.20+
476*9bb1b549SSpandan Das        # until rules_go is updated to work with the
477*9bb1b549SSpandan Das        # coverage redesign.
478*9bb1b549SSpandan Das        if not "nocoverageredesign" in experiments and not "coverageredesign" in experiments:
479*9bb1b549SSpandan Das            experiments = experiments + ["nocoverageredesign"]
480*9bb1b549SSpandan Das
481*9bb1b549SSpandan Das    ctx.template(
482*9bb1b549SSpandan Das        "BUILD.bazel",
483*9bb1b549SSpandan Das        ctx.path(ctx.attr._sdk_build_file),
484*9bb1b549SSpandan Das        executable = False,
485*9bb1b549SSpandan Das        substitutions = {
486*9bb1b549SSpandan Das            "{goos}": goos,
487*9bb1b549SSpandan Das            "{goarch}": goarch,
488*9bb1b549SSpandan Das            "{exe}": ".exe" if goos == "windows" else "",
489*9bb1b549SSpandan Das            "{version}": version,
490*9bb1b549SSpandan Das            "{experiments}": repr(experiments),
491*9bb1b549SSpandan Das        },
492*9bb1b549SSpandan Das    )
493*9bb1b549SSpandan Das
494*9bb1b549SSpandan Das    ctx.file(
495*9bb1b549SSpandan Das        "version.bzl",
496*9bb1b549SSpandan Das        executable = False,
497*9bb1b549SSpandan Das        content = _define_version_constants(version),
498*9bb1b549SSpandan Das    )
499*9bb1b549SSpandan Das
500*9bb1b549SSpandan Dasdef detect_host_platform(ctx):
501*9bb1b549SSpandan Das    goos = ctx.os.name
502*9bb1b549SSpandan Das    if goos == "mac os x":
503*9bb1b549SSpandan Das        goos = "darwin"
504*9bb1b549SSpandan Das    elif goos.startswith("windows"):
505*9bb1b549SSpandan Das        goos = "windows"
506*9bb1b549SSpandan Das
507*9bb1b549SSpandan Das    goarch = ctx.os.arch
508*9bb1b549SSpandan Das    if goarch == "aarch64":
509*9bb1b549SSpandan Das        goarch = "arm64"
510*9bb1b549SSpandan Das    elif goarch == "x86_64":
511*9bb1b549SSpandan Das        goarch = "amd64"
512*9bb1b549SSpandan Das
513*9bb1b549SSpandan Das    return goos, goarch
514*9bb1b549SSpandan Das
515*9bb1b549SSpandan Dasdef _detect_host_sdk(ctx):
516*9bb1b549SSpandan Das    root = "@invalid@"
517*9bb1b549SSpandan Das    if "GOROOT" in ctx.os.environ:
518*9bb1b549SSpandan Das        return ctx.os.environ["GOROOT"]
519*9bb1b549SSpandan Das    res = ctx.execute([executable_path(ctx, "go"), "env", "GOROOT"])
520*9bb1b549SSpandan Das    if res.return_code:
521*9bb1b549SSpandan Das        fail("Could not detect host go version")
522*9bb1b549SSpandan Das    root = res.stdout.strip()
523*9bb1b549SSpandan Das    if not root:
524*9bb1b549SSpandan Das        fail("host go version failed to report it's GOROOT")
525*9bb1b549SSpandan Das    return root
526*9bb1b549SSpandan Das
527*9bb1b549SSpandan Dasdef _detect_sdk_platform(ctx, goroot):
528*9bb1b549SSpandan Das    path = ctx.path(goroot + "/pkg/tool")
529*9bb1b549SSpandan Das    if not path.exists:
530*9bb1b549SSpandan Das        fail("Could not detect SDK platform: failed to find " + str(path))
531*9bb1b549SSpandan Das    tool_entries = path.readdir()
532*9bb1b549SSpandan Das
533*9bb1b549SSpandan Das    platforms = []
534*9bb1b549SSpandan Das    for f in tool_entries:
535*9bb1b549SSpandan Das        if f.basename.find("_") >= 0:
536*9bb1b549SSpandan Das            platforms.append(f.basename)
537*9bb1b549SSpandan Das
538*9bb1b549SSpandan Das    if len(platforms) == 0:
539*9bb1b549SSpandan Das        fail("Could not detect SDK platform: found no platforms in %s" % path)
540*9bb1b549SSpandan Das    if len(platforms) > 1:
541*9bb1b549SSpandan Das        fail("Could not detect SDK platform: found multiple platforms %s in %s" % (platforms, path))
542*9bb1b549SSpandan Das    return platforms[0]
543*9bb1b549SSpandan Das
544*9bb1b549SSpandan Dasdef _detect_sdk_version(ctx, goroot):
545*9bb1b549SSpandan Das    version_file_path = goroot + "/VERSION"
546*9bb1b549SSpandan Das    if ctx.path(version_file_path).exists:
547*9bb1b549SSpandan Das        # VERSION file has version prefixed by go, eg. go1.18.3
548*9bb1b549SSpandan Das        version = ctx.read(version_file_path)[2:]
549*9bb1b549SSpandan Das        if ctx.attr.version and ctx.attr.version != version:
550*9bb1b549SSpandan Das            fail("SDK is version %s, but version %s was expected" % (version, ctx.attr.version))
551*9bb1b549SSpandan Das        return version
552*9bb1b549SSpandan Das
553*9bb1b549SSpandan Das    # The top-level VERSION file does not exist in all Go SDK distributions, e.g. those shipped by Debian or Fedora.
554*9bb1b549SSpandan Das    # Falling back to running "go version"
555*9bb1b549SSpandan Das    go_binary_path = goroot + "/bin/go"
556*9bb1b549SSpandan Das    result = ctx.execute([go_binary_path, "version"])
557*9bb1b549SSpandan Das    if result.return_code != 0:
558*9bb1b549SSpandan Das        fail("Could not detect SDK version: '%s version' exited with exit code %d" % (go_binary_path, result.return_code))
559*9bb1b549SSpandan Das
560*9bb1b549SSpandan Das    # go version output is of the form "go version go1.18.3 linux/amd64" or "go
561*9bb1b549SSpandan Das    # version devel go1.19-fd1b5904ae Tue Mar 22 21:38:10 2022 +0000
562*9bb1b549SSpandan Das    # linux/amd64". See the following links for how this output is generated:
563*9bb1b549SSpandan Das    # - https://github.com/golang/go/blob/2bdb5c57f1efcbddab536028d053798e35de6226/src/cmd/go/internal/version/version.go#L75
564*9bb1b549SSpandan Das    # - https://github.com/golang/go/blob/2bdb5c57f1efcbddab536028d053798e35de6226/src/cmd/dist/build.go#L333
565*9bb1b549SSpandan Das    #
566*9bb1b549SSpandan Das    # Read the third word, or the fourth word if the third word is "devel", to
567*9bb1b549SSpandan Das    # find the version number.
568*9bb1b549SSpandan Das    output_parts = result.stdout.split(" ")
569*9bb1b549SSpandan Das    if len(output_parts) > 2 and output_parts[2].startswith("go"):
570*9bb1b549SSpandan Das        version = output_parts[2][len("go"):]
571*9bb1b549SSpandan Das    elif len(output_parts) > 3 and output_parts[2] == "devel" and output_parts[3].startswith("go"):
572*9bb1b549SSpandan Das        version = output_parts[3][len("go"):]
573*9bb1b549SSpandan Das    else:
574*9bb1b549SSpandan Das        fail("Could not parse SDK version from '%s version' output: %s" % (go_binary_path, result.stdout))
575*9bb1b549SSpandan Das    if parse_version(version) == None:
576*9bb1b549SSpandan Das        fail("Could not parse SDK version from '%s version' output: %s" % (go_binary_path, result.stdout))
577*9bb1b549SSpandan Das    if ctx.attr.version and ctx.attr.version != version:
578*9bb1b549SSpandan Das        fail("SDK is version %s, but version %s was expected" % (version, ctx.attr.version))
579*9bb1b549SSpandan Das    return version
580*9bb1b549SSpandan Das
581*9bb1b549SSpandan Dasdef _parse_versions_json(data):
582*9bb1b549SSpandan Das    """Parses version metadata returned by go.dev.
583*9bb1b549SSpandan Das
584*9bb1b549SSpandan Das    Args:
585*9bb1b549SSpandan Das        data: the contents of the file downloaded from
586*9bb1b549SSpandan Das            https://go.dev/dl/?mode=json. We assume the file is valid
587*9bb1b549SSpandan Das            JSON, is spaced and indented, and is in a particular format.
588*9bb1b549SSpandan Das
589*9bb1b549SSpandan Das    Return:
590*9bb1b549SSpandan Das        A dict mapping version strings (like "1.15.5") to dicts mapping
591*9bb1b549SSpandan Das        platform names (like "linux_amd64") to pairs of filenames
592*9bb1b549SSpandan Das        (like "go1.15.5.linux-amd64.tar.gz") and hex-encoded SHA-256 sums.
593*9bb1b549SSpandan Das    """
594*9bb1b549SSpandan Das    sdks = json.decode(data)
595*9bb1b549SSpandan Das    return {
596*9bb1b549SSpandan Das        sdk["version"][len("go"):]: {
597*9bb1b549SSpandan Das            "%s_%s" % (file["os"], file["arch"]): (
598*9bb1b549SSpandan Das                file["filename"],
599*9bb1b549SSpandan Das                file["sha256"],
600*9bb1b549SSpandan Das            )
601*9bb1b549SSpandan Das            for file in sdk["files"]
602*9bb1b549SSpandan Das            if file["kind"] == "archive"
603*9bb1b549SSpandan Das        }
604*9bb1b549SSpandan Das        for sdk in sdks
605*9bb1b549SSpandan Das    }
606*9bb1b549SSpandan Das
607*9bb1b549SSpandan Dasdef parse_version(version):
608*9bb1b549SSpandan Das    """Parses a version string like "1.15.5" and returns a tuple of numbers or None"""
609*9bb1b549SSpandan Das    l, r = 0, 0
610*9bb1b549SSpandan Das    parsed = []
611*9bb1b549SSpandan Das    for c in version.elems():
612*9bb1b549SSpandan Das        if c == ".":
613*9bb1b549SSpandan Das            if l == r:
614*9bb1b549SSpandan Das                # empty component
615*9bb1b549SSpandan Das                return None
616*9bb1b549SSpandan Das            parsed.append(int(version[l:r]))
617*9bb1b549SSpandan Das            r += 1
618*9bb1b549SSpandan Das            l = r
619*9bb1b549SSpandan Das            continue
620*9bb1b549SSpandan Das
621*9bb1b549SSpandan Das        if c.isdigit():
622*9bb1b549SSpandan Das            r += 1
623*9bb1b549SSpandan Das            continue
624*9bb1b549SSpandan Das
625*9bb1b549SSpandan Das        # pre-release suffix
626*9bb1b549SSpandan Das        break
627*9bb1b549SSpandan Das
628*9bb1b549SSpandan Das    if l == r:
629*9bb1b549SSpandan Das        # empty component
630*9bb1b549SSpandan Das        return None
631*9bb1b549SSpandan Das    parsed.append(int(version[l:r]))
632*9bb1b549SSpandan Das    if len(parsed) == 2:
633*9bb1b549SSpandan Das        # first minor version, like (1, 15)
634*9bb1b549SSpandan Das        parsed.append(0)
635*9bb1b549SSpandan Das    if len(parsed) != 3:
636*9bb1b549SSpandan Das        # too many or too few components
637*9bb1b549SSpandan Das        return None
638*9bb1b549SSpandan Das    if r < len(version):
639*9bb1b549SSpandan Das        # pre-release suffix
640*9bb1b549SSpandan Das        parsed.append(version[r:])
641*9bb1b549SSpandan Das    return tuple(parsed)
642*9bb1b549SSpandan Das
643*9bb1b549SSpandan Dasdef _version_is_prerelease(v):
644*9bb1b549SSpandan Das    return len(v) > 3
645*9bb1b549SSpandan Das
646*9bb1b549SSpandan Dasdef _version_less(a, b):
647*9bb1b549SSpandan Das    if a[:3] < b[:3]:
648*9bb1b549SSpandan Das        return True
649*9bb1b549SSpandan Das    if a[:3] > b[:3]:
650*9bb1b549SSpandan Das        return False
651*9bb1b549SSpandan Das    if len(a) > len(b):
652*9bb1b549SSpandan Das        return True
653*9bb1b549SSpandan Das    if len(a) < len(b) or len(a) == 3:
654*9bb1b549SSpandan Das        return False
655*9bb1b549SSpandan Das    return a[3:] < b[3:]
656*9bb1b549SSpandan Das
657*9bb1b549SSpandan Dasdef _version_string(v):
658*9bb1b549SSpandan Das    suffix = v[3] if _version_is_prerelease(v) else ""
659*9bb1b549SSpandan Das    if v[-1] == 0:
660*9bb1b549SSpandan Das        v = v[:-1]
661*9bb1b549SSpandan Das    return ".".join([str(n) for n in v]) + suffix
662*9bb1b549SSpandan Das
663*9bb1b549SSpandan Dasdef _have_same_length(*lists):
664*9bb1b549SSpandan Das    if not lists:
665*9bb1b549SSpandan Das        fail("expected at least one list")
666*9bb1b549SSpandan Das    return len({len(l): None for l in lists}) == 1
667*9bb1b549SSpandan Das
668*9bb1b549SSpandan Dasdef go_register_toolchains(version = None, nogo = None, go_version = None, experiments = None):
669*9bb1b549SSpandan Das    """See /go/toolchains.rst#go-register-toolchains for full documentation."""
670*9bb1b549SSpandan Das    if not version:
671*9bb1b549SSpandan Das        version = go_version  # old name
672*9bb1b549SSpandan Das
673*9bb1b549SSpandan Das    sdk_kinds = ("go_download_sdk_rule", "go_host_sdk_rule", "_go_local_sdk", "_go_wrap_sdk")
674*9bb1b549SSpandan Das    existing_rules = native.existing_rules()
675*9bb1b549SSpandan Das    sdk_rules = [r for r in existing_rules.values() if r["kind"] in sdk_kinds]
676*9bb1b549SSpandan Das    if len(sdk_rules) == 0 and "go_sdk" in existing_rules:
677*9bb1b549SSpandan Das        # may be local_repository in bazel_tests.
678*9bb1b549SSpandan Das        sdk_rules.append(existing_rules["go_sdk"])
679*9bb1b549SSpandan Das
680*9bb1b549SSpandan Das    if version and len(sdk_rules) > 0:
681*9bb1b549SSpandan Das        fail("go_register_toolchains: version set after go sdk rule declared ({})".format(", ".join([r["name"] for r in sdk_rules])))
682*9bb1b549SSpandan Das    if len(sdk_rules) == 0:
683*9bb1b549SSpandan Das        if not version:
684*9bb1b549SSpandan Das            fail('go_register_toolchains: version must be a string like "1.15.5" or "host"')
685*9bb1b549SSpandan Das        elif version == "host":
686*9bb1b549SSpandan Das            go_host_sdk(name = "go_sdk", experiments = experiments)
687*9bb1b549SSpandan Das        else:
688*9bb1b549SSpandan Das            pv = parse_version(version)
689*9bb1b549SSpandan Das            if not pv:
690*9bb1b549SSpandan Das                fail('go_register_toolchains: version must be a string like "1.15.5" or "host"')
691*9bb1b549SSpandan Das            if _version_less(pv, MIN_SUPPORTED_VERSION):
692*9bb1b549SSpandan Das                print("DEPRECATED: Go versions before {} are not supported and may not work".format(_version_string(MIN_SUPPORTED_VERSION)))
693*9bb1b549SSpandan Das            go_download_sdk(
694*9bb1b549SSpandan Das                name = "go_sdk",
695*9bb1b549SSpandan Das                version = version,
696*9bb1b549SSpandan Das                experiments = experiments,
697*9bb1b549SSpandan Das            )
698*9bb1b549SSpandan Das
699*9bb1b549SSpandan Das    if nogo:
700*9bb1b549SSpandan Das        # Override default definition in go_rules_dependencies().
701*9bb1b549SSpandan Das        go_register_nogo(
702*9bb1b549SSpandan Das            name = "io_bazel_rules_nogo",
703*9bb1b549SSpandan Das            nogo = nogo,
704*9bb1b549SSpandan Das        )
705