Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions go/private/context.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,8 @@ def go_context(
importpath_aliases = None,
go_context_data = None,
goos = "auto",
goarch = "auto"):
goarch = "auto",
impure_env = None):
"""Returns an API used to build Go code.

See /go/toolchains.rst#go-context
Expand Down Expand Up @@ -548,10 +549,15 @@ def go_context(
# reparse points (junctions) as symbolic links. Bazel uses junctions
# when constructing exec roots, and we use filepath.EvalSymlinks in
# GoStdlib, so this broke us. Setting GODEBUG=winsymlink=0 restores
# the old behavior.
# the old behavior. (Ideally this would only be set on Windows)
"GODEBUG": "winsymlink=0",
}

if impure_env:
env.update(impure_env)
elif hasattr(attr, "impure_env"):
env.update(attr.impure_env)

# The level of support is determined by the platform constraints in
# //go/constraints/amd64.
# See https://go.dev/wiki/MinimumRequirements#amd64
Expand Down
19 changes: 19 additions & 0 deletions go/private/rules/binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ def _go_binary_impl(ctx):
go_context_data = ctx.attr._go_context_data[0],
goos = ctx.attr.goos,
goarch = ctx.attr.goarch,
impure_env = ctx.attr.impure_env,
)

is_main = go.mode.linkmode not in (LINKMODE_SHARED, LINKMODE_PLUGIN)
Expand Down Expand Up @@ -168,6 +169,10 @@ def _go_binary_impl(ctx):
env = {}
for k, v in ctx.attr.env.items():
env[k] = ctx.expand_location(v, ctx.attr.data)

if hasattr(ctx.attr, "impure_env"):
env.update(ctx.attr.impure_env)

providers.append(RunEnvironmentInfo(environment = env))

# The executable is automatically added to the runfiles.
Expand Down Expand Up @@ -281,6 +286,20 @@ def _go_binary_kwargs(go_cc_aspects = []):
[make variable expansion](https://docs.bazel.build/versions/main/be/make-variables.html).
""",
),
"impure_env": attr.string_dict(
doc = """
A dictionary of environment variables to set during the build.
These variables will override any existing environment variables.
This is useful for setting variables like LD_LIBRARY_PATH that are needed
during the build process but should not be inherited from the host environment.

WARNING: This attribute should be used with caution. Setting environment variables
can make builds non-hermetic and potentially non-reproducible. Only use this if you
understand the implications and have a specific need that cannot be solved through
other means. This is particularly important for shared libraries and other external
dependencies that might affect build reproducibility.
""",
),
"importpath": attr.string(
doc = """The import path of this binary. Binaries can't actually be imported, but this
may be used by [go_path] and other tools to report the location of source
Expand Down
26 changes: 26 additions & 0 deletions go/private/rules/library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def _go_library_impl(ctx):
importpath_aliases = ctx.attr.importpath_aliases,
embed = ctx.attr.embed,
go_context_data = ctx.attr._go_context_data,
impure_env = ctx.attr.impure_env,
)

go_info = new_go_info(go, ctx.attr)
Expand Down Expand Up @@ -187,6 +188,31 @@ go_library = rule(
Subject to ["Make variable"] substitution and [Bourne shell tokenization]. Only valid if `cgo = True`.
""",
),
"env_inherit": attr.string_list(
doc = """Environment variables to inherit from the external environment.
""",
),
"env": attr.string_dict(
doc = """Environment variables to set for the binary execution.
The values (but not keys) are subject to
[location expansion](https://docs.bazel.build/versions/main/skylark/macros.html) but not full
[make variable expansion](https://docs.bazel.build/versions/main/be/make-variables.html).
""",
),
"impure_env": attr.string_dict(
doc = """
A dictionary of environment variables to set during the build.
These variables will override any existing environment variables.
This is useful for setting variables like LD_LIBRARY_PATH that are needed
during the build process but should not be inherited from the host environment.

WARNING: This attribute should be used with caution. Setting environment variables
can make builds non-hermetic and potentially non-reproducible. Only use this if you
understand the implications and have a specific need that cannot be solved through
other means. This is particularly important for shared libraries and other external
dependencies that might affect build reproducibility.
""",
),
"_go_context_data": attr.label(default = "//:go_context_data"),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
Expand Down
12 changes: 12 additions & 0 deletions go/private/rules/test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,13 @@ def _go_test_impl(ctx):
# to run_dir configured above.
"GO_TEST_RUN_FROM_BAZEL": "1",
}

