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

[Bug] "yarn node" command sometimes uses wrong node.exe on Windows #1377

Closed
a-sore opened this issue May 20, 2020 · 2 comments · Fixed by #1403
Closed

[Bug] "yarn node" command sometimes uses wrong node.exe on Windows #1377

a-sore opened this issue May 20, 2020 · 2 comments · Fixed by #1403
Labels
bug Something isn't working

Comments

@a-sore
Copy link

a-sore commented May 20, 2020

yarn node sometimes doesn't resolve node.exe to the one Yarn was started with. This has only happened on Windows.

To Reproduce

  • Create any new yarn 2 project on Windows.
  • Run yarn node using a predefined path to node.exe and Yarn: e.g. ..\path-to-node\node.exe ..\path-to-yarn\yarn-berry.js node
  • If the supplied node.exe is not in the current directory, Yarn will use the first node.exe found in the user's PATH, instead of the one invoked by the user.

This means only this works properly: .\node.exe ..\path-to-yarn\yarn-berry.js node ...

This doesn't (uses node.exe from PATH): ..\any-other-path\node.exe ..\path-to-yarn\yarn-berry.js node ...

Environment

  • OS: Windows 10
  • Node version: irrelevant
  • Yarn version: 2.0.0-rc.30
@a-sore a-sore added the bug Something isn't working label May 20, 2020
@a-sore a-sore changed the title [Bug] "yarn node" command uses wrong node.exe on Windows [Bug] "yarn node" command sometimes uses wrong node.exe on Windows May 20, 2020
@bgotink
Copy link
Member

bgotink commented May 21, 2020

I've tested this and can reproduce it on PowerShell, though it works fine in git BASH.

Ignore the mention above, I thought it worked after a fix for another PR but I was testing in BASH.

Old (false) theory explaining the issue, see comment below instead ![screenshot of correct output in BASH and faulty output in PowerShell](https://user-images.githubusercontent.com/821510/82564016-556fea00-9b78-11ea-8a88-a19b02b05fbb.png)

The issue lies with PATHEXT. The windows shells CMD and PowerShell search all folders in the PATH not just for files matching the executable's name, but also for those matching the executable's name with one of the PATHEXT file extensions.
The final executable it runs isn't just defined by the order of the PATH, but also by the order of the PATHEXT.

C:\Some\Folder> yarn exec where node
C:\Users\User\AppData\Temp\xfs-hash\node <-- note, I'm running code with #1386 in it, so the if you use the master branch yarn will not log this line
C:\Users\User\AppData\Temp\xfs-hash\node.cmd
C:\Program Files\nodejs\node.exe

You'd think Windows will execute the first file it finds, but sadly the order of PATHEXT prevails over the order of PATH, and PATHEXT is

C:\Some\Folder> $Env:PATHEXT
.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW;.CPL

.EXE comes before .CMD, so the exe wins and gets executed.

C:\Some\Folder> node --version
14.3.0
C:\Some\Folder> C:\path\to\node-12\node --version
12.16.3

C:\Some\Folder> C:\path\to\node-12\node .yarn/releases/yarn-berry.js exec node --version
14.3.0
C:\Some\Folder> C:\path\to\node-12\node .yarn/releases/yarn-berry.js exec node.cmd --version
12.16.3

The reason it works if you have node.exe in the current folder is because CMD/PowerShell first look for <executable name>.exe in the current folder and only look in the PATH if that executable doesn't exist.

I'm going out on a limb here and say this is probably one of the reasons for npm's --scripts-prepend-node-path flag.

@bgotink
Copy link
Member

bgotink commented May 24, 2020

Okay, I've looked into this some more, and we're in a pretty unique situation.

First things first: I've opened moxystudio/node-cross-spawn#133 to fix this bug.

What exactly is going on?

Let's start with some context:

  • On Windows the PATH environment value isn't necessarily named PATH. Windows environment keys are case insensitive, so on my maching it's actually called Path.
    Yarn 2 is always using the PATH key when passing the environment into cross-spawn.
  • libuv can only spawn .exe or .com files on Windows. If we ask it to spawn node, it will completely ignore the node.cmd yarn puts on the PATH and use C:\Program Files\nodejs\node.exe instead.
  • cross-spawn resolves what file should be executed. If that file is not a .exe or .com file, cross-spawn will actually spawn cmd.exe which then executes the actual command.

What's happening?

  1. Because cross-spawn didn't pass in the environment we pass into its options into the path-key package, that uses process.env to detect the name of the PATH environment variable.
    On my system that results in Path.
  2. However, options.env.Path is undefined (we pass in options.env.PATH instead). So the call to which to look up node gets passed an undefined path, which makes it fall back to the PATH environment variable in process.env (in this case process.env.Path).
  3. This PATH doesn't contain the temporary folder yarn has created, so which actually resolves node to C:\Program Files\nodejs\node.exe.
  4. cross-spawn then thinks "okay, that's an .exe, I don't need to wrap that with cmd.exe."
  5. Node's child_process is asked to spawn node directly, which asks libuv to spawn node.
  6. libuv only looks for node.exe and node.com on the PATH, so it ignores our node.cmd and executes C:\Program Files\nodejs\node.exe instead

bgotink added a commit to bgotink/berry that referenced this issue May 25, 2020
This version fixes a bug where node was resolved to
the wrong binary on Windows, resulting in the wrong
version of node being called if yarn is executed
with a node version that's not the first node on
the PATH.

Fixes yarnpkg#1377
arcanis pushed a commit that referenced this issue May 26, 2020
* Update cross-spawn

This version fixes a bug where node was resolved to
the wrong binary on Windows, resulting in the wrong
version of node being called if yarn is executed
with a node version that's not the first node on
the PATH.

Fixes #1377

* chore: update lockfile

* chore: update cache

Co-authored-by: merceyz <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants