diff --git a/.bazelrc b/.bazelrc index 4827c89..1e8b663 100644 --- a/.bazelrc +++ b/.bazelrc @@ -16,6 +16,8 @@ try-import %workspace%/.aspect/bazelrc/bazel6.bazelrc # For testing our --stamp behavior. # Normally users would use a --workspace_status_command with a script that calls `git describe`. build --embed_label=v1.2.3 +# Mock versioning command to test the --stamp behavior +build --workspace_status_command="echo BUILD_SCM_VERSION 1.2.3" # For releasing, use --workspace_status_command and stamp build:release --workspace_status_command "${PWD}/workspace_status.sh" diff --git a/MODULE.bazel b/MODULE.bazel index 4e5a400..7177319 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -13,12 +13,14 @@ bazel_dep(name = "stardoc", repo_name = "io_bazel_stardoc", version = "0.5.0") ext = use_extension("@aspect_bazel_lib//lib:extensions.bzl", "ext") -use_repo(ext, "copy_directory_toolchains", "copy_to_directory_toolchains", "jq_toolchains", "yq_toolchains", "coreutils_toolchains") +use_repo(ext, "copy_directory_toolchains", "copy_to_directory_toolchains", "jq_toolchains", "yq_toolchains", "coreutils_toolchains", "expand_template_toolchains") + register_toolchains( "@copy_directory_toolchains//:all", "@copy_to_directory_toolchains//:all", "@jq_toolchains//:all", "@yq_toolchains//:all", - "@coreutils_toolchains//:all" + "@coreutils_toolchains//:all", + "@expand_template_toolchains//:all" ) diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index a582123..1c5b824 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -37,6 +37,11 @@ stardoc_with_diff_test( bzl_library_target = "//lib:expand_make_vars", ) +stardoc_with_diff_test( + name = "expand_template", + bzl_library_target = "//lib:expand_template", +) + stardoc_with_diff_test( name = "params_file", bzl_library_target = "//lib:params_file", diff --git a/docs/expand_make_vars.md b/docs/expand_make_vars.md index 5c59b39..21ca544 100644 --- a/docs/expand_make_vars.md +++ b/docs/expand_make_vars.md @@ -7,7 +7,7 @@ Public API for expanding variables ## expand_template
-expand_template(name, data, is_executable, out, substitutions, template) +expand_template(name, data, is_executable, out, stamp, stamp_substitutions, substitutions, template)Template expansion @@ -31,7 +31,9 @@ such as `$(BINDIR)`, `$(TARGET_CPU)`, and `$(COMPILATION_MODE)` as documented in | data | List of targets for additional lookup information. | List of labels | optional | [] | | is_executable | Whether to mark the output file as executable. | Boolean | optional | False | | out | Where to write the expanded file. | Label | required | | -| substitutions | Mapping of strings to substitutions. | Dictionary: String -> String | required | | +| stamp | Whether to encode build information into the output. Possible values:
stamp = 1
: Always stamp the build information into the output, even in [--nostamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) builds. This setting should be avoided, since it is non-deterministic. It potentially causes remote cache misses for the target and any downstream actions that depend on the result. - stamp = 0
: Never stamp, instead replace build information by constant values. This gives good build result caching. - stamp = -1
: Embedding of build information is controlled by the [--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag. Stamped targets are not rebuilt unless their dependencies change. | Integer | optional | -1 |
+| stamp_substitutions | Mapping of strings to substitutions.+expand_template(name, data, is_executable, out, stamp, stamp_substitutions, substitutions, template) ++ +Template expansion + +This performs a simple search over the template file for the keys in substitutions, +and replaces them with the corresponding values. + +Values may also use location templates as documented in +[expand_locations](https://github.com/aspect-build/bazel-lib/blob/main/docs/expand_make_vars.md#expand_locations) +as well as [configuration variables](https://docs.bazel.build/versions/main/skylark/lib/ctx.html#var) +such as `$(BINDIR)`, `$(TARGET_CPU)`, and `$(COMPILATION_MODE)` as documented in +[expand_variables](https://github.com/aspect-build/bazel-lib/blob/main/docs/expand_make_vars.md#expand_variables). + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| data | List of targets for additional lookup information. | List of labels | optional | [] | +| is_executable | Whether to mark the output file as executable. | Boolean | optional | False | +| out | Where to write the expanded file. | Label | required | | +| stamp | Whether to encode build information into the output. Possible values:
stamp = 1
: Always stamp the build information into the output, even in [--nostamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) builds. This setting should be avoided, since it is non-deterministic. It potentially causes remote cache misses for the target and any downstream actions that depend on the result. - stamp = 0
: Never stamp, instead replace build information by constant values. This gives good build result caching. - stamp = -1
: Embedding of build information is controlled by the [--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag. Stamped targets are not rebuilt unless their dependencies change. | Integer | optional | -1 |
+| stamp_substitutions | Mapping of strings to substitutions.True
|
+
+
+## register_expand_template_toolchains
+
++register_expand_template_toolchains(name, register) ++ +Registers expand_template toolchain and repositories + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| name | override the prefix for the generated toolchain repositories |
"expand_template"
|
+| register | whether to call through to native.register_toolchains. Should be True for WORKSPACE users, but false when used under bzlmod extension | True
|
+
+
## register_jq_toolchains
diff --git a/e2e/smoke/.bazelrc b/e2e/smoke/.bazelrc
index 1482aca..94b8d05 100644
--- a/e2e/smoke/.bazelrc
+++ b/e2e/smoke/.bazelrc
@@ -9,9 +9,11 @@ import %workspace%/.aspect/bazelrc/debug.bazelrc
import %workspace%/.aspect/bazelrc/javascript.bazelrc
### PROJECT SPECIFIC OPTIONS ###
+# for testing expand_template
+build --workspace_status_command="echo BUILD_SCM_VERSION 1.2.3"
# Load any settings & overrides specific to the current user from `.aspect/bazelrc/user.bazelrc`.
# This file should appear in `.gitignore` so that settings are not shared with team members. This
# should be last statement in this config so the user configuration is able to overwrite flags from
# this file. See https://bazel.build/configure/best-practices#bazelrc-file.
-try-import %workspace%/.aspect/bazelrc/user.bazelrc
+try-import %workspace%/.aspect/bazelrc/user.bazelrc
\ No newline at end of file
diff --git a/e2e/smoke/BUILD.bazel b/e2e/smoke/BUILD.bazel
index 722df23..e6dd954 100644
--- a/e2e/smoke/BUILD.bazel
+++ b/e2e/smoke/BUILD.bazel
@@ -1,6 +1,7 @@
load("@aspect_bazel_lib//lib:copy_directory.bzl", "copy_directory")
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
load("@aspect_bazel_lib//lib:diff_test.bzl", "diff_test")
+load("@aspect_bazel_lib//lib:expand_make_vars.bzl", "expand_template")
load("@aspect_bazel_lib//lib:jq.bzl", "jq")
load("@aspect_bazel_lib//lib:yq.bzl", "yq")
@@ -61,3 +62,28 @@ diff_test(
# Source directories are not support on remote execution.
tags = ["no-remote-exec"],
)
+
+# Validate that expand_template works and resolves its toolchain
+expand_template(
+ name = "a_tmpl_stamp",
+ out = "a_stamp",
+ data = ["a.tmpl"],
+ stamp = 1,
+ stamp_substitutions = {
+ "{{VERSION}}": "v{{BUILD_SCM_VERSION}}",
+ },
+ substitutions = {
+ "{{VERSION}}": "v0.0.0",
+ "{{WORKSPACE}}": "$(WORKSPACE)",
+ },
+ template = "a.tmpl",
+)
+
+diff_test(
+ name = "a_stamp_test",
+ file1 = ":a_stamp",
+ file2 = select({
+ "@aspect_bazel_lib//lib:bzlmod": "a_stamp_expected_bzlmod",
+ "//conditions:default": "a_stamp_expected",
+ }),
+)
\ No newline at end of file
diff --git a/e2e/smoke/a.tmpl b/e2e/smoke/a.tmpl
new file mode 100644
index 0000000..0bdf04b
--- /dev/null
+++ b/e2e/smoke/a.tmpl
@@ -0,0 +1,4 @@
+WORKSPACE: {{WORKSPACE}}
+VERSION: {{VERSION}}
+WORKSPACE: {{WORKSPACE}}
+VERSION: {{VERSION}}
\ No newline at end of file
diff --git a/e2e/smoke/a_stamp_expected b/e2e/smoke/a_stamp_expected
new file mode 100644
index 0000000..a2200ca
--- /dev/null
+++ b/e2e/smoke/a_stamp_expected
@@ -0,0 +1,4 @@
+WORKSPACE: __main__
+VERSION: v1.2.3
+WORKSPACE: __main__
+VERSION: v1.2.3
\ No newline at end of file
diff --git a/e2e/smoke/a_stamp_expected_bzlmod b/e2e/smoke/a_stamp_expected_bzlmod
new file mode 100644
index 0000000..51188ac
--- /dev/null
+++ b/e2e/smoke/a_stamp_expected_bzlmod
@@ -0,0 +1,4 @@
+WORKSPACE: _main
+VERSION: v1.2.3
+WORKSPACE: _main
+VERSION: v1.2.3
\ No newline at end of file
diff --git a/lib/BUILD.bazel b/lib/BUILD.bazel
index 0515bdd..9220319 100644
--- a/lib/BUILD.bazel
+++ b/lib/BUILD.bazel
@@ -51,6 +51,10 @@ toolchain_type(
name = "coreutils_toolchain_type",
)
+toolchain_type(
+ name = "expand_template_toolchain_type",
+)
+
bzl_library(
name = "docs",
srcs = ["docs.bzl"],
@@ -62,8 +66,19 @@ bzl_library(
srcs = ["expand_make_vars.bzl"],
deps = [
"//lib/private/docs:expand_locations",
- "//lib/private/docs:expand_template",
"//lib/private/docs:expand_variables",
+ ":expand_template",
+ ],
+)
+
+
+bzl_library(
+ name = "expand_template",
+ srcs = ["expand_template.bzl"],
+ deps = [
+ "//lib/private/docs:expand_locations",
+ "//lib/private/docs:expand_variables",
+ "//lib/private/docs:expand_template",
],
)
@@ -216,6 +231,7 @@ bzl_library(
"//lib/private/docs:copy_directory_toolchain",
"//lib/private/docs:copy_to_directory_toolchain",
"//lib/private/docs:coreutils_toolchain",
+ "//lib/private/docs:expand_template_toolchain",
"//lib/private/docs:jq_toolchain",
"//lib/private/docs:local_config_platform",
"//lib/private/docs:yq_toolchain",
diff --git a/lib/expand_make_vars.bzl b/lib/expand_make_vars.bzl
index f219bdc..5a1ca30 100644
--- a/lib/expand_make_vars.bzl
+++ b/lib/expand_make_vars.bzl
@@ -2,8 +2,9 @@
load("//lib/private:expand_locations.bzl", _expand_locations = "expand_locations")
load("//lib/private:expand_variables.bzl", _expand_variables = "expand_variables")
-load("//lib/private:expand_template.bzl", _expand_template = "expand_template")
+load(":expand_template.bzl", _expand_template = "expand_template")
expand_locations = _expand_locations
expand_variables = _expand_variables
+# TODO: 2.0 remove re-export from this file.
expand_template = _expand_template
diff --git a/lib/expand_template.bzl b/lib/expand_template.bzl
new file mode 100644
index 0000000..7a2e64c
--- /dev/null
+++ b/lib/expand_template.bzl
@@ -0,0 +1,5 @@
+"Public API for expand template"
+
+load("//lib/private:expand_template.bzl", _expand_template = "expand_template")
+
+expand_template = _expand_template
\ No newline at end of file
diff --git a/lib/extensions.bzl b/lib/extensions.bzl
index 0282539..380f074 100644
--- a/lib/extensions.bzl
+++ b/lib/extensions.bzl
@@ -6,7 +6,8 @@ load(
"register_copy_to_directory_toolchains",
"register_jq_toolchains",
"register_yq_toolchains",
- "register_coreutils_toolchains"
+ "register_coreutils_toolchains",
+ "register_expand_template_toolchains",
)
load("//lib/private:host_repo.bzl", "host_repo")
@@ -16,7 +17,8 @@ def _toolchain_extension(mctx):
register_jq_toolchains(register = False)
register_yq_toolchains(register = False)
register_coreutils_toolchains(register = False)
-
+ register_expand_template_toolchains(register = False)
+
create_host_repo = False
for module in mctx.modules:
if len(module.tags.host) > 0:
diff --git a/lib/private/docs/BUILD.bazel b/lib/private/docs/BUILD.bazel
index f0b0147..58ca4db 100644
--- a/lib/private/docs/BUILD.bazel
+++ b/lib/private/docs/BUILD.bazel
@@ -102,6 +102,7 @@ bzl_library(
deps = [
":expand_locations",
"@bazel_skylib//lib:dicts",
+ "//lib:stamping"
],
)
@@ -247,6 +248,11 @@ bzl_library(
srcs = ["//lib/private:coreutils_toolchain.bzl"],
)
+bzl_library(
+ name = "expand_template_toolchain",
+ srcs = ["//lib/private:expand_template_toolchain.bzl"],
+ deps = ["//lib:stamping"]
+)
bzl_library(
name = "strings",
diff --git a/lib/private/expand_template.bzl b/lib/private/expand_template.bzl
index 20a0a62..c8fd066 100644
--- a/lib/private/expand_template.bzl
+++ b/lib/private/expand_template.bzl
@@ -1,21 +1,63 @@
"expand_template rule"
-
+load("@bazel_skylib//lib:dicts.bzl", "dicts")
load(":expand_locations.bzl", _expand_locations = "expand_locations")
load(":expand_variables.bzl", _expand_variables = "expand_variables")
+load("//lib:stamping.bzl", "STAMP_ATTRS", "maybe_stamp")
+
+
+def _expand_substitutions(ctx, substitutions):
+ result = {}
+ for k, v in substitutions.items():
+ result[k] = " ".join([
+ _expand_variables(ctx, e, outs = [ctx.outputs.out], attribute_name = "substitutions")
+ for e in _expand_locations(ctx, v, ctx.attr.data).split(" ")
+ ])
+ return result
def _expand_template_impl(ctx):
- template = ctx.file.template
+ substitutions = _expand_substitutions(ctx, ctx.attr.substitutions)
+ expand_template_info = ctx.toolchains["@aspect_bazel_lib//lib:expand_template_toolchain_type"].expand_template_info
+ stamp = maybe_stamp(ctx)
+ if stamp:
+ substitutions = dicts.add(substitutions, _expand_substitutions(ctx, ctx.attr.stamp_substitutions))
+ substitutions_out = ctx.actions.declare_file("{}_substitutions.json".format(ctx.label.name))
+ ctx.actions.write(
+ output = substitutions_out,
+ content = json.encode(substitutions)
+ )
- substitutions = {}
- for k, v in ctx.attr.substitutions.items():
- substitutions[k] = " ".join([_expand_variables(ctx, e, outs = [ctx.outputs.out], attribute_name = "substitutions") for e in _expand_locations(ctx, v, ctx.attr.data).split(" ")])
+ inputs = [
+ ctx.file.template,
+ stamp.volatile_status_file,
+ stamp.stable_status_file,
+ substitutions_out,
+ ]
- ctx.actions.expand_template(
- template = template,
- output = ctx.outputs.out,
- substitutions = substitutions,
- is_executable = ctx.attr.is_executable,
- )
+ args = ctx.actions.args()
+ args.add(ctx.file.template)
+ args.add(ctx.outputs.out)
+ args.add(substitutions_out)
+ args.add(stamp.volatile_status_file)
+ args.add(stamp.stable_status_file)
+ args.add(ctx.attr.is_executable)
+
+ ctx.actions.run(
+ arguments = [args],
+ outputs = [ctx.outputs.out],
+ inputs = inputs,
+ executable = expand_template_info.bin,
+ )
+ else:
+ ctx.actions.expand_template(
+ template = ctx.file.template,
+ output = ctx.outputs.out,
+ substitutions = substitutions,
+ is_executable = ctx.attr.is_executable,
+ )
+
+ all_outs = [ctx.outputs.out]
+ runfiles = ctx.runfiles(files = all_outs)
+ return [DefaultInfo(files = depset(all_outs), runfiles = runfiles)]
expand_template_lib = struct(
doc = """Template expansion
@@ -30,34 +72,49 @@ such as `$(BINDIR)`, `$(TARGET_CPU)`, and `$(COMPILATION_MODE)` as documented in
[expand_variables](https://github.com/aspect-build/bazel-lib/blob/main/docs/expand_make_vars.md#expand_variables).
""",
implementation = _expand_template_impl,
- attrs = {
- "template": attr.label(
- doc = "The template file to expand.",
- mandatory = True,
- allow_single_file = True,
+ toolchains = ["@aspect_bazel_lib//lib:expand_template_toolchain_type"],
+ attrs = dicts.add({
+ "data": attr.label_list(
+ doc = "List of targets for additional lookup information.",
+ allow_files = True,
),
- "substitutions": attr.string_dict(
- doc = "Mapping of strings to substitutions.",
- mandatory = True,
+ "is_executable": attr.bool(
+ doc = "Whether to mark the output file as executable.",
),
"out": attr.output(
doc = "Where to write the expanded file.",
mandatory = True,
),
- "is_executable": attr.bool(
- doc = "Whether to mark the output file as executable.",
- default = False,
- mandatory = False,
+ "stamp_substitutions": attr.string_dict(
+ doc = """Mapping of strings to substitutions.
+
+ There are overlayed on top of substitutions when stamping is enabled
+ for the target.
+
+ Substitutions can contain $(execpath :target) and $(rootpath :target)
+ expansions, $(MAKEVAR) expansions and {{STAMP_VAR}} expansions when
+ stamping is enabled for the target.
+ """,
),
- "data": attr.label_list(
- doc = "List of targets for additional lookup information.",
- allow_files = True,
+ "substitutions": attr.string_dict(
+ doc = """Mapping of strings to substitutions.
+
+ Substitutions can contain $(execpath :target) and $(rootpath :target)
+ expansions, $(MAKEVAR) expansions and {{STAMP_VAR}} expansions when
+ stamping is enabled for the target.
+ """,
),
- },
+ "template": attr.label(
+ doc = "The template file to expand.",
+ mandatory = True,
+ allow_single_file = True,
+ ),
+ }, **STAMP_ATTRS),
)
expand_template = rule(
doc = expand_template_lib.doc,
implementation = expand_template_lib.implementation,
+ toolchains = expand_template_lib.toolchains,
attrs = expand_template_lib.attrs,
)
diff --git a/lib/private/expand_template_toolchain.bzl b/lib/private/expand_template_toolchain.bzl
new file mode 100644
index 0000000..fac9623
--- /dev/null
+++ b/lib/private/expand_template_toolchain.bzl
@@ -0,0 +1,188 @@
+"Setup expand_template toolchain repositories and rules"
+
+# https://github.com/aspect-build/bazel-lib/releases
+#
+# The integrity hashes can be automatically fetched for the latest expand_template release by running
+# `tools/expand_template/mirror_release.sh`. To calculate for a specific release run
+# `tools/expand_template/mirror_release.sh