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
language/node: adjustments for npm 5.0.x #2710
Conversation
CC @MikeMcQuaid @ilovezfs @chrmoritz @JCount @dunn and possibly @zkat if you want to keep an eye on this side of the discussion as well. |
So were you able to determine whether @chrmoritz is correct that this can cause e.g. .brew_home to end up getting installed? |
It's not there for me. Perhaps because alexjs tree
|
@chrmoritz was saying it's dependent on whether the files to install happen to be specifically whitelisted or not: Homebrew/homebrew-core#14085 (comment) |
So far it hasn't appeared in any of:
|
@DomT4 yeah, I'm pretty skeptical that, even if it's true in some cases, that it would actually be a regression as opposed to preexisting behavior since upstream has said in more than one place that pack+install is the same as the old install, but obviously @chrmoritz knows more about the topic than I do by a mile. |
I'm down to |
Do we know if this new behavior (i.e. running pack first) is backwards compatible with the prior versions of npm < 5? |
Library/Homebrew/language/node.rb
Outdated
--verbose | ||
--global | ||
--prefix=#{libexec} | ||
#{Dir.pwd}/#{Utils.popen_read("npm pack").chomp} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It used to be possible to use std_npm_install_args
with an arbitrary package name by doing something like
args = std_npm_install_args(libexec/"vendor") << "foo@2"
system "npm", "install", *args
but now it looks like that won't be possible.
Admittedly, I don't think that behavior is actually used in core currently, but I'm wondering if we should allow an optional second argument with arbitrary package name(s), or a splat argument for any additional parameters, or something else along those lines, so that the node language module doesn't lose the flexibility it currently has. (i.e., if second arg is nil, do the pack magic, otherwise pass the parameters along and don't do pack magic.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure this was possible? Would std_npm_install_args(libexec/"vendor") << "foo@2"
really overide the "."
paramater which tells npm to install the local folder (or at least told before npm@5)?
I think it would just tell npm to install BOTH the local folder = "."
AND foo@2
and if couldn't find a valid node module in the current working directory it would error out early.
I don't think that such a hacky behavior (installing the module at the current local folder and an other named module) is something we want to support here. Also it looks to contradict against the homebrew philosopy that foo should be vendored as a resource too in such a use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The package name actually went first in the example I was recalling, where this did work:
system "npm", "install", "yarn", *Language::Node.std_npm_install_args(buildpath/"vendor/yarn")
system buildpath/"vendor/yarn/bin/yarn", "install"
Also it looks to contradict against the homebrew philosopy that foo should be vendored as a resource too in such a use case.
We have an exception for things installed via other trusted package managers (e.g. venv.pip_install, cabal_install, etc.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this will work, but it will install BOTH yarn and the module at the current working directory to buildpath/"vendor/yarn"
which is not what you would expect from it (the installing the module at the cwd too part) and it will only work if the cwd is a valid node module.
Just do a npm install grunt-cli -g --verbose .
from a cwd which is not a node module to confirm this.
It's more like a very dirty hack using the API for something it was not meant to be used to. Supporting such a use case by adding a third global_npm_install_args
(which does the right thing without installing the cwd as a module too) should be a much cleaner way to do so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Supporting such a use case by adding a third global_npm_install_args (which does the right thing without installing the cwd as a module too) should be a much cleaner way to do so.
Yes, that would probably be a nice thing to have at some point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should have some sort of error handling for the case where npm pack
fails. Run Utils.popen_read("npm pack")
before interpolation and check the exit code with $?
.
I said
It should be beackwarts compatible to at least npm@3, because it's basicaly the exact same thing our npm install folder call has done before unter the hood. (see this comment) |
When would that occur and how does moving it make any difference? |
When a module author would decide to not use this optional field and rely on the default package everything except stuff in
Because now |
Makes sense now. |
Library/Homebrew/language/node.rb
Outdated
--verbose | ||
--global | ||
--prefix=#{libexec} | ||
#{Dir.pwd}/#{Utils.popen_read("npm pack").chomp} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should have some sort of error handling for the case where npm pack
fails. Run Utils.popen_read("npm pack")
before interpolation and check the exit code with $?
.
I can't comment on Mike's request for changes directly, so I'll note here that yes, I'll look at that. |
Thanks, @DomT4! |
Changes pushed here. Let me know how much y'all hate it 😸 |
Library/Homebrew/language/node.rb
Outdated
Utils.popen_read("npm pack").chomp | ||
return if $?.exitstatus.zero? | ||
raise "npm failed to pack #{Dir.pwd}" | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this still actually return the tarball path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
irb(main):001:0> def foo
irb(main):002:1> 3
irb(main):003:1> return if 1 == 1
irb(main):004:1> end
=> :foo
irb(main):005:0> foo
=> nil
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not returning the variable, aye. Boo. So much for being lazy I guess 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be able to use a lambda
I guess. Maybe. Will check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or I could just turn the Utils.popen_read
into a block. I might try that. That feels sane. I've been thinking about this too long today & now my mind is sludge 😆
Nope. This doesn't |
I return, with a fresh push, which actually seems to work as intended now. I took some inspiration from |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Final nits but almost there. Thanks again @DomT4!
Library/Homebrew/language/node.rb
Outdated
# create and install real directories when passed a file path. We can | ||
# restore the old behaviour by packing the path first with "npm pack" | ||
# which also helpfully spits out the filename it just created allowing | ||
# us to pass that as the final argument. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can trim this comment such that it doesn't reference the old behaviour; future people looking at this comment will want to know what it does and why it's necessary but doesn't really say that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically this comment should answer the question: "why do we need to run npm pack
at all?" I don't understand the answer to that despite having read most of the conversation and definitely not just from this code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. I don't know how to explain it with brevity really, it's a fairly big change.
Essentially when you used to npm install some-directory --global --prefix="blah"
you could then dispose of your build directory & purely retain the end product, the "blah" prefix in this example. From the new npm
if you pass it a directory to install it only installs symlinks back to that directory in the "blah" prefix, which doesn't work for Homebrew since we trash buildpath
s/testpath
s the second we're done with 'em normally.
npm pack
is supported as an upstream way of retaining the old behaviour Homebrew relies on to be able to sensibly package npm
-using formulae.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, something like npm pack is needed to make a "clean" installation to a new directory i.e. not just install symlinks back to the source directory in the buildpath
will do
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about:
# Homebrew assumes the buildpath/testpath will always be disposable
# and from npm 5.0.0 the logic changed so that when a directory is
# fed to `npm install` only symlinks are created linking back to that
# directory, consequently breaking that assumption. We require a tarball
# because npm install creates a "real" installation when fed a tarball.
But not sure if that's still too wordy/full/etc.
Library/Homebrew/language/node.rb
Outdated
end | ||
|
||
def self.std_npm_install_args(libexec) | ||
setup_npm_environment | ||
# tell npm to not install .brew_home by adding it to the .npmignore file | ||
# (or creating a new one if no .npmignore file already exists) | ||
open(".npmignore", "a") { |f| f.write("\n.brew_home\n") } | ||
pack = pack_for_installation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pedantry but I'd add a newline above this because the comment doesn't seem to reference it but yet it feels related.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, no worries.
When the time comes to roll here, ideally, we probably want:
I think that makes logical sense. |
Going to bed by any maintainer can feel free to merge this in the order Dom says above when green. I want to wait a bit after merge before cutting a new tag, though, just to make sure there's not other bugs there. |
🚢'd Thanks @DomT4 |
Thanks @ilovezfs ❤️. This side of the changes proved relatively painless, thankfully. Or at least, so far 😄. |
Don't jinx it. |
🤐 |
brew tests
with your changes locally? (It dies, but for very unrelated reasons as far as I can see.)Goes with: Homebrew/homebrew-core#14085