From a1862e131c4a7ae315dad0c52fa6b4c8fa586e50 Mon Sep 17 00:00:00 2001 From: Dj Date: Wed, 8 Apr 2026 10:42:15 -0700 Subject: [PATCH] feat: add node_data attribute to nodejs_toolchain The node_data attribute allows for additional runtime files to be provided with the node binary. --- e2e/smoke/BUILD.bazel | 55 ++++++++++++++++++++++++++++++++++++++++++- e2e/smoke/defs.bzl | 37 ++++++++++++++++++++++++++++- nodejs/toolchain.bzl | 10 +++++++- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/e2e/smoke/BUILD.bazel b/e2e/smoke/BUILD.bazel index 27fc5f531b..9fcbf0c54d 100644 --- a/e2e/smoke/BUILD.bazel +++ b/e2e/smoke/BUILD.bazel @@ -1,7 +1,8 @@ load("@bazel_skylib//rules:build_test.bzl", "build_test") load("@bazel_skylib//rules:diff_test.bzl", "diff_test") load("@bazel_skylib//rules:write_file.bzl", "write_file") -load(":defs.bzl", "my_nodejs") +load("@rules_nodejs//nodejs:toolchain.bzl", "nodejs_toolchain") +load(":defs.bzl", "check_node_data", "my_nodejs") not_windows = select({ # There isn't a published rosetta binary for windows as of Feb 2024 @@ -339,3 +340,55 @@ diff_test( file1 = "write_node_version_24", file2 = "thing_toolchain_24", ) + +################################################ +# Test that node_data files are available in the sandbox + +write_file( + name = "write_companion", + out = "companion.txt", + content = ["companion_data"], +) + +# checks that each path in argv[2..] exists, writes "found" or "not_found" +write_file( + name = "write_check_node_data", + out = "check_node_data.js", + content = [ + "const fs = require('fs');", + "const paths = process.argv.slice(3);", + "const allExist = paths.every(p => fs.existsSync(p));", + "fs.writeFileSync(process.argv[2], allExist ? 'found' : 'not_found');", + ], +) + +write_file( + name = "write_expected_found", + out = "expected_found", + content = ["found"], +) + +nodejs_toolchain( + name = "node_with_data_impl", + node = select({ + "@bazel_tools//src/conditions:linux_x86_64": "@nodejs_linux_amd64//:node_bin", + "@bazel_tools//src/conditions:linux_aarch64": "@nodejs_linux_arm64//:node_bin", + "@bazel_tools//src/conditions:darwin_x86_64": "@nodejs_darwin_amd64//:node_bin", + "@bazel_tools//src/conditions:darwin_arm64": "@nodejs_darwin_arm64//:node_bin", + "@bazel_tools//src/conditions:windows": "@nodejs_windows_amd64//:node_bin", + }), + node_data = [":companion.txt"], +) + +check_node_data( + name = "run_node_data", + out = "node_data_result", + entry_point = "check_node_data.js", + toolchain = ":node_with_data_impl", +) + +diff_test( + name = "test_node_data", + file1 = "expected_found", + file2 = "node_data_result", +) diff --git a/e2e/smoke/defs.bzl b/e2e/smoke/defs.bzl index c17f6197b2..4adc4222be 100644 --- a/e2e/smoke/defs.bzl +++ b/e2e/smoke/defs.bzl @@ -5,8 +5,14 @@ def _my_nodejs_impl(ctx): nodeinfo = ctx.attr.toolchain[platform_common.ToolchainInfo].nodeinfo else: nodeinfo = ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo + + inputs = depset( + [ctx.file.entry_point], + transitive = [nodeinfo.node_data] if hasattr(nodeinfo, "node_data") else None, + ) + ctx.actions.run( - inputs = [ctx.file.entry_point], + inputs = inputs, executable = nodeinfo.node, arguments = [ctx.file.entry_point.path, ctx.outputs.out.path], outputs = [ctx.outputs.out], @@ -22,3 +28,32 @@ my_nodejs = rule( }, toolchains = ["@rules_nodejs//nodejs:toolchain_type"], ) + +def _check_node_data_impl(ctx): + """Test rule that verifies node_data files are present in the action sandbox.""" + nodeinfo = ctx.attr.toolchain[platform_common.ToolchainInfo].nodeinfo + + node_data = nodeinfo.node_data if hasattr(nodeinfo, "node_data") else depset() + node_data_list = node_data.to_list() + if not node_data_list: + fail("Expected node_data to contain files") + + # Pass each node_data file path as an arg so the JS script can check existence + args = [ctx.file.entry_point.path, ctx.outputs.out.path] + [f.path for f in node_data_list] + + ctx.actions.run( + inputs = depset([ctx.file.entry_point], transitive = [node_data]), + executable = nodeinfo.node, + arguments = args, + outputs = [ctx.outputs.out], + ) + return [] + +check_node_data = rule( + implementation = _check_node_data_impl, + attrs = { + "entry_point": attr.label(allow_single_file = True), + "out": attr.output(), + "toolchain": attr.label(mandatory = True), + }, +) diff --git a/nodejs/toolchain.bzl b/nodejs/toolchain.bzl index 8f3721bc13..f00e865e27 100644 --- a/nodejs/toolchain.bzl +++ b/nodejs/toolchain.bzl @@ -34,6 +34,7 @@ For backward compability, if set then npm_path will be set to the runfiles path For backward compability, npm_path is set to the runfiles path of npm if npm is set. """, + "node_data": """Additional runtime files required by the Node.js executable (depset of Files).""", "npm_sources": """Additional source files required to run npm""", "headers": """Optional.\ @@ -86,14 +87,16 @@ def _nodejs_toolchain_impl(ctx): "NPM_PATH": ctx.file.npm.path if ctx.attr.npm else ctx.attr.npm_path, }) files = [f for f in [ctx.file.node, ctx.file.npm] if f] + node_data = depset(ctx.files.node_data) default = DefaultInfo( files = depset(files), - runfiles = ctx.runfiles(files = files), + runfiles = ctx.runfiles(files = files, transitive_files = node_data), ) npm_sources = depset([ctx.file.npm] + ctx.files.npm_srcs) nodeinfo = NodeInfo( node = ctx.file.node, node_path = ctx.attr.node_path, + node_data = node_data, npm = ctx.file.npm, npm_path = ctx.attr.npm_path if ctx.attr.npm_path else (_to_manifest_path(ctx, ctx.file.npm) if ctx.file.npm else ""), # _to_manifest_path for backward compat npm_sources = npm_sources, @@ -131,6 +134,7 @@ _nodejs_toolchain = rule( allow_single_file = True, ), "node_path": attr.string(), + "node_data": attr.label_list(allow_files = True), "npm": attr.label(allow_single_file = True), "npm_path": attr.string(), "npm_srcs": attr.label_list(), @@ -142,6 +146,7 @@ def nodejs_toolchain( name, node = None, node_path = "", + node_data = [], npm = None, npm_path = "", npm_srcs = [], @@ -206,6 +211,8 @@ def nodejs_toolchain( Only one of `node` and `node_path` may be set. + node_data: Additional runtime files required by the Node.js executable. + npm: Npm JavaScript entry point npm_path: Path to npm JavaScript entry point. @@ -252,6 +259,7 @@ WARNING: npm_files attribute of nodejs_toolchain is deprecated; use npm_srcs ins name = name, node = node, node_path = node_path, + node_data = node_data, npm = npm, npm_path = npm_path, npm_srcs = npm_srcs,