Do you want to request a feature or report a bug?
Bug
What is the current behavior?
Yarn does not update changed global package binary paths when upgrading a package.
I changed the binary path in my package.json from:
// v0.2.10
"bin": {
"dodgem": "index.js"
}
to:
// v0.2.12
"bin": {
"dodgem": "src/app.js"
}
After upgrading the package, the symlink to the binary is not updated to reflect the new path in package.json.
Steps to reproduce
$ yarn global add [email protected]
success Installed "[email protected]" with binaries:
- dodgem
✨ Done in 10.39s.
$ dodgem --version
0.2.10
$ readlink /usr/local/bin/dodgem
../../../Users/jamie/.config/yarn/global/node_modules/dodgem/index.js
$ yarn global upgrade dodgem@latest
success Saved lockfile.
success Saved 1 new dependency.
└─ [email protected]
✨ Done in 1.89s.
$ dodgem --version
fish: Unknown command 'dodgem'
$ readlink /usr/local/bin/dodgem
../../../Users/jamie/.config/yarn/global/node_modules/dodgem/index.js
Uninstalling and re-installing the package shows the correct symlink:
$ yarn global remove dodgem
success Uninstalled packages.
✨ Done in 1.67s.
$ yarn global add dodgem
success Installed "[email protected]" with binaries:
- dodgem
✨ Done in 11.32s.
$ readlink /usr/local/bin/dodgem
../../../Users/jamie/.config/yarn/global/node_modules/dodgem/src/app.js
What is the expected behavior?
For the symlink to be updated to match the changed binary path.
Node 8.9.1
Yarn 1.3.2
macOS 10.13.1
Confirmed on 1.3.2.
~File ~src/cli/commands/global.js function initUpdateBins() has logic to not create bins if they already exist
// add new bins
for (const src of afterBins) {
if (beforeBins.has(src)) {
// already inserted
continue;
}
EDIT
The above assumption is incorrect. What yarn actually does is to create the correct link in
/Users/me/.config/yarn/global/node_modules/.bin/dodgem -> ../dodgem/index.js
We then create a "link to a link"
/usr/local/bin/dodgem -> /Users/me/.config/yarn/global/node_modules/.bin/dodgem
Now on upgrade, we leave the /usr/local/bin link in place and just update the first link:
/Users/me/.config/yarn/global/node_modules/.bin/dodgem -> ../dodgem/src/app.js
On the surface this looks like it would work fine, because
/usr/local/bin/dodgem
-> /Users/me/.config/yarn/global/node_modules/.bin/dodgem
-> ../dodgem/src/app.js
However, it seems that creating a "link to a link" doesn't actually make the link as specified, but links to the final location. So when we make the link:
/usr/local/bin/dodgem -> /Users/me/.config/yarn/global/node_modules/.bin/dodgem
what we _actually_ get on the OS filesystem is
/usr/local/bin/dodgem -> ../../../Users/me/.config/yarn/global/node_modules/dodgem/index.js
The upgrade process leaves the /usr/local/bin/dodgem link alone/unchanged with the assumption it is pointing to /Users/me/.config/yarn/global/node_modules/.bin/dodgem, but it isn't.
This behavior seems to come from Yarn itself. src/util/fs.js
// if destination exists
if (destStat) {
const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink();
...
if (bothSymlinks) {
const srcReallink = await readlink(src);
Since this is the case, I think the logic in src/cli/commands/global.js to skip update of existing links just needs to be removed.
Hi, I'm going to try to work on this issue on the next few weeks
Most helpful comment
Hi, I'm going to try to work on this issue on the next few weeks