Skip to content

Commit

Permalink
Add support for location expansion in args (#100)
Browse files Browse the repository at this point in the history
See the long comment in `args.bzl` for an explanation of why this is so
complicated.

Fixes #82
  • Loading branch information
fmeum authored Jul 22, 2024
1 parent 44e4833 commit d7193de
Show file tree
Hide file tree
Showing 15 changed files with 436 additions and 29 deletions.
2 changes: 1 addition & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ bazel_dep(name = "bazel_skylib", version = "1.4.1")

bazel_dep(name = "aspect_bazel_lib", version = "1.34.0", dev_dependency = True)
bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.4.1", dev_dependency = True)
bazel_dep(name = "buildifier_prebuilt", version = "6.1.0", dev_dependency = True)
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
bazel_dep(name = "gazelle", version = "0.33.0", dev_dependency = True, repo_name = "bazel_gazelle")
bazel_dep(name = "platforms", version = "0.0.6", dev_dependency = True)
bazel_dep(name = "rules_testing", version = "0.4.0", dev_dependency = True)
Expand Down
1 change: 1 addition & 0 deletions examples/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ local_path_override(
path = "..",
)

bazel_dep(name = "bazel_skylib", version = "1.6.1")
bazel_dep(name = "contrib_rules_jvm", version = "0.27.0")
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_cc", version = "0.0.9")
Expand Down
58 changes: 58 additions & 0 deletions examples/args_location_expansion/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
load("//args_location_expansion/rules:defs.bzl", "write_settings_rule")
load(":doubly_transitioned_test.bzl", "doubly_transitioned_test")

write_settings_rule(
name = "single_rule",
tags = ["manual"],
)

alias(
name = "alias_target",
actual = "//args_location_expansion/pkg:aliased_rule",
tags = ["manual"],
)

doubly_transitioned_test(
name = "doubly_transitioned_test",
args = [
"$(rlocationpath :source_file.txt)",
"$(rlocationpath :single_rule)",
"$(rlocationpaths //args_location_expansion/pkg:multiple_rules)",
"$(rlocationpath alias_target)",
"$(rlocationpath :alias_target)",
"$(rlocationpath @bazel_tools//tools/bash/runfiles)",
"_main/$(rootpath :single_rule)",
"_main/$(location :single_rule)",
] + select({
"@platforms//os:linux": ["$(rlocationpath //args_location_expansion/pkg:linux_only_rule)"],
"//conditions:default": ["$(rlocationpath //args_location_expansion/pkg:generic_rule)"],
}) + select({
"@platforms//os:windows": [],
"//conditions:default": ["$(rlocationpath //args_location_expansion/pkg:special_09!%-@^_\"#$&'(*-+,;<=>?[]{|}~/._characters_rule)"],
}),
binary = ":test_bin",
data = [
":alias_target",
":single_rule",
":source_file.txt",
"//args_location_expansion/pkg:multiple_rules",
"@bazel_tools//tools/bash/runfiles",
] + select({
"@platforms//os:linux": ["//args_location_expansion/pkg:linux_only_rule"],
"//conditions:default": ["//args_location_expansion/pkg:generic_rule"],
}) + select({
"@platforms//os:windows": [],
"//conditions:default": ["//args_location_expansion/pkg:special_09!%-@^_\"#$&'(*-+,;<=>?[]{|}~/._characters_rule"],
}),
env = select({
"@platforms//os:windows": {"NUM_RUNFILES": "10"},
"//conditions:default": {"NUM_RUNFILES": "11"},
}),
)

sh_binary(
name = "test_bin",
srcs = ["test_bin.sh"],
data = ["@bazel_tools//tools/bash/runfiles"],
visibility = ["//visibility:public"],
)
6 changes: 6 additions & 0 deletions examples/args_location_expansion/doubly_transitioned_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
load("@with_cfg.bzl", "with_cfg")
load("//args_location_expansion/rules:defs.bzl", "transitioned_test")

_builder = with_cfg(transitioned_test)
_builder.set(Label("//args_location_expansion/rules:with_cfg_setting"), "with_cfg")
doubly_transitioned_test, _doubly_transitioned_test_ = _builder.build()
46 changes: 46 additions & 0 deletions examples/args_location_expansion/pkg/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
load("//args_location_expansion/rules:defs.bzl", "write_settings_rule")

write_settings_rule(
name = "some_rule",
tags = ["manual"],
)

write_settings_rule(
name = "other_rule",
tags = ["manual"],
)

filegroup(
name = "multiple_rules",
srcs = [
":other_rule",
":some_rule",
],
tags = ["manual"],
visibility = ["//visibility:public"],
)

write_settings_rule(
name = "aliased_rule",
tags = ["manual"],
visibility = ["//visibility:public"],
)

write_settings_rule(
# Omits ')' as it doesn't seem to be supported with location expansion.
name = "special_09!%-@^_\"#$&'(*-+,;<=>?[]{|}~/._characters_rule",
tags = ["manual"],
visibility = ["//visibility:public"],
)

write_settings_rule(
name = "linux_only_rule",
tags = ["manual"],
visibility = ["//visibility:public"],
)

write_settings_rule(
name = "generic_rule",
tags = ["manual"],
visibility = ["//visibility:public"],
)
13 changes: 13 additions & 0 deletions examples/args_location_expansion/rules/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
load("@bazel_skylib//rules:common_settings.bzl", "string_setting")

string_setting(
name = "rule_setting",
build_setting_default = "unset",
visibility = ["//visibility:public"],
)

string_setting(
name = "with_cfg_setting",
build_setting_default = "unset",
visibility = ["//visibility:public"],
)
71 changes: 71 additions & 0 deletions examples/args_location_expansion/rules/defs.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")

def _write_settings_rule_impl(ctx):
# type: (ctx) -> None
rule_setting = ctx.attr._rule_setting[BuildSettingInfo].value
if rule_setting == "unset":
fail("rule_setting is unset")
with_cfg_setting = ctx.attr._with_cfg_setting[BuildSettingInfo].value
if with_cfg_setting == "unset":
fail("with_cfg_setting is unset")

out = ctx.actions.declare_file(ctx.label.name + "_" + rule_setting[0] + "_" + with_cfg_setting[0])
ctx.actions.write(out, "name:{},rule_setting:{},with_cfg_setting:{}\n".format(out.basename, rule_setting, with_cfg_setting))
return [DefaultInfo(files = depset([out]))]

write_settings_rule = rule(
implementation = _write_settings_rule_impl,
attrs = {
"_rule_setting": attr.label(default = ":rule_setting"),
"_with_cfg_setting": attr.label(default = ":with_cfg_setting"),
},
)

def _data_transition_impl(_settings, _attr):
return {
"//args_location_expansion/rules:rule_setting": "rule",
}

_data_transition = transition(
implementation = _data_transition_impl,
inputs = ["//args_location_expansion/rules:rule_setting"],
outputs = ["//args_location_expansion/rules:rule_setting"],
)

def _transitioned_test_impl(ctx):
# type: (ctx) -> None
executable = ctx.actions.declare_file(ctx.label.name)
ctx.actions.symlink(output = executable, target_file = ctx.executable.binary)
runfiles = ctx.runfiles()
runfiles = runfiles.merge(ctx.attr.binary[DefaultInfo].default_runfiles)
for target in ctx.attr.data:
runfiles = runfiles.merge(ctx.runfiles(transitive_files = target[DefaultInfo].files))
runfiles = runfiles.merge(target[DefaultInfo].data_runfiles)
return [
DefaultInfo(
executable = executable,
runfiles = runfiles,
),
RunEnvironmentInfo(
environment = ctx.attr.env,
),
]

transitioned_test = rule(
implementation = _transitioned_test_impl,
attrs = {
"binary": attr.label(
cfg = "target",
executable = True,
),
"data": attr.label_list(
cfg = _data_transition,
allow_files = True,
),
"env": attr.string_dict(),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
test = True,
)
1 change: 1 addition & 0 deletions examples/args_location_expansion/source_file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name:source_file.txt,rule_setting:rule,with_cfg_setting:with_cfg
31 changes: 31 additions & 0 deletions examples/args_location_expansion/test_bin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash

# --- begin runfiles.bash initialization v3 ---
# Copy-pasted from the Bazel Bash runfiles library v3.
set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash
# shellcheck disable=SC1090
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
source "$0.runfiles/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
# --- end runfiles.bash initialization v3 ---

function check_runfile() {
real_path=$(rlocation "$1" || { >&2 echo "$1 not found"; exit 1; })
basename=$(basename "$1")
want="name:$basename,rule_setting:rule,with_cfg_setting:with_cfg"
if [[ $1 != bazel_tools/* && "$(cat "$real_path")" != "$want" ]]; then
echo "Runfile content mismatch in $1: got '$(cat "$real_path")', want '$want'"
exit 1
fi
}

if [ "$#" -ne "$NUM_RUNFILES" ]; then
echo "Unexpected number of arguments: $#, want $NUM_RUNFILES"
exit 1
fi
for arg in "$@"; do
check_runfile "$arg"
done
10 changes: 10 additions & 0 deletions with_cfg/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ config_setting(
},
)

bzl_library(
name = "args",
srcs = ["args.bzl"],
visibility = ["//with_cfg:__subpackages__"],
deps = [
":rewrite",
],
)

bzl_library(
name = "builder",
srcs = ["builder.bzl"],
Expand Down Expand Up @@ -136,6 +145,7 @@ bzl_library(
srcs = ["wrapper.bzl"],
visibility = ["//with_cfg:__subpackages__"],
deps = [
":args",
":rewrite",
":select",
":setting",
Expand Down
Loading

0 comments on commit d7193de

Please sign in to comment.