Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

javascript: NodeJS bootstrapping via binary paths, PATH, asdf or nvm #18520

Merged
merged 17 commits into from Mar 20, 2023

Conversation

tobni
Copy link
Contributor

@tobni tobni commented Mar 16, 2023

Enables (nodejs dialect) semver version specification for NodeJs binary in the nodejs subsystem.

Also enables support for asdf and nvm binary installation discovery, along with $PATH discovery.

Addresses #16959.

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.check_version_constraints()
class ExternalToolOptionsMixin:
Copy link
Contributor Author

@tobni tobni Mar 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find much precedence for this kind of code reuse, but I'm not sure how else to fit the square "downloaded external tool" peg into the bootstrapping round hole, as the interfaces for TemplatedExternalTool just doesn't fit semver versions.

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with it. @thejcannon : you recently had to emulate ExternalTool without actually implementing it: is there any connection to what @tobni is doing here?

@@ -38,6 +38,7 @@ types-setuptools==62.6.1
types-toml==0.10.8
typing-extensions==4.3.0
mypy-typing-asserts==0.1.1
node-semver==0.9.0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 118 to 120
This option take precedence over the templated url download,
if a version matching the configured version range is found
in these paths.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes it less hermetic(I think?), but also what I think is most intuitive to users? I'm guessing here.

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, interesting. And the advantage to doing this is that it avoids the download? That's probably not necessary on an end user machine, but could make sense in CI. But in CI you could also imagine that somebody would be fine explicitly enabling a local search path (rather than having it on by default) for node as an optimization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the advantage to doing this is that it avoids the download?

Indeed. That, and a little bit of consistency across backend, what with go and python backends both defaulting to search_paths to find their runtimes.

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That, and a little bit of consistency across backend, what with go and python backends both defaulting to search_paths to find their runtimes.

While true, that has caused us no end of issues, heh. Hermetic by default would be quite nice: it's what we have for the java/scala backends.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flipping the switch is simple, so I'll do it!

Comment on lines +304 to +306
test=BinaryPathTest(
["--version"], fingerprint_stdout=False
), # Hack to retain version info
Copy link
Contributor Author

@tobni tobni Mar 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this too hacky? I'm annoyed by the prospect to have to iterate the paths again to call the node --version.

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it seems fine? AFAICT, fingerprint_stdout exists for cases where the output might be large.

Copy link
Contributor Author

@tobni tobni Mar 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More the name of the variable that gave me pause, I think. It's called "fingerprint" but is the --version output. Fingerprint usually makes me think "hash".

@@ -133,6 +142,8 @@ class EnvironmentAware(Subsystem.EnvironmentAware):

* `{AsdfPathString.STANDARD}`, {AsdfPathString.STANDARD.description("Node.js")}
* `{AsdfPathString.LOCAL}`, {AsdfPathString.LOCAL.description("binaries")}
* `<NVM>`, all NodeJS versions under $NVM_DIR/versions/node
* `<NVM_LOCAL>`, the nvm installation with the version in BUILD_ROOT/.nvmrc
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be possible to defer the version option to this file as well? Repeating the version in both pants.toml and .nvmrc (or .node-version, for that matter) seem like bad UX.

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be possible to defer the version option to this file as well?

Do you mean "infer"? Right now I don't think that it would be possible, because ExternalTool has the version as a class member.

Second best though would be to validate that both copies of the version are equal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, infer. I think I'll leave this as is for now if that's alright, validating the contents should probably happen in all backends with asdf support for example, and I think that work is a larger tangle.

Copy link
Sponsor Member

@stuhood stuhood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot!

Comment on lines 118 to 120
This option take precedence over the templated url download,
if a version matching the configured version range is found
in these paths.
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, interesting. And the advantage to doing this is that it avoids the download? That's probably not necessary on an end user machine, but could make sense in CI. But in CI you could also imagine that somebody would be fine explicitly enabling a local search path (rather than having it on by default) for node as an optimization.

@@ -133,6 +142,8 @@ class EnvironmentAware(Subsystem.EnvironmentAware):

* `{AsdfPathString.STANDARD}`, {AsdfPathString.STANDARD.description("Node.js")}
* `{AsdfPathString.LOCAL}`, {AsdfPathString.LOCAL.description("binaries")}
* `<NVM>`, all NodeJS versions under $NVM_DIR/versions/node
* `<NVM_LOCAL>`, the nvm installation with the version in BUILD_ROOT/.nvmrc
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be possible to defer the version option to this file as well?

Do you mean "infer"? Right now I don't think that it would be possible, because ExternalTool has the version as a class member.

Second best though would be to validate that both copies of the version are equal.

src/python/pants/backend/javascript/subsystems/nodejs.py Outdated Show resolved Hide resolved
Comment on lines +304 to +306
test=BinaryPathTest(
["--version"], fingerprint_stdout=False
), # Hack to retain version info
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it seems fine? AFAICT, fingerprint_stdout exists for cases where the output might be large.

src/python/pants/backend/javascript/subsystems/nodejs.py Outdated Show resolved Hide resolved
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.check_version_constraints()
class ExternalToolOptionsMixin:
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with it. @thejcannon : you recently had to emulate ExternalTool without actually implementing it: is there any connection to what @tobni is doing here?

src/python/pants/core/util_rules/search_paths.py Outdated Show resolved Hide resolved
@stuhood stuhood enabled auto-merge (squash) March 20, 2023 21:34
@stuhood stuhood merged commit 1477734 into pantsbuild:main Mar 20, 2023
17 checks passed
@tobni tobni deleted the add/nodejs-bootstrapping branch May 16, 2023 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants