Skip to content

Commit

Permalink
feat: support custom nodejs toolchains (#1053)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbedard committed May 9, 2023
1 parent 1d2c499 commit fa60c0c
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 30 deletions.
18 changes: 18 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,25 @@ node_dev = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node", dev_dep

use_repo(node_dev, "nodejs_toolchains")

use_repo(node_dev, "node18_linux_amd64")
use_repo(node_dev, "node18_darwin_arm64")
use_repo(node_dev, "node18_darwin_amd64")
use_repo(node_dev, "node18_linux_arm64")
use_repo(node_dev, "node18_linux_s390x")
use_repo(node_dev, "node18_linux_ppc64le")
use_repo(node_dev, "node18_windows_amd64")

use_repo(node_dev, "node16_linux_amd64")
use_repo(node_dev, "node16_darwin_arm64")
use_repo(node_dev, "node16_darwin_amd64")
use_repo(node_dev, "node16_linux_arm64")
use_repo(node_dev, "node16_linux_s390x")
use_repo(node_dev, "node16_linux_ppc64le")
use_repo(node_dev, "node16_windows_amd64")

node_dev.toolchain(node_version = "16.14.2")
node_dev.toolchain(name = "node16", node_version = "16.13.1")
node_dev.toolchain(name = "node18", node_version = "18.13.0")

############################################
# npm dependencies used by examples
Expand Down
8 changes: 4 additions & 4 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ nodejs_register_toolchains(

# Alternate toolchains for testing across versions
nodejs_register_toolchains(
name = "node14",
node_version = "14.17.1",
name = "node16",
node_version = "16.13.1",
)

nodejs_register_toolchains(
name = "node16",
node_version = "16.13.1",
name = "node18",
node_version = "18.13.0",
)

load("@bazel_skylib//lib:unittest.bzl", "register_unittest_toolchains")
Expand Down
10 changes: 6 additions & 4 deletions docs/js_binary.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 23 additions & 7 deletions js/private/js_binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,16 @@ _ATTRS = {
# TODO(2.0): make this mandatory so that downstream binary rules that inherit these attributes are required to set it
mandatory = False,
),
"node_toolchain": attr.label(
doc = """The Node.js toolchain to use for this target.
See https://bazelbuild.github.io/rules_nodejs/Toolchains.html
Typically this is left unset so that Bazel automatically selects the right Node.js toolchain
for the target platform. See https://bazel.build/extending/toolchains#toolchain-resolution
for more information.
""",
),
"_launcher_template": attr.label(
default = Label("//js/private:js_binary.sh.tpl"),
allow_single_file = True,
Expand Down Expand Up @@ -309,7 +319,7 @@ def _consistent_label_str(workspace_name, label):
label.name,
)

def _bash_launcher(ctx, entry_point_path, log_prefix_rule_set, log_prefix_rule, fixed_args, fixed_env, is_windows, use_legacy_node_patches):
def _bash_launcher(ctx, node_toolchain, entry_point_path, log_prefix_rule_set, log_prefix_rule, fixed_args, fixed_env, is_windows, use_legacy_node_patches):
envs = []
for (key, value) in dicts.add(fixed_env, ctx.attr.env).items():
envs.append(_ENV_SET.format(
Expand Down Expand Up @@ -400,7 +410,7 @@ def _bash_launcher(ctx, entry_point_path, log_prefix_rule_set, log_prefix_rule,

npm_path = ""
if ctx.attr.include_npm:
npm_path = _target_tool_short_path(ctx.workspace_name, ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo.npm_path)
npm_path = _target_tool_short_path(ctx.workspace_name, node_toolchain.nodeinfo.npm_path)
if is_windows:
npm_wrapper = ctx.actions.declare_file("%s_node_bin/npm.bat" % ctx.label.name)
ctx.actions.expand_template(
Expand All @@ -419,7 +429,7 @@ def _bash_launcher(ctx, entry_point_path, log_prefix_rule_set, log_prefix_rule,
)
toolchain_files.append(npm_wrapper)

node_path = _target_tool_short_path(ctx.workspace_name, ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo.target_tool_path)
node_path = _target_tool_short_path(ctx.workspace_name, node_toolchain.nodeinfo.target_tool_path)

launcher_subst = {
"{{target_label}}": _consistent_label_str(ctx.workspace_name, ctx.label),
Expand Down Expand Up @@ -457,10 +467,15 @@ def _create_launcher(ctx, log_prefix_rule_set, log_prefix_rule, fixed_args = [],
unresolved_symlinks_enabled = ctx.attr.unresolved_symlinks_enabled
use_legacy_node_patches = not is_bazel_6 or not unresolved_symlinks_enabled

if ctx.attr.node_toolchain:
node_toolchain = ctx.attr.node_toolchain[platform_common.ToolchainInfo]
else:
node_toolchain = ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"]

if is_windows and not ctx.attr.enable_runfiles:
fail("need --enable_runfiles on Windows for to support rules_js")

if ctx.attr.include_npm and not hasattr(ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo, "npm_files"):
if ctx.attr.include_npm and not hasattr(node_toolchain.nodeinfo, "npm_files"):
fail("include_npm requires a minimum @rules_nodejs version of 5.7.0")

if DirectoryPathInfo in ctx.attr.entry_point:
Expand All @@ -475,17 +490,18 @@ def _create_launcher(ctx, log_prefix_rule_set, log_prefix_rule, fixed_args = [],
entry_point = ctx.files.entry_point[0]
entry_point_path = entry_point.short_path

bash_launcher, toolchain_files = _bash_launcher(ctx, entry_point_path, log_prefix_rule_set, log_prefix_rule, fixed_args, fixed_env, is_windows, use_legacy_node_patches)
bash_launcher, toolchain_files = _bash_launcher(ctx, node_toolchain, entry_point_path, log_prefix_rule_set, log_prefix_rule, fixed_args, fixed_env, is_windows, use_legacy_node_patches)
launcher = create_windows_native_launcher_script(ctx, bash_launcher) if is_windows else bash_launcher

launcher_files = [bash_launcher] + toolchain_files
if use_legacy_node_patches:
launcher_files.extend(ctx.files._node_patches_legacy_files + [ctx.file._node_patches_legacy])
else:
launcher_files.extend(ctx.files._node_patches_files + [ctx.file._node_patches])
launcher_files.extend(ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo.tool_files)

launcher_files.extend(node_toolchain.nodeinfo.tool_files)
if ctx.attr.include_npm:
launcher_files.extend(ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo.npm_files)
launcher_files.extend(node_toolchain.nodeinfo.npm_files)

runfiles = gather_runfiles(
ctx = ctx,
Expand Down
44 changes: 43 additions & 1 deletion js/private/test/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files")
load("@aspect_bazel_lib_host//:defs.bzl", "host")
load("//js:defs.bzl", "js_binary", "js_library")
load("//js:defs.bzl", "js_binary", "js_library", "js_test")
load(":js_library_test.bzl", "js_library_test_suite")

####################################################################################################
Expand Down Expand Up @@ -59,3 +59,45 @@ genrule(
cmd = "echo '{\"answer\": 42}' > $@",
visibility = ["//js/private/test:__subpackages__"],
)

write_file(
name = "binary_version",
out = "binary_version.js",
content = ["""
if (parseInt(process.version.slice(1)) !== parseInt(process.argv[2])) {
throw new Error(`Expected node version ${parseInt(process.version)}.* but got ${parseInt(process.argv[2])}`)
}
"""],
)

js_test(
name = "main_default_toolchain",
args = ["16"],
entry_point = "binary_version.js",
)

js_test(
name = "main_toolchain_16",
args = ["16"],
entry_point = "binary_version.js",
# using the select statement will download toolchains for all three platforms
# you can also just provide an individual toolchain if you don't want to download them all
node_toolchain = select({
"@bazel_tools//src/conditions:linux_x86_64": "@node16_linux_amd64//:node_toolchain",
"@bazel_tools//src/conditions:darwin": "@node16_darwin_amd64//:node_toolchain",
"@bazel_tools//src/conditions:windows": "@node16_windows_amd64//:node_toolchain",
}),
)

js_test(
name = "main_toolchain_18",
args = ["18"],
entry_point = "binary_version.js",
# using the select statement will download toolchains for all three platforms
# you can also just provide an individual toolchain if you don't want to download them all
node_toolchain = select({
"@bazel_tools//src/conditions:linux_x86_64": "@node18_linux_amd64//:node_toolchain",
"@bazel_tools//src/conditions:darwin": "@node18_darwin_amd64//:node_toolchain",
"@bazel_tools//src/conditions:windows": "@node18_windows_amd64//:node_toolchain",
}),
)
Loading

0 comments on commit fa60c0c

Please sign in to comment.