Skip to content

Commit 4c48449

Browse files
redsun82Paolo Tranquilli
and
Paolo Tranquilli
authored
feat: add node_urls parameter to bzlmod toolchain in the node extension (#3763)
--------- Co-authored-by: Paolo Tranquilli <[email protected]>
1 parent 20d9b25 commit 4c48449

File tree

19 files changed

+197
-33
lines changed

19 files changed

+197
-33
lines changed

.github/workflows/ci.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ jobs:
1919
test:
2020
uses: bazel-contrib/.github/.github/workflows/bazel.yaml@v6
2121
with:
22-
folders: '[".", "e2e/headers", "e2e/smoke", "e2e/nodejs_host"]'
22+
folders: '[".", "e2e/headers", "e2e/smoke", "e2e/nodejs_host", "e2e/conflicting_toolchains"]'
2323
# stardoc generated docs fail on diff_test with Bazel 6.4.0 so don't test against it in root repository
2424
exclude: |
2525
[
2626
{"bazelversion": "6.4.0", "os": "macos-latest"},
2727
{"bazelversion": "6.4.0", "os": "windows-latest"},
2828
{"bazelversion": "6.4.0", folder: "."},
2929
{"bazelversion": "6.4.0", bzlmodEnabled: true}
30+
# this test is for bzlmod only
31+
{folder: "e2e/conflicting_toolchains", bzlmodEnabled: false},
3032
]
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../.bazelversion

e2e/conflicting_toolchains/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
error.txt
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# this is set up to make bazel test //... pass
2+
load("@bazel_skylib//rules:write_file.bzl", "write_file")
3+
4+
write_file(
5+
name = "empty",
6+
out = "empty.sh",
7+
content = [],
8+
)
9+
10+
sh_test(
11+
name = "dummy",
12+
srcs = [":empty"],
13+
)
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# this is set up to make bazel test //... pass
2+
bazel_dep(name = "bazel_skylib", version = "1.7.1", dev_dependency = True)

e2e/conflicting_toolchains/test.sh

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
# this is the integration test checking various combinations of conflicting nodejs toolchain definitions
3+
4+
set -eu
5+
6+
for test_attr in test_*; do
7+
pushd $test_attr > /dev/null
8+
attr=${test_attr#test_}
9+
echo -n "testing conflict on $attr... "
10+
if bazel mod tidy &> error.txt; then
11+
echo "ERROR: bazel mod tidy should have failed with following MODULE.bazel:"
12+
cat MODULE.bazel
13+
exit 1
14+
elif ! grep "conflicting toolchains" error.txt > /dev/null; then
15+
echo "ERROR: expected bazel mod tidy to mention conflicting toolchains, found:"
16+
cat error.txt
17+
exit 1
18+
else
19+
echo "PASS"
20+
fi
21+
popd > /dev/null
22+
done
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../.bazelversion
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
bazel_dep(name = "rules_nodejs", version = "0.0.0", dev_dependency = True)
2+
local_path_override(
3+
module_name = "rules_nodejs",
4+
path = "../../..",
5+
)
6+
7+
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node", dev_dependency = True)
8+
node.toolchain(
9+
name = "mynode",
10+
)
11+
node.toolchain(
12+
name = "mynode",
13+
node_urls = ["file://whatever"],
14+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../.bazelversion
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
bazel_dep(name = "rules_nodejs", version = "0.0.0", dev_dependency = True)
2+
local_path_override(
3+
module_name = "rules_nodejs",
4+
path = "../../..",
5+
)
6+
7+
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node", dev_dependency = True)
8+
node.toolchain(
9+
name = "mynode",
10+
)
11+
node.toolchain(
12+
name = "mynode",
13+
include_headers = True,
14+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../.bazelversion
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
bazel_dep(name = "rules_nodejs", version = "0.0.0", dev_dependency = True)
2+
local_path_override(
3+
module_name = "rules_nodejs",
4+
path = "../../..",
5+
)
6+
7+
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node", dev_dependency = True)
8+
node.toolchain(
9+
name = "mynode",
10+
)
11+
node.toolchain(
12+
name = "mynode",
13+
node_version = "15.14.0",
14+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../.bazelversion

e2e/conflicting_toolchains/test_node_version_from_nvmrc/.nvmrc

Whitespace-only changes.

e2e/conflicting_toolchains/test_node_version_from_nvmrc/BUILD.bazel

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
bazel_dep(name = "rules_nodejs", version = "0.0.0", dev_dependency = True)
2+
local_path_override(
3+
module_name = "rules_nodejs",
4+
path = "../../..",
5+
)
6+
7+
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node", dev_dependency = True)
8+
node.toolchain(
9+
name = "mynode",
10+
)
11+
node.toolchain(
12+
name = "mynode",
13+
node_version_from_nvmrc = "//:.nvmrc",
14+
)

e2e/smoke/BUILD.bazel

+25
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,12 @@ write_file(
202202

203203
# Files used in test cases later that contain the correct nodejs version
204204
# that is imported into the workspace.
205+
write_file(
206+
name = "write_node_version_15",
207+
out = "expected_node_15",
208+
content = ["v15.14.0"],
209+
)
210+
205211
write_file(
206212
name = "write_node_version_17",
207213
out = "expected_node_17",
@@ -268,3 +274,22 @@ diff_test(
268274
file1 = "write_node_version_16",
269275
file2 = "thing_toolchain_16",
270276
)
277+
278+
my_nodejs(
279+
name = "run_15",
280+
out = "thing_toolchain_15",
281+
entry_point = "version.js",
282+
# using the select statement will download toolchains for all three platforms
283+
# you can also just provide an individual toolchain if you don't want to download them all
284+
toolchain = select({
285+
"@bazel_tools//src/conditions:linux_x86_64": "@node15_linux_amd64//:toolchain",
286+
"@bazel_tools//src/conditions:darwin": "@node15_darwin_amd64//:toolchain",
287+
"@bazel_tools//src/conditions:windows": "@node15_windows_amd64//:toolchain",
288+
}),
289+
)
290+
291+
diff_test(
292+
name = "test_node_version_15",
293+
file1 = "write_node_version_15",
294+
file2 = "thing_toolchain_15",
295+
)

e2e/smoke/MODULE.bazel

+11
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,21 @@ node.toolchain(
1414
name = "node17",
1515
node_version = "17.9.1",
1616
)
17+
node.toolchain(
18+
name = "node15",
19+
node_urls = [
20+
"https://nodejs.org/dist/v{version}/{filename}",
21+
"https://mirrors.dotsrc.org/nodejs/release/v{version}/{filename}",
22+
],
23+
node_version = "15.14.0",
24+
)
1725

1826
# FIXME(6.0): a repo rule with name=foo should create a repo named @foo, not @foo_toolchains
1927
use_repo(
2028
node,
29+
"node15_darwin_amd64",
30+
"node15_linux_amd64",
31+
"node15_windows_amd64",
2132
"node17_darwin_amd64",
2233
"node17_linux_amd64",
2334
"node17_windows_amd64",

nodejs/extensions.bzl

+59-32
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
"extensions for bzlmod"
22

3-
load(":repositories.bzl", "DEFAULT_NODE_REPOSITORY", "DEFAULT_NODE_VERSION", "nodejs_register_toolchains")
3+
load(
4+
":repositories.bzl",
5+
"DEFAULT_NODE_REPOSITORY",
6+
"DEFAULT_NODE_URL",
7+
"DEFAULT_NODE_VERSION",
8+
"nodejs_register_toolchains",
9+
)
10+
11+
def _toolchain_repr(toolchain):
12+
""" Return a `toolchain` tag object representation useful for diagnostics """
13+
key_values = [(attr, getattr(toolchain, attr)) for attr in _ATTRS]
14+
return ", ".join(["%s = %r" % (attr, value) for attr, value in key_values if value])
15+
16+
def _toolchains_equal(lhs, rhs):
17+
""" Compare two `toolchain` tag objects """
18+
for attr in _ATTRS:
19+
if getattr(lhs, attr) != getattr(rhs, attr):
20+
return False
21+
return True
422

523
def _toolchain_extension(module_ctx):
624
registrations = {}
@@ -14,54 +32,63 @@ def _toolchain_extension(module_ctx):
1432
# Prioritize the root-most registration of the default node toolchain version and
1533
# ignore any further registrations (modules are processed breadth-first)
1634
continue
17-
if toolchain.node_version == registrations[toolchain.name].node_version and toolchain.node_version_from_nvmrc == registrations[toolchain.name].node_version_from_nvmrc:
35+
if not _toolchains_equal(toolchain, registrations[toolchain.name]):
36+
fail("Multiple conflicting toolchains declared:\n* {}\n* {}".format(
37+
_toolchain_repr(toolchain),
38+
_toolchain_repr(registrations[toolchain.name]),
39+
))
40+
else:
1841
# No problem to register a matching toolchain twice
1942
continue
20-
fail("Multiple conflicting toolchains declared for name {} ({} and {})".format(
21-
toolchain.name,
22-
toolchain.node_version,
23-
registrations[toolchain.name],
24-
))
2543
else:
26-
registrations[toolchain.name] = struct(
27-
node_version = toolchain.node_version,
28-
node_version_from_nvmrc = toolchain.node_version_from_nvmrc,
29-
include_headers = toolchain.include_headers,
30-
)
44+
registrations[toolchain.name] = toolchain
3145

3246
for k, v in registrations.items():
3347
nodejs_register_toolchains(
3448
name = k,
3549
node_version = v.node_version,
3650
node_version_from_nvmrc = v.node_version_from_nvmrc,
51+
node_urls = v.node_urls,
3752
include_headers = v.include_headers,
3853
register = False,
3954
)
4055

41-
node = module_extension(
42-
implementation = _toolchain_extension,
43-
tag_classes = {
44-
"toolchain": tag_class(attrs = {
45-
"name": attr.string(
46-
doc = "Base name for generated repositories",
47-
default = DEFAULT_NODE_REPOSITORY,
48-
),
49-
"node_version": attr.string(
50-
doc = "Version of the Node.js interpreter",
51-
default = DEFAULT_NODE_VERSION,
52-
),
53-
"node_version_from_nvmrc": attr.label(
54-
allow_single_file = True,
55-
doc = """The .nvmrc file containing the version of Node.js to use.
56+
_ATTRS = {
57+
"name": attr.string(
58+
doc = "Base name for generated repositories",
59+
default = DEFAULT_NODE_REPOSITORY,
60+
),
61+
"node_version": attr.string(
62+
doc = "Version of the Node.js interpreter",
63+
default = DEFAULT_NODE_VERSION,
64+
),
65+
"node_version_from_nvmrc": attr.label(
66+
allow_single_file = True,
67+
doc = """The .nvmrc file containing the version of Node.js to use.
5668
5769
If set then the version found in the .nvmrc file is used instead of the one specified by node_version.""",
58-
),
59-
"include_headers": attr.bool(
60-
doc = """Set headers field in NodeInfo provided by this toolchain.
70+
),
71+
"include_headers": attr.bool(
72+
doc = """Set headers field in NodeInfo provided by this toolchain.
6173
6274
This setting creates a dependency on a c++ toolchain.
6375
""",
64-
),
65-
}),
76+
),
77+
"node_urls": attr.string_list(
78+
doc = """List of URLs to use to download Node.js.
79+
80+
Each entry is a template for downloading a node distribution.
81+
82+
The `{version}` parameter is substituted with the `node_version` attribute,
83+
and `{filename}` with the matching entry from the `node_repositories` attribute.
84+
""",
85+
default = [DEFAULT_NODE_URL],
86+
),
87+
}
88+
89+
node = module_extension(
90+
implementation = _toolchain_extension,
91+
tag_classes = {
92+
"toolchain": tag_class(attrs = _ATTRS),
6693
},
6794
)

0 commit comments

Comments
 (0)