Yarn: Global binary path symlink not updated on package upgrade

Created on 16 Nov 2017  Â·  3Comments  Â·  Source: yarnpkg/yarn

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.

Environment Versions
Node   8.9.1
Yarn   1.3.2
macOS  10.13.1
cat-bug good first issue help wanted triaged

Most helpful comment

Hi, I'm going to try to work on this issue on the next few weeks

All 3 comments

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

Was this page helpful?
0 / 5 - 0 ratings