From bdadb2a1879672d993b3469d81b19dc35747d9f5 Mon Sep 17 00:00:00 2001 From: Mike Danese Date: Wed, 9 Sep 2020 17:44:05 -0700 Subject: [PATCH] make kube::util::find-binary not dependent on bazel-out/ structure Implement an aspect that outputs go_build_mode metadata for go binaries, and use that during binary selection. --- build/go.bzl | 64 ++++++++++++++++++++++++++++++++++++++++++++- build/root/.bazelrc | 4 +++ hack/lib/util.sh | 23 +++++++--------- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/build/go.bzl b/build/go.bzl index b7b6bbc798b..d0fe3490bd1 100644 --- a/build/go.bzl +++ b/build/go.bzl @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_test") +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_context", "go_test") +load("@io_bazel_rules_go//go/platform:list.bzl", "GOOS_GOARCH") # Defines a go_binary rule that enables cgo on platform builds targeting Linux, # and otherwise builds a pure go binary. @@ -47,3 +48,64 @@ def go_test_conditional_pure(name, out, tags = [], **kwargs): name = "name", actual = out, ) + +_GO_BUILD_MODE_TMPL = "{goos}/{goarch}/pure={pure},static={static},msan={msan},race={race}\n" + +def _go_build_mode_aspect_impl(target, ctx): + if (not hasattr(ctx.rule.attr, "_is_executable") or + not ctx.rule.attr._is_executable or + ctx.rule.attr.testonly): + # We only care about exporting platform info for executable targets + # that aren't testonly (e.g. kubectl and e2e.test). + return [] + + mode = go_context(ctx).mode + + out = ctx.actions.declare_file( + target.files_to_run.executable.basename + ".go_build_mode", + sibling = target.files_to_run.executable, + ) + ctx.actions.write(out, _GO_BUILD_MODE_TMPL.format( + goos = mode.goos, + goarch = mode.goarch, + pure = str(mode.pure).lower(), + static = str(mode.static).lower(), + msan = str(mode.msan).lower(), + race = str(mode.race).lower(), + )) + + return [OutputGroupInfo(default = depset([out]))] + +# This aspect ouputs a *.go_build_mode metadata for go binaries. This metadata +# is used for executable selection e.g. in CI. +go_build_mode_aspect = aspect( + implementation = _go_build_mode_aspect_impl, + attrs = { + "goos": attr.string( + default = "auto", + values = ["auto"] + {goos: None for goos, _ in GOOS_GOARCH}.keys(), + ), + "goarch": attr.string( + default = "auto", + values = ["auto"] + {goarch: None for _, goarch in GOOS_GOARCH}.keys(), + ), + "pure": attr.string( + default = "auto", + values = ["auto", "on", "off"], + ), + "static": attr.string( + default = "auto", + values = ["auto", "on", "off"], + ), + "msan": attr.string( + default = "auto", + values = ["auto", "on", "off"], + ), + "race": attr.string( + default = "auto", + values = ["auto", "on", "off"], + ), + "_go_context_data": attr.label(default = "@io_bazel_rules_go//:go_context_data"), + }, + toolchains = ["@io_bazel_rules_go//go:toolchain"], +) diff --git a/build/root/.bazelrc b/build/root/.bazelrc index 9c9d6b79a52..d0bcddcd543 100644 --- a/build/root/.bazelrc +++ b/build/root/.bazelrc @@ -22,6 +22,10 @@ build --define gotags=selinux # This flag requires Bazel 0.5.0+ build --sandbox_fake_username +# Output go_build_mode metadata for binaries. This metadata is used for +# executable selection e.g. in CI. +build --aspects //build:go.bzl%go_build_mode_aspect + # Enable go race detection. build:unit --@io_bazel_rules_go//go/config:race test:unit --@io_bazel_rules_go//go/config:race diff --git a/hack/lib/util.sh b/hack/lib/util.sh index dc70ea1f157..ff699da004f 100755 --- a/hack/lib/util.sh +++ b/hack/lib/util.sh @@ -207,19 +207,16 @@ kube::util::find-binary-for-platform() { "${KUBE_ROOT}/_output/dockerized/go/bin/${lookfor}" ); fi - # Also search for binary in bazel build tree. - # The bazel go rules place some binaries in subtrees like - # "bazel-bin/source/path/linux_amd64_pure_stripped/binaryname", so make sure - # the platform name is matched in the path. - while IFS=$'\n' read -r location; do - locations+=("$location"); - done < <(find "${KUBE_ROOT}/bazel-bin/" -type f -executable \ - \( -path "*/${platform/\//_}*/${lookfor}" -o -path "*/${lookfor}" \) 2>/dev/null || true) - # search for executables for non-GNU versions of find (eg. BSD) - while IFS=$'\n' read -r location; do - locations+=("$location"); - done < <(find "${KUBE_ROOT}/bazel-bin/" -type f -perm -111 \ - \( -path "*/${platform/\//_}*/${lookfor}" -o -path "*/${lookfor}" \) 2>/dev/null || true) + + # Also search for binary in bazel build tree if bazel-out/ exists. + if [[ -d "${KUBE_ROOT}/bazel-out" ]]; then + while IFS=$'\n' read -r bin_build_mode; do + if grep -q "${platform}" "${bin_build_mode}"; then + # drop the extension to get the real binary path. + locations+=("${bin_build_mode%.*}") + fi + done < <(find "${KUBE_ROOT}/bazel-out/" -name "${lookfor}.go_build_mode") + fi # List most recently-updated location. local -r bin=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 )