nvm
nvm copied to clipboard
`npm` produces escape sequences that `nvm` should filter out when not a tty
i.e. avoid using it on non-interactive or non-login shells
There is a big problem with the usage of .bashrc for outputing escape sequences (as-is), because it can corrupt the communication of other tools that are doing non-login SSH sessions (yes, some even use an interactive shell for non-interactive use). One of such problems we have with Ansible (see ansible/ansible#14282), but the same could happen to other tools.
So my prefered solution is to avoid using .bashrc to ensure we have a login-shell. But you may also want to ensure that you have an interactive shell before appending your own stuff. So I added that snippet as well. I am not sure if this would work on all distributions, so please test !
References: https://www.gnu.org/software/bash/manual/html_node/Is-this-Shell-Interactive_003f.html http://superuser.com/questions/183870/difference-between-bashrc-and-bash-profile
All of these files are intentional - we have had many more users complaining of nvm not being available on a shell - interactive or otherwise, login or otherwise - and you're the first user to have this specific problem.
Detecting PS1 - can you confirm that works on dash, sh, ksh, zsh, and bash? But also, the lack of a terminal prompt does not mean nvm commands shouldn't work - for example, all of travis-ci I believe would fail this test, since it's used non-interactively.
I would prefer a specific troubleshooting note added to the README that handles the design choice in ansible, rather than breaking use cases for the majority of nvm users.
The same issue with Ansible+NVM and weird/corrupted paths with ANSI escape characters brought me here. My team and I upgraded from NVM 0.25.4 to 0.31.0 and ran into this. Why would sourcing nvm.sh have any output at all, ANSI escape sequences or otherwise? I'd be happy leaving it in .bashrc, as long as it doesn't have any output. Thanks.
Looking at the escape sequences being sent, it is related to cursor properties (show cursor CSI ?25h), cursor placement (CSI 0G) and line-erasure (CSI K). The sequence is repeated twice in the ansible output.
@skehlet i'm not sure how that's relevant to this issue - sourcing nvm should have no output at all. The linked ansible issue seems to be that their prompt is set in bashrc.
@ljharb In two separate cases, removing nvm fixed the issue.
@dagwieers i don't see any output, so it's hard for me to reproduce. If you can help me pin down which line(s) of nvm.sh are producing any output to stdout/stderr on the sourcing path, i'll happily fix them.
@ljharb I am not an nvm or node user. Clearly the source code does not produce these escape sequences itself (I only see colors used when asked for the version), but I am wondering of any of the used tools could produce them ? I see nvm using various tools (curl, wget, npm) ? I wouldn't expect curl or wget to produce them, but maybe npm ?
@dagwieers that's all possible, but i also pipe all output to dev/null pretty aggressively in the sourcing path, so control characters should be silenced too :-/
Ok, it wasn't that hard. npm is indeed doing ANSI escape codes from:
https://github.com/npm/npm/blob/master/node_modules/npmlog/node_modules/ansi/lib/ansi.js#L38
And the codes we are seeing related to cursor control are part of these.
ok thanks, that's definitely going to help me track them down. Do you know a non-ansible way I can detect, from the command line, when these codes are present?
And here you can see the exact sequence being played:
https://github.com/npm/npm/blob/master/node_modules/npmlog/node_modules/gauge/progress-bar.js#L101
No, it's quite possible that it depends on a specific code path (that may not be the regular code path). You know best what nvm does by default, and in specific use-cases.
@ljharb For example, I see you do this:
NPMLIST=$(nvm use system > /dev/null && npm list -g --depth=0 2> /dev/null | command tail -n +2)
so $NPMLIST could theoretically contain escape sequences. (It shouldn't because there is no tty)
Now mind you that normally npm would not be generating escape sequences when there is no tty, but Ansible unfortunately creates a pseudo tty, which triggeres this kind behaviour in tools. So if you'd be piping the npm output somewhere, you will not be seeing escape sequences...
Ok, I think I found it:
https://github.com/npm/npm/blob/master/node_modules/npmlog/log.js#L98
The function log.clearProgress() is called from all over the place and will play the escape sequence we are talking about.
[dag@moria npm]$ grep -r clearProgress .
./lib/shrinkwrap.js: log.clearProgress()
./lib/install.js: log.clearProgress()
./lib/install.js: log.clearProgress()
./lib/build.js: log.clearProgress()
./lib/publish.js: log.clearProgress()
./lib/link.js: log.clearProgress()
./lib/link.js: log.clearProgress()
./lib/utils/lifecycle.js: log.clearProgress()
./lib/rebuild.js: log.clearProgress()
./lib/unbuild.js: log.clearProgress()
So it is quite likely that these escape sequences are poluting output nvm is producing. I wonder if there is a way to filter out escape sequences in Bash. Far easier would be if npm would have an option to disable escape sequences. Or you could try doing: TERM=dumb npm ...
<3 thanks for the legwork!
Fantastic detective work @dagwieers, thank you.
@dagwieers could you check the "allow edits" checkbox on the RHS of the PR?
ping @dagwieers