for k, v in ctx.attr.env.items():
env[k] = ctx.expand_location(v, ctx.attr.data)

if hasattr(ctx.attr, "impure_env"):
env.update(ctx.attr.impure_env)

run_environment_info = RunEnvironmentInfo(env, ctx.attr.env_inherit)

# Bazel only looks for coverage data if the test target has an
Expand Down Expand Up @@ -291,6 +295,14 @@ _go_test_kwargs = {
doc = """Environment variables to inherit from the external environment.
""",
),
"impure_env": attr.string_dict(
doc = """
A dictionary of environment variables to set during the build and test execution.
These variables will override any existing environment variables.
WARNING: This attribute is impure and may cause non-hermetic builds.
Use with caution and only when absolutely necessary.
""",
),
"importpath": attr.string(
doc = """The import path of this test. Tests can't actually be imported, but this
may be used by [go_path] and other tools to report the location of source
Expand Down
51 changes: 51 additions & 0 deletions tests/core/impure_env/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# To run the tests:
# bazelisk test //tests/core/impure_env/...

load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
load(
"@bazel_skylib//lib:structs.bzl",
"structs",
)
load(
"//go/private:common.bzl",
"GO_TOOLCHAIN",
"GO_TOOLCHAIN_LABEL",
"SUPPORTS_PATH_MAPPING_REQUIREMENT",
"as_list",
"asm_exts",
"cgo_exts",
"go_exts",
"syso_exts",
)

go_library(
name = "impure_env_lib",
srcs = ["lib.go"],
importpath = "github.com/bazelbuild/rules_go/tests/core/impure_env",
)

go_test(
name = "impure_env_test",
srcs = ["test.go"],
deps = [":impure_env_lib"],
impure_env = {
"TEST_VAR": "test_value",
},
)

go_test(
name = "impure_env_test_no_env",
srcs = ["test_no_env.go"],
deps = [":impure_env_lib"],
)

go_test(
name = "impure_env_test_multiple",
srcs = ["test_multiple_env.go"],
deps = [":impure_env_lib"],
impure_env = {
"TEST_VAR1": "value1",
"TEST_VAR2": "value2",
"TEST_VAR3": "value3",
},
)
17 changes: 17 additions & 0 deletions tests/core/impure_env/lib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package impure_env

import "os"

// GetTestVar returns the value of TEST_VAR environment variable
func GetTestVar() string {
return os.Getenv("TEST_VAR")
}

// GetMultipleVars returns a map of multiple environment variables
func GetMultipleVars() map[string]string {
return map[string]string{
"TEST_VAR1": os.Getenv("TEST_VAR1"),
"TEST_VAR2": os.Getenv("TEST_VAR2"),
"TEST_VAR3": os.Getenv("TEST_VAR3"),
}
}
14 changes: 14 additions & 0 deletions tests/core/impure_env/test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package impure_env_test

import (
"testing"

"github.com/bazelbuild/rules_go/tests/core/impure_env"
)

func TestEnvironmentWithImpureEnv(t *testing.T) {
got := impure_env.GetTestVar()
if got != "test_value" {
t.Errorf("GetTestVar() = %q; want %q", got, "test_value")
}
}
22 changes: 22 additions & 0 deletions tests/core/impure_env/test_multiple_env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package impure_env_test

import (
"testing"

"github.com/bazelbuild/rules_go/tests/core/impure_env"
)

func TestMultipleEnvironmentVars(t *testing.T) {
got := impure_env.GetMultipleVars()
want := map[string]string{
"TEST_VAR1": "value1",
"TEST_VAR2": "value2",
"TEST_VAR3": "value3",
}

for k, v := range want {
if got[k] != v {
t.Errorf("GetMultipleVars()[%q] = %q; want %q", k, got[k], v)
}
}
}
14 changes: 14 additions & 0 deletions tests/core/impure_env/test_no_env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package impure_env_test

import (
"testing"

"github.com/bazelbuild/rules_go/tests/core/impure_env"
)

func TestEnvironmentWithoutImpureEnv(t *testing.T) {
got := impure_env.GetTestVar()
if got != "" {
t.Errorf("GetTestVar() = %q; want %q", got, "")
}
}