From cc454109d78ce52edcad3902a0c39f72c857d4a6 Mon Sep 17 00:00:00 2001 From: hunshcn Date: Tue, 22 Aug 2023 14:21:25 +0800 Subject: [PATCH] go_download_sdk: allow patching to stdlib --- go/private/sdk.bzl | 73 +++++++- go/toolchains.rst | 164 ++++++++++++++++++ .../go_download_sdk/go_download_sdk_test.go | 36 +++- 3 files changed, 261 insertions(+), 12 deletions(-) diff --git a/go/private/sdk.bzl b/go/private/sdk.bzl index 08c6e74c00..de8555ff6b 100644 --- a/go/private/sdk.bzl +++ b/go/private/sdk.bzl @@ -24,6 +24,61 @@ load( "//go/private/skylib/lib:versions.bzl", "versions", ) +load( + "@bazel_tools//tools/build_defs/repo:utils.bzl", + "patch", +) + +patch_attrs = { + "patches": attr.label_list( + default = [], + doc = + "A list of files that are to be applied as patches after " + + "extracting the archive. By default, it uses the Bazel-native patch implementation " + + "which doesn't support fuzz match and binary patch, but Bazel will fall back to use " + + "patch command line tool if `patch_tool` attribute is specified or there are " + + "arguments other than `-p` in `patch_args` attribute.", + ), + "remote_patches": attr.string_dict( + default = {}, + doc = + "A map of patch file URL to its integrity value, they are applied after extracting " + + "the archive and before applying patch files from the `patches` attribute. " + + "It uses the Bazel-native patch implementation, you can specify the patch strip " + + "number with `remote_patch_strip`", + ), + "remote_patch_strip": attr.int( + default = 0, + doc = + "The number of leading slashes to be stripped from the file name in the remote patches.", + ), + "patch_tool": attr.string( + default = "", + doc = "The patch(1) utility to use. If this is specified, Bazel will use the specified " + + "patch tool instead of the Bazel-native patch implementation.", + ), + "patch_args": attr.string_list( + default = ["-p0"], + doc = + "The arguments given to the patch tool. Defaults to -p0, " + + "however -p1 will usually be needed for patches generated by " + + "git. If multiple -p arguments are specified, the last one will take effect." + + "If arguments other than -p are specified, Bazel will fall back to use patch " + + "command line tool instead of the Bazel-native patch implementation. When falling " + + "back to patch command line tool and patch_tool attribute is not specified, " + + "`patch` will be used. This only affects patch files in the `patches` attribute.", + ), + "patch_cmds": attr.string_list( + default = [], + doc = "Sequence of Bash commands to be applied on Linux/Macos after patches are applied.", + ), + "patch_cmds_win": attr.string_list( + default = [], + doc = "Sequence of Powershell commands to be applied on Windows after patches are " + + "applied. If this attribute is not set, patch_cmds will be executed on Windows, " + + "which requires Bash binary to exist.", + ), +} MIN_SUPPORTED_VERSION = (1, 14, 0) @@ -37,7 +92,7 @@ def _go_host_sdk_impl(ctx): go_host_sdk_rule = repository_rule( implementation = _go_host_sdk_impl, environ = ["GOROOT"], - attrs = { + attrs = dict({ "version": attr.string(), "experiments": attr.string_list( doc = "Go experiments to enable via GOEXPERIMENT", @@ -45,7 +100,7 @@ go_host_sdk_rule = repository_rule( "_sdk_build_file": attr.label( default = Label("//go/private:BUILD.sdk.bazel"), ), - }, + }, **patch_attrs), ) def go_host_sdk(name, register_toolchains = True, **kwargs): @@ -136,7 +191,7 @@ def _go_download_sdk_impl(ctx): go_download_sdk_rule = repository_rule( implementation = _go_download_sdk_impl, - attrs = { + attrs = dict({ "goos": attr.string(), "goarch": attr.string(), "sdks": attr.string_list_dict(), @@ -149,7 +204,7 @@ go_download_sdk_rule = repository_rule( "_sdk_build_file": attr.label( default = Label("//go/private:BUILD.sdk.bazel"), ), - }, + }, **patch_attrs), ) def _define_version_constants(version, prefix = ""): @@ -325,7 +380,7 @@ def _go_local_sdk_impl(ctx): _go_local_sdk = repository_rule( implementation = _go_local_sdk_impl, - attrs = { + attrs = dict({ "path": attr.string(), "version": attr.string(), "experiments": attr.string_list( @@ -334,7 +389,7 @@ _go_local_sdk = repository_rule( "_sdk_build_file": attr.label( default = Label("//go/private:BUILD.sdk.bazel"), ), - }, + }, **patch_attrs), ) def go_local_sdk(name, register_toolchains = True, **kwargs): @@ -371,7 +426,7 @@ def _go_wrap_sdk_impl(ctx): _go_wrap_sdk = repository_rule( implementation = _go_wrap_sdk_impl, - attrs = { + attrs = dict({ "root_file": attr.label( mandatory = False, doc = "A file in the SDK root direcotry. Used to determine GOROOT.", @@ -387,7 +442,7 @@ _go_wrap_sdk = repository_rule( "_sdk_build_file": attr.label( default = Label("//go/private:BUILD.sdk.bazel"), ), - }, + }, **patch_attrs), ) def go_wrap_sdk(name, register_toolchains = True, **kwargs): @@ -478,6 +533,8 @@ def _sdk_build_file(ctx, platform, version, experiments): if not "nocoverageredesign" in experiments and not "coverageredesign" in experiments: experiments = experiments + ["nocoverageredesign"] + patch(ctx) + ctx.template( "BUILD.bazel", ctx.path(ctx.attr._sdk_build_file), diff --git a/go/toolchains.rst b/go/toolchains.rst index 57182aab5c..03553d790b 100644 --- a/go/toolchains.rst +++ b/go/toolchains.rst @@ -313,6 +313,47 @@ This downloads a Go SDK for use in toolchains. | Go distribution (with a different SHA-256 sum) or a version of Go | | not supported by rules_go (for example, a beta or release candidate). | +--------------------------------+-----------------------------+---------------------------------------------+ +| :param:`patches` | :type:`label_list` | :value:`[]` | ++--------------------------------+-----------------------------+---------------------------------------------+ +| A list of files that are to be applied to go sdk. By default, it uses the Bazel-native patch | +| implementation which doesn't support fuzz match and binary patch, but Bazel will fall back to use | +| patch command line tool if `patch_tool` attribute is specified or there are | +| arguments other than `-p` in `patch_args` attribute. | ++--------------------------------+-----------------------------+---------------------------------------------+ +| :param:`remote_patches` | :type:`string_dict` | :value:`{}` | ++--------------------------------+-----------------------------+---------------------------------------------+ +| A map of patch file URL to its integrity value, they are applied before applying patch files | +| from the `patches` attribute. It uses the Bazel-native patch implementation, you can specify | +| the patch strip number with `remote_patch_strip`. | ++--------------------------------+-----------------------------+---------------------------------------------+ +| :param:`remote_patch_strip` | :type:`int` | :value:`0` | ++--------------------------------+-----------------------------+---------------------------------------------+ +| The number of leading slashes to be stripped from the file name in the remote patches. | ++--------------------------------+-----------------------------+---------------------------------------------+ +| :param:`patch_tool` | :type:`string` | :value:`""` | ++--------------------------------+-----------------------------+---------------------------------------------+ +| The patch(1) utility to use. If this is specified, Bazel will use the specified | +| patch tool instead of the Bazel-native patch implementation. | ++--------------------------------+-----------------------------+---------------------------------------------+ +| :param:`patch_args` | :type:`string_list` | :value:`["-p0"]` | ++--------------------------------+-----------------------------+---------------------------------------------+ +| The arguments given to the patch tool. Defaults to -p0, however -p1 will usually be | +| needed for patches generated by git. If multiple -p arguments are specified, the last | +| one will take effect. If arguments other than -p are specified, Bazel will fall back to | +| use patch command line tool instead of the Bazel-native patch implementation. | +| When falling back to patch command line tool and patch_tool attribute is not specified, | +| `patch` will be used. This only affects patch files in the `patches` attribute. | ++--------------------------------+-----------------------------+---------------------------------------------+ +| :param:`patch_cmds` | :type:`string_list` | :value:`[]` | ++--------------------------------+-----------------------------+---------------------------------------------+ +| Sequence of Bash commands to be applied on Linux/Macos after patches are applied. | ++--------------------------------+-----------------------------+---------------------------------------------+ +| :param:`patch_cmds_win` | :type:`string_list` | :value:`[]` | ++--------------------------------+-----------------------------+---------------------------------------------+ +| Sequence of Powershell commands to be applied on Windows after patches are applied. | +| If this attribute is not set, patch_cmds will be executed on Windows, which requires Bash binary to exist. | ++--------------------------------+-----------------------------+---------------------------------------------+ + **Example**: @@ -375,6 +416,47 @@ used. Otherwise, ``go env GOROOT`` is used. +--------------------------------+-----------------------------+-----------------------------------+ | Go experiments to enable via `GOEXPERIMENT`. | +--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patches` | :type:`label_list` | :value:`[]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| A list of files that are to be applied to go sdk. By default, it uses the Bazel-native patch | +| implementation which doesn't support fuzz match and binary patch, but Bazel will fall back to | +| use patch command line tool if `patch_tool` attribute is specified or there are | +| arguments other than `-p` in `patch_args` attribute. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`remote_patches` | :type:`string_dict` | :value:`{}` | ++--------------------------------+-----------------------------+-----------------------------------+ +| A map of patch file URL to its integrity value, they are applied before applying patch files | +| from the `patches` attribute. It uses the Bazel-native patch implementation, you can specify | +| the patch strip number with `remote_patch_strip`. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`remote_patch_strip` | :type:`int` | :value:`0` | ++--------------------------------+-----------------------------+-----------------------------------+ +| The number of leading slashes to be stripped from the file name in the remote patches. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_tool` | :type:`string` | :value:`""` | ++--------------------------------+-----------------------------+-----------------------------------+ +| The patch(1) utility to use. If this is specified, Bazel will use the specified | +| patch tool instead of the Bazel-native patch implementation. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_args` | :type:`string_list` | :value:`["-p0"]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| The arguments given to the patch tool. Defaults to -p0, however -p1 will usually be | +| needed for patches generated by git. If multiple -p arguments are specified, the last | +| one will take effect. If arguments other than -p are specified, Bazel will fall back to | +| use patch command line tool instead of the Bazel-native patch implementation. | +| When falling back to patch command line tool and patch_tool attribute is not specified, | +| `patch` will be used. This only affects patch files in the `patches` attribute. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_cmds` | :type:`string_list` | :value:`[]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| Sequence of Bash commands to be applied on Linux/Macos after patches are applied. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_cmds_win` | :type:`string_list` | :value:`[]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| Sequence of Powershell commands to be applied on Windows after patches are applied. | +| If this attribute is not set, patch_cmds will be executed on Windows, which requires | +| Bash binary to exist. | ++--------------------------------+-----------------------------+-----------------------------------+ go_local_sdk ~~~~~~~~~~~~ @@ -404,6 +486,47 @@ This prepares a local path to use as the Go SDK in toolchains. +--------------------------------+-----------------------------+-----------------------------------+ | Go experiments to enable via `GOEXPERIMENT`. | +--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patches` | :type:`label_list` | :value:`[]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| A list of files that are to be applied to go sdk. By default, it uses the Bazel-native patch | +| implementation which doesn't support fuzz match and binary patch, but Bazel will fall back to | +| use patch command line tool if `patch_tool` attribute is specified or there are | +| arguments other than `-p` in `patch_args` attribute. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`remote_patches` | :type:`string_dict` | :value:`{}` | ++--------------------------------+-----------------------------+-----------------------------------+ +| A map of patch file URL to its integrity value, they are applied before applying patch files | +| from the `patches` attribute. It uses the Bazel-native patch implementation, you can specify | +| the patch strip number with `remote_patch_strip`. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`remote_patch_strip` | :type:`int` | :value:`0` | ++--------------------------------+-----------------------------+-----------------------------------+ +| The number of leading slashes to be stripped from the file name in the remote patches. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_tool` | :type:`string` | :value:`""` | ++--------------------------------+-----------------------------+-----------------------------------+ +| The patch(1) utility to use. If this is specified, Bazel will use the specified | +| patch tool instead of the Bazel-native patch implementation. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_args` | :type:`string_list` | :value:`["-p0"]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| The arguments given to the patch tool. Defaults to -p0, however -p1 will usually be | +| needed for patches generated by git. If multiple -p arguments are specified, the last | +| one will take effect. If arguments other than -p are specified, Bazel will fall back to | +| use patch command line tool instead of the Bazel-native patch implementation. | +| When falling back to patch command line tool and patch_tool attribute is not specified, | +| `patch` will be used. This only affects patch files in the `patches` attribute. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_cmds` | :type:`string_list` | :value:`[]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| Sequence of Bash commands to be applied on Linux/Macos after patches are applied. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_cmds_win` | :type:`string_list` | :value:`[]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| Sequence of Powershell commands to be applied on Windows after patches are applied. | +| If this attribute is not set, patch_cmds will be executed on Windows, which requires | +| Bash binary to exist. | ++--------------------------------+-----------------------------+-----------------------------------+ go_wrap_sdk @@ -440,6 +563,47 @@ rule. +--------------------------------+-----------------------------+-----------------------------------+ | Go experiments to enable via `GOEXPERIMENT`. | +--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patches` | :type:`label_list` | :value:`[]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| A list of files that are to be applied to go sdk. By default, it uses the Bazel-native patch | +| implementation which doesn't support fuzz match and binary patch, but Bazel will fall back to | +| use patch command line tool if `patch_tool` attribute is specified or there are | +| arguments other than `-p` in `patch_args` attribute. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`remote_patches` | :type:`string_dict` | :value:`{}` | ++--------------------------------+-----------------------------+-----------------------------------+ +| A map of patch file URL to its integrity value, they are applied before applying patch files | +| from the `patches` attribute. It uses the Bazel-native patch implementation, you can specify | +| the patch strip number with `remote_patch_strip`. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`remote_patch_strip` | :type:`int` | :value:`0` | ++--------------------------------+-----------------------------+-----------------------------------+ +| The number of leading slashes to be stripped from the file name in the remote patches. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_tool` | :type:`string` | :value:`""` | ++--------------------------------+-----------------------------+-----------------------------------+ +| The patch(1) utility to use. If this is specified, Bazel will use the specified | +| patch tool instead of the Bazel-native patch implementation. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_args` | :type:`string_list` | :value:`["-p0"]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| The arguments given to the patch tool. Defaults to -p0, however -p1 will usually be | +| needed for patches generated by git. If multiple -p arguments are specified, the last | +| one will take effect. If arguments other than -p are specified, Bazel will fall back to | +| use patch command line tool instead of the Bazel-native patch implementation. | +| When falling back to patch command line tool and patch_tool attribute is not specified, | +| `patch` will be used. This only affects patch files in the `patches` attribute. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_cmds` | :type:`string_list` | :value:`[]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| Sequence of Bash commands to be applied on Linux/Macos after patches are applied. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`patch_cmds_win` | :type:`string_list` | :value:`[]` | ++--------------------------------+-----------------------------+-----------------------------------+ +| Sequence of Powershell commands to be applied on Windows after patches are applied. | +| If this attribute is not set, patch_cmds will be executed on Windows, which requires | +| Bash binary to exist. | ++--------------------------------+-----------------------------+-----------------------------------+ **Example:** diff --git a/tests/core/go_download_sdk/go_download_sdk_test.go b/tests/core/go_download_sdk/go_download_sdk_test.go index 61bd05b89f..a448231467 100644 --- a/tests/core/go_download_sdk/go_download_sdk_test.go +++ b/tests/core/go_download_sdk/go_download_sdk_test.go @@ -16,7 +16,7 @@ package go_download_sdk_test import ( "bytes" - "io/ioutil" + "os" "testing" "github.com/bazelbuild/rules_go/go/tools/bazel_testing" @@ -25,12 +25,26 @@ import ( func TestMain(m *testing.M) { bazel_testing.TestMain(m, bazel_testing.Args{ Main: ` +-- go.patch -- +--- src/runtime/extern.go 1969-12-31 16:00:00 ++++ src/runtime/extern.go 2000-01-01 00:00:00.000000000 -0000 +@@ -244,7 +244,7 @@ + // It is either the commit hash and date at the time of the build or, + // when possible, a release tag like "go1.3". + func Version() string { +- return sys.TheVersion ++ return "go100.0" + } + + // GOOS is the running program's operating system target: + -- BUILD.bazel -- load("@io_bazel_rules_go//go:def.bzl", "go_test") go_test( name = "version_test", srcs = ["version_test.go"], + pure = "on", ) -- version_test.go -- @@ -59,6 +73,20 @@ func Test(t *testing.T) { optToWantVersion map[string]string fetchOnly string }{ + { + desc: "patch", + rule: ` +load("@io_bazel_rules_go//go:deps.bzl", "go_download_sdk") + +go_download_sdk( + name = "go_sdk_patch", + version = "1.16", + patches = ["//:go.patch"], +) + +`, + optToWantVersion: map[string]string{"": "go100.0"}, + }, { desc: "version", rule: ` @@ -133,7 +161,7 @@ go_download_sdk( }, } { t.Run(test.desc, func(t *testing.T) { - origWorkspaceData, err := ioutil.ReadFile("WORKSPACE") + origWorkspaceData, err := os.ReadFile("WORKSPACE") if err != nil { t.Fatal(err) } @@ -151,11 +179,11 @@ go_rules_dependencies() go_register_toolchains() `) - if err := ioutil.WriteFile("WORKSPACE", buf.Bytes(), 0666); err != nil { + if err := os.WriteFile("WORKSPACE", buf.Bytes(), 0666); err != nil { t.Fatal(err) } defer func() { - if err := ioutil.WriteFile("WORKSPACE", origWorkspaceData, 0666); err != nil { + if err := os.WriteFile("WORKSPACE", origWorkspaceData, 0666); err != nil { t.Errorf("error restoring WORKSPACE: %v", err) } }()