From 994d24ddad4c1139d1ea3d5f94286f6d79b61f99 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Thu, 21 Mar 2019 13:43:46 -0700 Subject: [PATCH] fix: resolve symbol links until their are no more symbolic links Depending on your npm / yarn set up a global install may have to resolve through several symlinks before it correctly arrives the the baseDir that actually contains the other subcommands. The changes the resolution logic to resolve symlinks until their are no more to resolve by using realpath which will resolve links all the way to the final destination. --- index.js | 11 ++++------- test/fixtures/another-dir/pm | 1 + test/fixtures/other-dir/pm | 1 + test/test.command.executableSubcommand.js | 7 +++++++ test/test.command.executableSubcommandAlias.js | 7 +++++++ test/test.command.executableSubcommandDefault.js | 7 +++++++ 6 files changed, 27 insertions(+), 7 deletions(-) create mode 120000 test/fixtures/another-dir/pm create mode 120000 test/fixtures/other-dir/pm diff --git a/index.js b/index.js index 84436d8ea..06173c1a0 100644 --- a/index.js +++ b/index.js @@ -527,14 +527,11 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) { // In case of globally installed, get the base dir where executable // subcommand file should be located at - var baseDir, - link = fs.lstatSync(f).isSymbolicLink() ? fs.readlinkSync(f) : f; + var baseDir; - // when symbolink is relative path - if (link !== f && link.charAt(0) !== '/') { - link = path.join(dirname(f), link); - } - baseDir = dirname(link); + var resolvedLink = fs.realpathSync(f); + + baseDir = dirname(resolvedLink); // prefer local `./` to bin in the $PATH var localBin = path.join(baseDir, bin); diff --git a/test/fixtures/another-dir/pm b/test/fixtures/another-dir/pm new file mode 120000 index 000000000..9e8f71e18 --- /dev/null +++ b/test/fixtures/another-dir/pm @@ -0,0 +1 @@ +../other-dir/pm \ No newline at end of file diff --git a/test/fixtures/other-dir/pm b/test/fixtures/other-dir/pm new file mode 120000 index 000000000..d7569ef30 --- /dev/null +++ b/test/fixtures/other-dir/pm @@ -0,0 +1 @@ +../pm \ No newline at end of file diff --git a/test/test.command.executableSubcommand.js b/test/test.command.executableSubcommand.js index 2dae6b7bf..b9c720c04 100644 --- a/test/test.command.executableSubcommand.js +++ b/test/test.command.executableSubcommand.js @@ -34,3 +34,10 @@ var bin = path.join(__dirname, './fixtures/pmlink') exec(bin + ' install', function (error, stdout, stderr) { stdout.should.equal('install\n'); }); + +// when `bin` is a symbol link pointing at a symbolic for mocking global install +var bin = path.join(__dirname, './fixtures/another-dir/pm') +// success case +exec(bin + ' install', function (error, stdout, stderr) { + stdout.should.equal('install\n'); +}); diff --git a/test/test.command.executableSubcommandAlias.js b/test/test.command.executableSubcommandAlias.js index 6d03161eb..0bf1fb0f4 100644 --- a/test/test.command.executableSubcommandAlias.js +++ b/test/test.command.executableSubcommandAlias.js @@ -26,3 +26,10 @@ var bin = path.join(__dirname, './fixtures/pmlink') exec(bin + ' i', function (error, stdout, stderr) { stdout.should.equal('install\n'); }); + +// when `bin` is a symbol link pointing at a symbolic for mocking global install +var bin = path.join(__dirname, './fixtures/another-dir/pm') +// success case +exec(bin + ' install', function (error, stdout, stderr) { + stdout.should.equal('install\n'); +}); diff --git a/test/test.command.executableSubcommandDefault.js b/test/test.command.executableSubcommandDefault.js index 36796d867..cf6d773a8 100644 --- a/test/test.command.executableSubcommandDefault.js +++ b/test/test.command.executableSubcommandDefault.js @@ -44,3 +44,10 @@ var bin = path.join(__dirname, './fixtures/pmlink') exec(bin + ' install', function (error, stdout, stderr) { stdout.should.equal('install\n'); }); + +// when `bin` is a symbol link pointing at a symbolic for mocking global install +var bin = path.join(__dirname, './fixtures/another-dir/pm') +// success case +exec(bin + ' install', function (error, stdout, stderr) { + stdout.should.equal('install\n'); +});