From 11437b8005db9788d664febf61ff5c3d7c2d6c0a Mon Sep 17 00:00:00 2001 From: Greg Magolan Date: Tue, 2 Apr 2024 01:37:50 -0400 Subject: [PATCH] fix: support node_version_from_nvmrc with bzlmod --- docs/Core.md | 247 +++++++++++++++++----------------- e2e/nodejs_host/.bazelversion | 1 + e2e/nodejs_host/MODULE.bazel | 25 ++-- e2e/nodejs_host/WORKSPACE | 2 +- nodejs/extensions.bzl | 20 ++- nodejs/repositories.bzl | 210 ++++++++++++++++------------- 6 files changed, 268 insertions(+), 237 deletions(-) create mode 100644 e2e/nodejs_host/.bazelversion diff --git a/docs/Core.md b/docs/Core.md index 3588d38753..ddbd56e08a 100644 --- a/docs/Core.md +++ b/docs/Core.md @@ -12,131 +12,6 @@ Features: - Core [Providers](https://docs.bazel.build/versions/main/skylark/rules.html#providers) to allow interop between JS rules. -## node_repositories - -**USAGE** - -
-node_repositories(name, node_download_auth, node_repositories, node_urls, node_version, platform,
-                  repo_mapping, use_nvmrc)
-
- -To be run in user's WORKSPACE to install rules_nodejs dependencies. - -This rule sets up node, npm, and npx. The versions of these tools can be specified in one of three ways - -### Simplest Usage - -Specify no explicit versions. This will download and use the latest NodeJS that was available when the -version of rules_nodejs you're using was released. - -### Forced version(s) - -You can select the version of NodeJS to download & use by specifying it when you call node_repositories, -using a value that matches a known version (see the default values) - -### Using a custom version - -You can pass in a custom list of NodeJS repositories and URLs for node_repositories to use. - -#### Custom NodeJS versions - -To specify custom NodeJS versions, use the `node_repositories` attribute - -```python -node_repositories( - node_repositories = { - "10.10.0-darwin_amd64": ("node-v10.10.0-darwin-x64.tar.gz", "node-v10.10.0-darwin-x64", "00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e"), - "10.10.0-linux_amd64": ("node-v10.10.0-linux-x64.tar.xz", "node-v10.10.0-linux-x64", "686d2c7b7698097e67bcd68edc3d6b5d28d81f62436c7cf9e7779d134ec262a9"), - "10.10.0-windows_amd64": ("node-v10.10.0-win-x64.zip", "node-v10.10.0-win-x64", "70c46e6451798be9d052b700ce5dadccb75cf917f6bf0d6ed54344c856830cfb"), - }, -) -``` - -These can be mapped to a custom download URL, using `node_urls` - -```python -node_repositories( - node_version = "10.10.0", - node_repositories = {"10.10.0-darwin_amd64": ("node-v10.10.0-darwin-x64.tar.gz", "node-v10.10.0-darwin-x64", "00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e")}, - node_urls = ["https://mycorpproxy/mirror/node/v{version}/{filename}"], -) -``` - -A Mac client will try to download node from `https://mycorpproxy/mirror/node/v10.10.0/node-v10.10.0-darwin-x64.tar.gz` -and expect that file to have sha256sum `00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e` - -See the [the repositories documentation](repositories.html) for how to use the resulting repositories. - -### Using a custom node.js. - -To avoid downloads, you can check in a vendored node.js binary or can build one from source. -See [toolchains](./toolchains.md). - - -**ATTRIBUTES** - - -

name

- -(*Name, mandatory*): A unique name for this repository. - - -

node_download_auth

- -(*Dictionary: String -> String*): auth to use for all url requests -Example: {"type": "basic", "login": "", "password": "" } - -Defaults to `{}` - -

node_repositories

- -(*Dictionary: String -> List of strings*): Custom list of node repositories to use - -A dictionary mapping NodeJS versions to sets of hosts and their corresponding (filename, strip_prefix, sha256) tuples. -You should list a node binary for every platform users have, likely Mac, Windows, and Linux. - -By default, if this attribute has no items, we'll use a list of all public NodeJS releases. - -Defaults to `{}` - -

node_urls

- -(*List of strings*): custom list of URLs to use to download NodeJS - -Each entry is a template for downloading a node distribution. - -The `{version}` parameter is substituted with the `node_version` attribute, -and `{filename}` with the matching entry from the `node_repositories` attribute. - -Defaults to `["https://nodejs.org/dist/v{version}/{filename}"]` - -

node_version

- -(*String*): the specific version of NodeJS to install - -Defaults to `"18.20.0"` - -

platform

- -(*String*): Internal use only. Which platform to install as a toolchain. If unset, we assume the repository is named nodejs_[platform] - -Defaults to `""` - -

repo_mapping

- -(*Dictionary: String -> String, mandatory*): A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.

For example, an entry `"@foo": "@bar"` declares that, for any time this repository depends on `@foo` (such as a dependency on `@foo//some:target`, it should actually resolve that dependency within globally-declared `@bar` (`@bar//some:target`). - - -

use_nvmrc

- -(*Label*): the local path of the .nvmrc file containing the version of node - -If set then also set node_version to the version found in the .nvmrc file. - -Defaults to `None` - - ## node_toolchain **USAGE** @@ -247,3 +122,125 @@ UserBuildSettingInfo(value) (Undocumented) +## node_repositories + +**USAGE** + +
+node_repositories(name, node_download_auth, node_repositories, node_urls, node_version,
+                  node_version_from_nvmrc, kwargs)
+
+ +To be run in user's WORKSPACE to install rules_nodejs dependencies. + +This rule sets up node, npm, and npx. The versions of these tools can be specified in one of three ways + +### Simplest Usage + +Specify no explicit versions. This will download and use the latest Node.js that was available when the +version of rules_nodejs you're using was released. + +### Forced version(s) + +You can select the version of Node.js to download & use by specifying it when you call node_repositories, +using a value that matches a known version (see the default values) + +### Using a custom version + +You can pass in a custom list of Node.js repositories and URLs for node_repositories to use. + +#### Custom Node.js versions + +To specify custom Node.js versions, use the `node_repositories` attribute + +```python +node_repositories( + node_repositories = { + "10.10.0-darwin_amd64": ("node-v10.10.0-darwin-x64.tar.gz", "node-v10.10.0-darwin-x64", "00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e"), + "10.10.0-linux_amd64": ("node-v10.10.0-linux-x64.tar.xz", "node-v10.10.0-linux-x64", "686d2c7b7698097e67bcd68edc3d6b5d28d81f62436c7cf9e7779d134ec262a9"), + "10.10.0-windows_amd64": ("node-v10.10.0-win-x64.zip", "node-v10.10.0-win-x64", "70c46e6451798be9d052b700ce5dadccb75cf917f6bf0d6ed54344c856830cfb"), + }, +) +``` + +These can be mapped to a custom download URL, using `node_urls` + +```python +node_repositories( + node_version = "10.10.0", + node_repositories = {"10.10.0-darwin_amd64": ("node-v10.10.0-darwin-x64.tar.gz", "node-v10.10.0-darwin-x64", "00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e")}, + node_urls = ["https://mycorpproxy/mirror/node/v{version}/{filename}"], +) +``` + +A Mac client will try to download node from `https://mycorpproxy/mirror/node/v10.10.0/node-v10.10.0-darwin-x64.tar.gz` +and expect that file to have sha256sum `00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e` + +See the [the repositories documentation](repositories.html) for how to use the resulting repositories. + +### Using a custom node.js. + +To avoid downloads, you can check in a vendored node.js binary or can build one from source. +See [toolchains](./toolchains.md). + + +**PARAMETERS** + + +

name

+ +Unique name for the repository rule + + + +

node_download_auth

+ +Auth to use for all url requests. + +Example: { "type": "basic", "login": "<UserName>", "password": "<Password>" } + +Defaults to `{}` + +

node_repositories

+ +Custom list of node repositories to use + +A dictionary mapping Node.js versions to sets of hosts and their corresponding (filename, strip_prefix, sha256) tuples. +You should list a node binary for every platform users have, likely Mac, Windows, and Linux. + +By default, if this attribute has no items, we'll use a list of all public Node.js releases. + +Defaults to `{}` + +

node_urls

+ +List of URLs to use to download Node.js. + +Each entry is a template for downloading a node distribution. + +The `{version}` parameter is substituted with the `node_version` attribute, +and `{filename}` with the matching entry from the `node_repositories` attribute. + +Defaults to `["https://nodejs.org/dist/v{version}/{filename}"]` + +

node_version

+ +The specific version of Node.js to install + +Defaults to `"18.20.0"` + +

node_version_from_nvmrc

+ +The .nvmrc file containing the version of Node.js to use. + +If set then the version found in the .nvmrc file is used instead of the one specified by node_version. + +Defaults to `None` + +

kwargs

+ +Additional parameters + + + + diff --git a/e2e/nodejs_host/.bazelversion b/e2e/nodejs_host/.bazelversion new file mode 100644 index 0000000000..21c8c7b46b --- /dev/null +++ b/e2e/nodejs_host/.bazelversion @@ -0,0 +1 @@ +7.1.1 diff --git a/e2e/nodejs_host/MODULE.bazel b/e2e/nodejs_host/MODULE.bazel index 5b0a98617e..1e3a248c81 100644 --- a/e2e/nodejs_host/MODULE.bazel +++ b/e2e/nodejs_host/MODULE.bazel @@ -21,20 +21,23 @@ node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") # https://github.com/bazelbuild/rules_nodejs/blob/5.8.0/nodejs/repositories.bzl#L11 node.toolchain() node.toolchain( - name = "node16", - node_version = "16.5.0", + name = "node14", + node_version = "14.19.0", +) +node.toolchain( + name = "node16_nvmrc", + node_version_from_nvmrc = "//:.nvmrc", ) - -# TODO: nvmrc test like WORKSPACE? # FIXME(6.0): a repo rule with name=foo should create a repo named @foo, not @foo_toolchains use_repo( node, - "node16_darwin_amd64", - "node16_linux_amd64", - "node16_toolchains", - "node16_windows_amd64", - "nodejs_darwin_amd64", - "nodejs_linux_amd64", - "nodejs_windows_amd64", + "node16_nvmrc_darwin_amd64", + "node16_nvmrc_linux_amd64", + "node16_nvmrc_toolchains", + "node16_nvmrc_windows_amd64", + "node14_darwin_amd64", + "node14_linux_amd64", + "node14_toolchains", + "node14_windows_amd64", ) diff --git a/e2e/nodejs_host/WORKSPACE b/e2e/nodejs_host/WORKSPACE index 92f5c71c31..412f28c706 100644 --- a/e2e/nodejs_host/WORKSPACE +++ b/e2e/nodejs_host/WORKSPACE @@ -31,5 +31,5 @@ nodejs_register_toolchains( nodejs_register_toolchains( name = "node16_nvmrc", - use_nvmrc = "//:.nvmrc", + node_version_from_nvmrc = "//:.nvmrc", ) diff --git a/nodejs/extensions.bzl b/nodejs/extensions.bzl index 3d2fc8b657..45d589be3c 100644 --- a/nodejs/extensions.bzl +++ b/nodejs/extensions.bzl @@ -14,7 +14,7 @@ def _toolchain_extension(module_ctx): # Prioritize the root-most registration of the default node toolchain version and # ignore any further registrations (modules are processed breadth-first) continue - if toolchain.node_version == registrations[toolchain.name]: + if toolchain.node_version == registrations[toolchain.name].node_version and toolchain.node_version_from_nvmrc == registrations[toolchain.name].node_version_from_nvmrc: # No problem to register a matching toolchain twice continue fail("Multiple conflicting toolchains declared for name {} ({} and {})".format( @@ -23,12 +23,16 @@ def _toolchain_extension(module_ctx): registrations[toolchain.name], )) else: - registrations[toolchain.name] = toolchain.node_version + registrations[toolchain.name] = struct( + node_version = toolchain.node_version, + node_version_from_nvmrc = toolchain.node_version_from_nvmrc, + ) - for name, node_version in registrations.items(): + for k, v in registrations.items(): nodejs_register_toolchains( - name = name, - node_version = node_version, + name = k, + node_version = v.node_version, + node_version_from_nvmrc = v.node_version_from_nvmrc, register = False, ) @@ -44,6 +48,12 @@ node = module_extension( doc = "Version of the Node.js interpreter", default = DEFAULT_NODE_VERSION, ), + "node_version_from_nvmrc": attr.label( + allow_single_file = True, + doc = """The .nvmrc file containing the version of Node.js to use. + +If set then the version found in the .nvmrc file is used instead of the one specified by node_version.""", + ), }), }, ) diff --git a/nodejs/repositories.bzl b/nodejs/repositories.bzl index 17f4d982f5..a94d2e0dba 100644 --- a/nodejs/repositories.bzl +++ b/nodejs/repositories.bzl @@ -22,98 +22,12 @@ DEFAULT_NODE_VERSION = [ BUILT_IN_NODE_PLATFORMS = PLATFORMS.keys() -_DOC = """To be run in user's WORKSPACE to install rules_nodejs dependencies. - -This rule sets up node, npm, and npx. The versions of these tools can be specified in one of three ways - -### Simplest Usage - -Specify no explicit versions. This will download and use the latest NodeJS that was available when the -version of rules_nodejs you're using was released. - -### Forced version(s) - -You can select the version of NodeJS to download & use by specifying it when you call node_repositories, -using a value that matches a known version (see the default values) - -### Using a custom version - -You can pass in a custom list of NodeJS repositories and URLs for node_repositories to use. - -#### Custom NodeJS versions - -To specify custom NodeJS versions, use the `node_repositories` attribute - -```python -node_repositories( - node_repositories = { - "10.10.0-darwin_amd64": ("node-v10.10.0-darwin-x64.tar.gz", "node-v10.10.0-darwin-x64", "00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e"), - "10.10.0-linux_amd64": ("node-v10.10.0-linux-x64.tar.xz", "node-v10.10.0-linux-x64", "686d2c7b7698097e67bcd68edc3d6b5d28d81f62436c7cf9e7779d134ec262a9"), - "10.10.0-windows_amd64": ("node-v10.10.0-win-x64.zip", "node-v10.10.0-win-x64", "70c46e6451798be9d052b700ce5dadccb75cf917f6bf0d6ed54344c856830cfb"), - }, -) -``` - -These can be mapped to a custom download URL, using `node_urls` - -```python -node_repositories( - node_version = "10.10.0", - node_repositories = {"10.10.0-darwin_amd64": ("node-v10.10.0-darwin-x64.tar.gz", "node-v10.10.0-darwin-x64", "00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e")}, - node_urls = ["https://mycorpproxy/mirror/node/v{version}/{filename}"], -) -``` - -A Mac client will try to download node from `https://mycorpproxy/mirror/node/v10.10.0/node-v10.10.0-darwin-x64.tar.gz` -and expect that file to have sha256sum `00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e` - -See the [the repositories documentation](repositories.html) for how to use the resulting repositories. - -### Using a custom node.js. - -To avoid downloads, you can check in a vendored node.js binary or can build one from source. -See [toolchains](./toolchains.md). -""" - _ATTRS = { - "node_download_auth": attr.string_dict( - default = {}, - doc = """auth to use for all url requests -Example: {\"type\": \"basic\", \"login\": \"\", \"password\": \"\" } -""", - ), - "node_repositories": attr.string_list_dict( - doc = """Custom list of node repositories to use - -A dictionary mapping NodeJS versions to sets of hosts and their corresponding (filename, strip_prefix, sha256) tuples. -You should list a node binary for every platform users have, likely Mac, Windows, and Linux. - -By default, if this attribute has no items, we'll use a list of all public NodeJS releases. -""", - ), - "node_urls": attr.string_list( - default = [ - "https://nodejs.org/dist/v{version}/{filename}", - ], - doc = """custom list of URLs to use to download NodeJS - -Each entry is a template for downloading a node distribution. - -The `{version}` parameter is substituted with the `node_version` attribute, -and `{filename}` with the matching entry from the `node_repositories` attribute. -""", - ), - "node_version": attr.string( - default = DEFAULT_NODE_VERSION, - doc = "the specific version of NodeJS to install", - ), - "use_nvmrc": attr.label( - allow_single_file = True, - default = None, - doc = """the local path of the .nvmrc file containing the version of node - -If set then also set node_version to the version found in the .nvmrc file.""", - ), + "node_download_auth": attr.string_dict(), + "node_repositories": attr.string_list_dict(), + "node_urls": attr.string_list(), + "node_version": attr.string(), + "node_version_from_nvmrc": attr.label(allow_single_file = True), "platform": attr.string( doc = "Internal use only. Which platform to install as a toolchain. If unset, we assume the repository is named nodejs_[platform]", values = BUILT_IN_NODE_PLATFORMS, @@ -149,8 +63,8 @@ def _download_node(repository_ctx): node_version = repository_ctx.attr.node_version - if repository_ctx.attr.use_nvmrc: - node_version = str(repository_ctx.read(repository_ctx.attr.use_nvmrc)).strip() + if repository_ctx.attr.node_version_from_nvmrc: + node_version = str(repository_ctx.read(repository_ctx.attr.node_version_from_nvmrc)).strip() _verify_version_is_valid(node_version) @@ -379,12 +293,118 @@ def _nodejs_repo_impl(repository_ctx): _download_node(repository_ctx) _prepare_node(repository_ctx) -node_repositories = repository_rule( +_node_repositories = repository_rule( _nodejs_repo_impl, - doc = _DOC, attrs = _ATTRS, ) +def node_repositories( + name, + node_download_auth = {}, + node_repositories = {}, + node_urls = ["https://nodejs.org/dist/v{version}/{filename}"], + node_version = DEFAULT_NODE_VERSION, + node_version_from_nvmrc = None, + **kwargs): + """To be run in user's WORKSPACE to install rules_nodejs dependencies. + + This rule sets up node, npm, and npx. The versions of these tools can be specified in one of three ways + + ### Simplest Usage + + Specify no explicit versions. This will download and use the latest Node.js that was available when the + version of rules_nodejs you're using was released. + + ### Forced version(s) + + You can select the version of Node.js to download & use by specifying it when you call node_repositories, + using a value that matches a known version (see the default values) + + ### Using a custom version + + You can pass in a custom list of Node.js repositories and URLs for node_repositories to use. + + #### Custom Node.js versions + + To specify custom Node.js versions, use the `node_repositories` attribute + + ```python + node_repositories( + node_repositories = { + "10.10.0-darwin_amd64": ("node-v10.10.0-darwin-x64.tar.gz", "node-v10.10.0-darwin-x64", "00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e"), + "10.10.0-linux_amd64": ("node-v10.10.0-linux-x64.tar.xz", "node-v10.10.0-linux-x64", "686d2c7b7698097e67bcd68edc3d6b5d28d81f62436c7cf9e7779d134ec262a9"), + "10.10.0-windows_amd64": ("node-v10.10.0-win-x64.zip", "node-v10.10.0-win-x64", "70c46e6451798be9d052b700ce5dadccb75cf917f6bf0d6ed54344c856830cfb"), + }, + ) + ``` + + These can be mapped to a custom download URL, using `node_urls` + + ```python + node_repositories( + node_version = "10.10.0", + node_repositories = {"10.10.0-darwin_amd64": ("node-v10.10.0-darwin-x64.tar.gz", "node-v10.10.0-darwin-x64", "00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e")}, + node_urls = ["https://mycorpproxy/mirror/node/v{version}/{filename}"], + ) + ``` + + A Mac client will try to download node from `https://mycorpproxy/mirror/node/v10.10.0/node-v10.10.0-darwin-x64.tar.gz` + and expect that file to have sha256sum `00b7a8426e076e9bf9d12ba2d571312e833fe962c70afafd10ad3682fdeeaa5e` + + See the [the repositories documentation](repositories.html) for how to use the resulting repositories. + + ### Using a custom node.js. + + To avoid downloads, you can check in a vendored node.js binary or can build one from source. + See [toolchains](./toolchains.md). + + Args: + name: Unique name for the repository rule + + node_download_auth: Auth to use for all url requests. + + Example: { "type": "basic", "login": "", "password": "" } + + node_repositories: Custom list of node repositories to use + + A dictionary mapping Node.js versions to sets of hosts and their corresponding (filename, strip_prefix, sha256) tuples. + You should list a node binary for every platform users have, likely Mac, Windows, and Linux. + + By default, if this attribute has no items, we'll use a list of all public Node.js releases. + + node_urls: List of URLs to use to download Node.js. + + Each entry is a template for downloading a node distribution. + + The `{version}` parameter is substituted with the `node_version` attribute, + and `{filename}` with the matching entry from the `node_repositories` attribute. + + node_version: The specific version of Node.js to install + + node_version_from_nvmrc: The .nvmrc file containing the version of Node.js to use. + + If set then the version found in the .nvmrc file is used instead of the one specified by node_version. + + **kwargs: Additional parameters + """ + use_nvmrc = kwargs.pop("use_nvmrc", None) + if use_nvmrc: + # buildifier: disable=print + print("""\ +WARNING: use_nvmrc attribute of node_repositories is deprecated; use node_version_from_nvmrc instead of use_nvmrc +""") + node_version_from_nvmrc = use_nvmrc + + _node_repositories( + name = name, + node_download_auth = node_download_auth, + node_repositories = node_repositories, + node_urls = node_urls, + node_version = node_version, + node_version_from_nvmrc = node_version_from_nvmrc, + **kwargs, + ) + # Wrapper macro around everything above, this is the primary API def nodejs_register_toolchains(name = DEFAULT_NODE_REPOSITORY, register = True, **kwargs): """Convenience macro for users which does typical setup.