treewide: replace stampsrcs with embed
A rules_go maintainer suggested using embed instead of stampsrcs:
https://github.com/bazel-contrib/rules_go/issues/3507
For Kubernetes, this means we need to patch the version libraries.
Instead of creating a separate file for each variable, I put them all in
one file, which is parsed in an init function. This init function needs
to run before all other init functions, which access the variables.
Another benefit of this change is that versions are stamped in all
binaries which include Kubernetes client libraries, not just hyperkube.
Change-Id: Ib1157d3686fc35e0c4191d2fc8e165862a1973c7
Reviewed-on: https://review.monogon.dev/c/monogon/+/4208
Tested-by: Jenkins CI
Reviewed-by: Tim Windelschmidt <tim@monogon.tech>
diff --git a/MODULE.bazel b/MODULE.bazel
index b73a8eb..fc9e97f 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -16,7 +16,6 @@
patches = [
"//third_party/rules_go:rules_go_absolute_embedsrc.patch",
"//third_party/rules_go:introduce-all-scope-for-nogo.patch",
- "//third_party/rules_go:stamp-srcs.patch",
],
version = "0.53.0",
)
diff --git a/build/BUILD.bazel b/build/BUILD.bazel
index 3708a0b..9cd94ec 100644
--- a/build/BUILD.bazel
+++ b/build/BUILD.bazel
@@ -1,18 +1,42 @@
-load("//build/filter_stamp:def.bzl", "filtered_stamp")
+load("@aspect_bazel_lib//lib:expand_template.bzl", "expand_template")
-# This is a filtered stable status file which contains only the variables which
-# do not change on every commit. Using this instead of the status file avoids
-# unnecessary rebuilds.
-filtered_stamp(
- name = "stabler_status",
- vars = [
- "KUBERNETES_gitMajor",
- "KUBERNETES_gitMinor",
- "KUBERNETES_gitVersion",
- "KUBERNETES_gitCommit",
- "KUBERNETES_gitTreeState",
- "KUBERNETES_buildDate",
- "MONOGON_copyright",
- ],
+# The copyright and Kubernetes stamp variables change less often than the status
+# file. Instead of stamping these into Go binaries through x_defs, we create a
+# file for each variable and stamp through go:embed. With this indirection, only
+# the expand_template actions are executed each time the status file changes,
+# instead of relinking the Go binaries, which would be more expensive.
+
+expand_template(
+ name = "copyright_line",
+ out = "copyright_line.txt",
+ stamp = 1,
+ stamp_substitutions = {"copyright": "{{STABLE_MONOGON_copyright}}"},
+ template = ["copyright"],
+ visibility = ["//visibility:public"],
+)
+
+kubernetes_vars = [
+ "gitMajor",
+ "gitMinor",
+ "gitVersion",
+ "gitCommit",
+ "gitTreeState",
+ "buildDate",
+]
+
+[
+ expand_template(
+ name = "kubernetes_%s" % var,
+ out = "kubernetes_%s.txt" % var,
+ stamp = 1,
+ stamp_substitutions = {"value": "{{STABLE_KUBERNETES_%s}}" % var},
+ template = ["value"],
+ )
+ for var in kubernetes_vars
+]
+
+filegroup(
+ name = "kubernetes_stamp",
+ srcs = ["kubernetes_%s.txt" % var for var in kubernetes_vars],
visibility = ["//visibility:public"],
)
diff --git a/build/bazel/go.MODULE.bazel b/build/bazel/go.MODULE.bazel
index eb4aea5..d83abc6 100644
--- a/build/bazel/go.MODULE.bazel
+++ b/build/bazel/go.MODULE.bazel
@@ -235,6 +235,9 @@
],
},
"k8s.io/client-go": {
+ "patches": [
+ "//third_party/com_k8s_io_client_go:version-stamp.patch",
+ ],
"pre_patches": [
"//third_party/com_k8s_io_client_go:k8s-fix-websocket-custom-dialer.patch",
],
@@ -369,6 +372,7 @@
"k8s.io/component-base": {
"patches": [
"//third_party/com_k8s_io_component_base:k8s-fix-metrics-data-race.patch",
+ "//third_party/com_k8s_io_component_base:version-stamp.patch",
],
},
"k8s.io/mount-utils": {
diff --git a/build/filter_stamp/BUILD.bazel b/build/filter_stamp/BUILD.bazel
deleted file mode 100644
index 693b12e..0000000
--- a/build/filter_stamp/BUILD.bazel
+++ /dev/null
@@ -1,14 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-
-go_library(
- name = "filter_stamp_lib",
- srcs = ["main.go"],
- importpath = "source.monogon.dev/build/filter_stamp",
- visibility = ["//visibility:private"],
-)
-
-go_binary(
- name = "filter_stamp",
- embed = [":filter_stamp_lib"],
- visibility = ["//visibility:public"],
-)
diff --git a/build/filter_stamp/def.bzl b/build/filter_stamp/def.bzl
deleted file mode 100644
index 650a025..0000000
--- a/build/filter_stamp/def.bzl
+++ /dev/null
@@ -1,32 +0,0 @@
-def _filtered_stamp_impl(ctx):
- output = ctx.actions.declare_file(ctx.label.name + ".txt")
- ctx.actions.run(
- mnemonic = "FilterStamp",
- executable = ctx.executable._filter_stamp,
- arguments = ["-status", ctx.info_file.path, "-out", output.path, "--"] + ctx.attr.vars,
- inputs = [ctx.info_file],
- outputs = [output],
- )
- return [DefaultInfo(files = depset([output]))]
-
-filtered_stamp = rule(
- implementation = _filtered_stamp_impl,
- doc = """
- Build a stamp file with a subset of
- variables from the stable status file.
- """,
- attrs = {
- "vars": attr.string_list(
- doc = """
- List of variables to include in the output.
- """,
- mandatory = True,
- ),
- # Tool
- "_filter_stamp": attr.label(
- default = Label("//build/filter_stamp"),
- executable = True,
- cfg = "exec",
- ),
- },
-)
diff --git a/build/filter_stamp/main.go b/build/filter_stamp/main.go
deleted file mode 100644
index 6b8d561..0000000
--- a/build/filter_stamp/main.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright The Monogon Project Authors.
-// SPDX-License-Identifier: Apache-2.0
-
-package main
-
-import (
- "flag"
- "fmt"
- "log"
- "os"
- "strings"
-)
-
-var (
- statusFile = flag.String("status", "", "Path to bazel workspace status file")
- outFile = flag.String("out", "", "Output stamp file path")
-)
-
-func main() {
- flag.Parse()
-
- vars := make(map[string]bool)
- for _, variable := range flag.Args() {
- vars[variable] = true
- }
-
- statusFileContent, err := os.ReadFile(*statusFile)
- if err != nil {
- log.Fatalf("Failed to open bazel workspace status file: %v\n", err)
- }
-
- var filtered []string
- for line := range strings.SplitSeq(string(statusFileContent), "\n") {
- if line == "" {
- continue
- }
- variable, value, ok := strings.Cut(line, " ")
- if !ok {
- log.Fatalf("Invalid line in status file: %q\n", line)
- }
- variable, ok = strings.CutPrefix(variable, "STABLE_")
- if ok && vars[variable] {
- filtered = append(filtered, fmt.Sprintf("STABLER_%s %s\n", variable, value))
- }
- }
-
- filteredContent := []byte(strings.Join(filtered, ""))
- err = os.WriteFile(*outFile, filteredContent, 0644)
- if err != nil {
- log.Fatalf("Failed to write output file: %v", err)
- }
-}
diff --git a/build/print-workspace-status.py b/build/print-workspace-status.py
index 992a8fc..3b86ee4 100755
--- a/build/print-workspace-status.py
+++ b/build/print-workspace-status.py
@@ -227,6 +227,10 @@
variables["STABLE_KUBERNETES_gitCommit"] = git_commit
variables["STABLE_KUBERNETES_gitTreeState"] = git_tree_state
variables["STABLE_KUBERNETES_buildDate"] = git_commit_date
+else:
+ variables["STABLE_KUBERNETES_gitCommit"] = ""
+ variables["STABLE_KUBERNETES_gitTreeState"] = ""
+ variables["STABLE_KUBERNETES_buildDate"] = "1970-01-01T00:00:00Z"
# Emit variables to stdout for consumption by Bazel and targets.
for key in sorted(variables.keys()):
diff --git a/metropolis/installer/BUILD.bazel b/metropolis/installer/BUILD.bazel
index 0fb1659..d995777 100644
--- a/metropolis/installer/BUILD.bazel
+++ b/metropolis/installer/BUILD.bazel
@@ -7,14 +7,11 @@
name = "installer_lib",
srcs = ["main.go"],
embedsrcs = [
+ "//build:copyright_line.txt", #keep
"//metropolis/node/abloader", #keep
],
importpath = "source.monogon.dev/metropolis/installer",
- stampsrcs = ["//build:stabler_status"],
visibility = ["//visibility:private"],
- x_defs = {
- "copyrightLine": "{STABLER_MONOGON_copyright}",
- },
deps = [
"//osbase/blockdev",
"//osbase/bringup",
diff --git a/metropolis/installer/main.go b/metropolis/installer/main.go
index 3d2df41..baf9cc8 100644
--- a/metropolis/installer/main.go
+++ b/metropolis/installer/main.go
@@ -32,7 +32,7 @@
//go:embed metropolis/node/abloader/abloader_bin.efi
var abloader []byte
-// Filled at linking time.
+//go:embed build/copyright_line.txt
var copyrightLine string
const mib = 1024 * 1024
diff --git a/metropolis/node/core/tconsole/BUILD.bazel b/metropolis/node/core/tconsole/BUILD.bazel
index 2cae5df..f67e9b9 100644
--- a/metropolis/node/core/tconsole/BUILD.bazel
+++ b/metropolis/node/core/tconsole/BUILD.bazel
@@ -10,12 +10,11 @@
"statusbar.go",
"tconsole.go",
],
+ embedsrcs = [
+ "//build:copyright_line.txt", #keep
+ ],
importpath = "source.monogon.dev/metropolis/node/core/tconsole",
- stampsrcs = ["//build:stabler_status"],
visibility = ["//visibility:public"],
- x_defs = {
- "copyrightLine": "{STABLER_MONOGON_copyright}",
- },
deps = [
"//metropolis/node/core/network",
"//metropolis/node/core/roleserve",
diff --git a/metropolis/node/core/tconsole/page_status.go b/metropolis/node/core/tconsole/page_status.go
index 8b08b23..7a139ac 100644
--- a/metropolis/node/core/tconsole/page_status.go
+++ b/metropolis/node/core/tconsole/page_status.go
@@ -4,6 +4,7 @@
package tconsole
import (
+ _ "embed"
"fmt"
"strings"
@@ -13,7 +14,7 @@
"source.monogon.dev/version"
)
-// Filled at linking time.
+//go:embed build/copyright_line.txt
var copyrightLine string
// pageStatusData encompasses all data to be shown within the status page.
diff --git a/metropolis/node/kubernetes/hyperkube/BUILD.bazel b/metropolis/node/kubernetes/hyperkube/BUILD.bazel
index 3930eb8..e87e738 100644
--- a/metropolis/node/kubernetes/hyperkube/BUILD.bazel
+++ b/metropolis/node/kubernetes/hyperkube/BUILD.bazel
@@ -17,24 +17,8 @@
],
)
-stamp_pkgs = [
- "k8s.io/component-base/version",
- "k8s.io/client-go/pkg/version",
-]
-
-stamp_vars = [
- "gitMajor",
- "gitMinor",
- "gitVersion",
- "gitCommit",
- "gitTreeState",
- "buildDate",
-]
-
go_binary(
name = "hyperkube",
embed = [":hyperkube_lib"],
- stampsrcs = ["//build:stabler_status"],
visibility = ["//metropolis/node:__pkg__"],
- x_defs = {"%s.%s" % (pkg, var): "{STABLER_KUBERNETES_%s}" % var for pkg in stamp_pkgs for var in stamp_vars},
)
diff --git a/third_party/com_k8s_io_client_go/version-stamp.patch b/third_party/com_k8s_io_client_go/version-stamp.patch
new file mode 100644
index 0000000..d1dc52d
--- /dev/null
+++ b/third_party/com_k8s_io_client_go/version-stamp.patch
@@ -0,0 +1,56 @@
+diff --git a/pkg/version/BUILD.bazel b/pkg/version/BUILD.bazel
+index a0ab203..1514297 100644
+--- a/pkg/version/BUILD.bazel
++++ b/pkg/version/BUILD.bazel
+@@ -7,6 +7,7 @@ go_library(
+ "doc.go",
+ "version.go",
+ ],
++ embedsrcs = ["@@//build:kubernetes_stamp"],
+ importpath = "k8s.io/client-go/pkg/version",
+ visibility = ["//visibility:public"],
+ deps = ["@io_k8s_apimachinery//pkg/version"],
+diff --git a/pkg/version/base.go b/pkg/version/base.go
+index 676d51d..c76789a 100644
+--- a/pkg/version/base.go
++++ b/pkg/version/base.go
+@@ -16,6 +16,8 @@ limitations under the License.
+
+ package version
+
++import _ "embed"
++
+ // Base version information.
+ //
+ // This is the fallback data used when version information from git is not
+@@ -39,8 +41,10 @@ var (
+ // them irrelevant. (Next we'll take it out, which may muck with
+ // scripts consuming the kubectl version output - but most of
+ // these should be looking at gitVersion already anyways.)
+- gitMajor string = "" // major version, always numeric
+- gitMinor string = "" // minor version, numeric possibly followed by "+"
++ //go:embed build/kubernetes_gitMajor.txt
++ gitMajor string // major version, always numeric
++ //go:embed build/kubernetes_gitMinor.txt
++ gitMinor string // minor version, numeric possibly followed by "+"
+
+ // semantic version, derived by build scripts (see
+ // https://github.com/kubernetes/sig-release/blob/master/release-engineering/versioning.md#kubernetes-release-versioning
+@@ -56,9 +60,13 @@ var (
+ // NOTE: The $Format strings are replaced during 'git archive' thanks to the
+ // companion .gitattributes file containing 'export-subst' in this same
+ // directory. See also https://git-scm.com/docs/gitattributes
+- gitVersion string = "v0.0.0-master+$Format:%H$"
+- gitCommit string = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD)
+- gitTreeState string = "" // state of git tree, either "clean" or "dirty"
++ //go:embed build/kubernetes_gitVersion.txt
++ gitVersion string
++ //go:embed build/kubernetes_gitCommit.txt
++ gitCommit string // sha1 from git, output of $(git rev-parse HEAD)
++ //go:embed build/kubernetes_gitTreeState.txt
++ gitTreeState string // state of git tree, either "clean" or "dirty"
+
+- buildDate string = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
++ //go:embed build/kubernetes_buildDate.txt
++ buildDate string // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
+ )
diff --git a/third_party/com_k8s_io_component_base/version-stamp.patch b/third_party/com_k8s_io_component_base/version-stamp.patch
new file mode 100644
index 0000000..d411f0d
--- /dev/null
+++ b/third_party/com_k8s_io_component_base/version-stamp.patch
@@ -0,0 +1,55 @@
+diff --git a/version/BUILD.bazel b/version/BUILD.bazel
+index d6aeae2..978a9d3 100644
+--- a/version/BUILD.bazel
++++ b/version/BUILD.bazel
+@@ -7,6 +7,7 @@ go_library(
+ "dynamic.go",
+ "version.go",
+ ],
++ embedsrcs = ["@@//build:kubernetes_stamp"],
+ importpath = "k8s.io/component-base/version",
+ visibility = ["//visibility:public"],
+ deps = [
+diff --git a/version/base.go b/version/base.go
+index 4650011..c7250a7 100644
+--- a/version/base.go
++++ b/version/base.go
+@@ -16,6 +16,8 @@ limitations under the License.
+
+ package version
+
++import _ "embed"
++
+ // Base version information.
+ //
+ // This is the fallback data used when version information from git is not
+@@ -39,7 +41,9 @@ var (
+ // them irrelevant. (Next we'll take it out, which may muck with
+ // scripts consuming the kubectl version output - but most of
+ // these should be looking at gitVersion already anyways.)
++ //go:embed build/kubernetes_gitMajor.txt
+ gitMajor string // major version, always numeric
++ //go:embed build/kubernetes_gitMinor.txt
+ gitMinor string // minor version, numeric possibly followed by "+"
+
+ // semantic version, derived by build scripts (see
+@@ -55,11 +59,15 @@ var (
+ // NOTE: The $Format strings are replaced during 'git archive' thanks to the
+ // companion .gitattributes file containing 'export-subst' in this same
+ // directory. See also https://git-scm.com/docs/gitattributes
+- gitVersion = "v0.0.0-master+$Format:%H$"
+- gitCommit = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD)
+- gitTreeState = "" // state of git tree, either "clean" or "dirty"
++ //go:embed build/kubernetes_gitVersion.txt
++ gitVersion string
++ //go:embed build/kubernetes_gitCommit.txt
++ gitCommit string // sha1 from git, output of $(git rev-parse HEAD)
++ //go:embed build/kubernetes_gitTreeState.txt
++ gitTreeState string // state of git tree, either "clean" or "dirty"
+
+- buildDate = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
++ //go:embed build/kubernetes_buildDate.txt
++ buildDate string // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
+ )
+
+ const (
diff --git a/third_party/rules_go/stamp-srcs.patch b/third_party/rules_go/stamp-srcs.patch
deleted file mode 100644
index 0b3c2cd..0000000
--- a/third_party/rules_go/stamp-srcs.patch
+++ /dev/null
@@ -1,167 +0,0 @@
-commit 676d9d220a8a71f207701fc8568078028235aea6
-Author: Jan Schär <jan@monogon.tech>
-Date: Wed Apr 30 09:30:04 2025 +0000
-
- Add stampsrcs attribute
-
- This change adds the stampsrcs attribute, which allows providing a list
- of files containing variable definitions, which are used in addition to
- the stable and volatile status files and have the same format.
-
- See https://github.com/bazel-contrib/rules_go/issues/3507
-
-diff --git a/go/private/actions/archive.bzl b/go/private/actions/archive.bzl
-index 06212139..e89cedd6 100644
---- a/go/private/actions/archive.bzl
-+++ b/go/private/actions/archive.bzl
-@@ -177,6 +177,7 @@ def emit_archive(go, source = None, _recompile_suffix = "", recompile_internal_d
- _cover = source.cover,
- _embedsrcs = tuple(source.embedsrcs),
- _x_defs = tuple(source.x_defs.items()),
-+ _stampsrcs = tuple(source.stampsrcs),
- _gc_goopts = tuple(source.gc_goopts),
- _cgo = source.cgo,
- _cdeps = tuple(source.cdeps),
-@@ -198,8 +199,10 @@ def emit_archive(go, source = None, _recompile_suffix = "", recompile_internal_d
- _cgo_deps = cgo_deps,
- )
- x_defs = dict(source.x_defs)
-+ stampsrcs = source.stampsrcs
- for a in direct:
- x_defs.update(a.x_defs)
-+ stampsrcs = stampsrcs + a.stampsrcs
-
- # Ensure that the _cgo_export.h of the current target comes first when cgo_exports is iterated
- # by prepending it and specifying the order explicitly. This is required as the CcInfo attached
-@@ -213,6 +216,7 @@ def emit_archive(go, source = None, _recompile_suffix = "", recompile_internal_d
- libs = depset(direct = [out_lib], transitive = [a.libs for a in direct]),
- transitive = depset([data], transitive = [a.transitive for a in direct]),
- x_defs = x_defs,
-+ stampsrcs = stampsrcs,
- cgo_deps = depset(transitive = [cgo_deps] + [a.cgo_deps for a in direct]),
- cgo_exports = cgo_exports,
- runfiles = runfiles,
-diff --git a/go/private/actions/link.bzl b/go/private/actions/link.bzl
-index 18dd1f94..3b236f06 100644
---- a/go/private/actions/link.bzl
-+++ b/go/private/actions/link.bzl
-@@ -161,6 +161,7 @@ def emit_link(
- stamp_inputs.append(info_file)
- if stamp_x_defs_volatile:
- stamp_inputs.append(version_file)
-+ stamp_inputs = stamp_inputs + archive.stampsrcs
- if stamp_inputs:
- builder_args.add_all(stamp_inputs, before_each = "-stamp")
-
-diff --git a/go/private/context.bzl b/go/private/context.bzl
-index f5cd735d..42c5cf13 100644
---- a/go/private/context.bzl
-+++ b/go/private/context.bzl
-@@ -202,6 +202,7 @@ def _merge_embed(source, embed):
- source["cover"] = depset(transitive = [source["cover"], s.cover])
- source["deps"] = source["deps"] + s.deps
- source["x_defs"].update(s.x_defs)
-+ source["stampsrcs"] = source["stampsrcs"] + s.stampsrcs
- source["gc_goopts"] = source["gc_goopts"] + s.gc_goopts
- source["runfiles"] = source["runfiles"].merge(s.runfiles)
-
-@@ -319,6 +320,7 @@ def new_go_info(
- "embedsrcs": embedsrcs,
- "cover": depset(attr_srcs) if coverage_instrumented else depset(),
- "x_defs": {},
-+ "stampsrcs": [],
- "deps": deps,
- "gc_goopts": _expand_opts(go, "gc_goopts", getattr(attr, "gc_goopts", [])),
- "runfiles": _collect_runfiles(go, getattr(attr, "data", []), deps),
-@@ -344,6 +346,8 @@ def new_go_info(
- k = "{}.{}".format(importmap, k)
- x_defs[k] = v
- go_info["x_defs"] = x_defs
-+ for t in getattr(attr, "stampsrcs", []):
-+ go_info["stampsrcs"] = go_info["stampsrcs"] + t[DefaultInfo].files.to_list()
- if not go_info["cgo"]:
- for k in ("cdeps", "cppopts", "copts", "cxxopts", "clinkopts"):
- if getattr(attr, k, None):
-diff --git a/go/private/rules/binary.bzl b/go/private/rules/binary.bzl
-index f3f2f07c..eac3a978 100644
---- a/go/private/rules/binary.bzl
-+++ b/go/private/rules/binary.bzl
-@@ -302,6 +302,12 @@ def _go_binary_kwargs(go_cc_aspects = []):
- See [Defines and stamping] for examples of how to use these.
- """,
- ),
-+ "stampsrcs": attr.label_list(
-+ allow_files = True,
-+ doc = """Additional files containing variables which can be referenced in `x_defs`.
-+ The format of these files should be the same as the workspace status.
-+ """,
-+ ),
- "basename": attr.string(
- doc = """The basename of this binary. The binary
- basename may also be platform-dependent: on Windows, we add an .exe extension.
-diff --git a/go/private/rules/library.bzl b/go/private/rules/library.bzl
-index 8aa020d6..fe944d3a 100644
---- a/go/private/rules/library.bzl
-+++ b/go/private/rules/library.bzl
-@@ -147,6 +147,12 @@ go_library = rule(
- Map of defines to add to the go link command. See [Defines and stamping] for examples of how to use these.
- """,
- ),
-+ "stampsrcs": attr.label_list(
-+ allow_files = True,
-+ doc = """Additional files containing variables which can be referenced in `x_defs`.
-+ The format of these files should be the same as the workspace status.
-+ """,
-+ ),
- "cgo": attr.bool(
- doc = """
- If `True`, the package may contain [cgo] code, and `srcs` may contain C, C++, Objective-C, and Objective-C++ files
-diff --git a/go/private/rules/test.bzl b/go/private/rules/test.bzl
-index 4859c53e..da46ead9 100644
---- a/go/private/rules/test.bzl
-+++ b/go/private/rules/test.bzl
-@@ -93,6 +93,7 @@ def _go_test_impl(ctx):
- embedsrcs = [struct(files = internal_go_info.embedsrcs)],
- deps = internal_archive.direct + [internal_archive],
- x_defs = ctx.attr.x_defs,
-+ stampsrcs = ctx.attr.stampsrcs,
- ),
- name = internal_go_info.name + "_test",
- importpath = internal_go_info.importpath + "_test",
-@@ -326,6 +327,12 @@ _go_test_kwargs = {
- See [Defines and stamping] for examples of how to use these.
- """,
- ),
-+ "stampsrcs": attr.label_list(
-+ allow_files = True,
-+ doc = """Additional files containing variables which can be referenced in `x_defs`.
-+ The format of these files should be the same as the workspace status.
-+ """,
-+ ),
- "linkmode": attr.string(
- default = "auto",
- values = ["auto"] + LINKMODES,
-@@ -661,6 +668,7 @@ def _recompile_external_deps(go, external_go_info, internal_archive, library_lab
- attrs = structs.to_dict(internal_go_info)
- attrs["deps"] = internal_deps
- attrs["x_defs"] = x_defs
-+ attrs["stampsrcs"] = internal_go_info.stampsrcs + internal_archive.stampsrcs
- internal_go_info = GoInfo(**attrs)
- internal_archive = go.archive(go, internal_go_info, _recompile_suffix = ".recompileinternal", recompile_internal_deps = need_recompile_deps)
-
-@@ -698,6 +706,7 @@ def _recompile_external_deps(go, external_go_info, internal_archive, library_lab
- cover = arc_data._cover,
- embedsrcs = as_list(arc_data._embedsrcs),
- x_defs = dict(arc_data._x_defs),
-+ stampsrcs = as_list(arc_data._stampsrcs),
- deps = deps,
- gc_goopts = as_list(arc_data._gc_goopts),
- runfiles = arc_data.runfiles,
-@@ -722,6 +731,7 @@ def _recompile_external_deps(go, external_go_info, internal_archive, library_lab
- libs = depset(direct = [arc_data.file], transitive = [a.libs for a in deps]),
- transitive = depset(direct = [arc_data], transitive = [a.transitive for a in deps]),
- x_defs = go_info.x_defs,
-+ stampsrcs = go_info.stampsrcs,
- cgo_deps = depset(transitive = [arc_data._cgo_deps] + [a.cgo_deps for a in deps]),
- cgo_exports = depset(transitive = [a.cgo_exports for a in deps]),
- runfiles = go_info.runfiles,