From 3724d2a9fb5a0f59c82f961023f5a7e8478e04c1 Mon Sep 17 00:00:00 2001 From: nlf Date: Wed, 10 Feb 2021 11:41:12 -0800 Subject: [PATCH] use the idealtree target path if it exists This ensures relpaths are from the correct root PR-URL: https://github.com/npm/arborist/pull/224 Credit: @nlf Close: #224 Reviewed-by: @wraithgar, @ruyadorno --- lib/arborist/build-ideal-tree.js | 3 +- ...t-arborist-build-ideal-tree.js-TAP.test.js | 40 +++++++++++++++++++ test/arborist/build-ideal-tree.js | 28 ++++++++++++- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/lib/arborist/build-ideal-tree.js b/lib/arborist/build-ideal-tree.js index 4c2665021..810af85b1 100644 --- a/lib/arborist/build-ideal-tree.js +++ b/lib/arborist/build-ideal-tree.js @@ -491,7 +491,8 @@ module.exports = cls => class IdealTreeBuilder extends cls { /* istanbul ignore else - should also be covered by realpath failure */ if (filepath) { const { name } = spec - spec = npa(`file:${relpath(this.path, filepath)}`, this.path) + const tree = this.idealTree.target || this.idealTree + spec = npa(`file:${relpath(tree.path, filepath)}`, tree.path) spec.name = name } return spec diff --git a/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js b/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js index 8c46e23fb..e6b550e13 100644 --- a/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js +++ b/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js @@ -315,6 +315,46 @@ ArboristNode { } ` +exports[`test/arborist/build-ideal-tree.js TAP adding tarball to global prefix that is a symlink at a different path depth > must match snapshot 1`] = ` +ArboristLink { + "location": "../another-path/global-root", + "name": "global-root", + "path": "{CWD}/test/arborist/build-ideal-tree-adding-tarball-to-global-prefix-that-is-a-symlink-at-a-different-path-depth/another-path/global-root", + "realpath": "{CWD}/test/arborist/build-ideal-tree-adding-tarball-to-global-prefix-that-is-a-symlink-at-a-different-path-depth/real-root", + "resolved": "file:../real-root", + "target": ArboristNode { + "children": Map { + "mkdirp" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "mkdirp", + "spec": "file:../../../fixtures/registry-mocks/content/mkdirp/-/mkdirp-1.0.2.tgz", + "type": "prod", + }, + }, + "location": "node_modules/mkdirp", + "name": "mkdirp", + "path": "{CWD}/test/arborist/build-ideal-tree-adding-tarball-to-global-prefix-that-is-a-symlink-at-a-different-path-depth/real-root/node_modules/mkdirp", + "resolved": "file:{CWD}/test/fixtures/registry-mocks/content/mkdirp/-/mkdirp-1.0.2.tgz", + "version": "1.0.2", + }, + }, + "edgesOut": Map { + "mkdirp" => EdgeOut { + "name": "mkdirp", + "spec": "file:../../../fixtures/registry-mocks/content/mkdirp/-/mkdirp-1.0.2.tgz", + "to": "node_modules/mkdirp", + "type": "prod", + }, + }, + "location": "", + "name": "real-root", + "path": "{CWD}/test/arborist/build-ideal-tree-adding-tarball-to-global-prefix-that-is-a-symlink-at-a-different-path-depth/real-root", + }, +} +` + exports[`test/arborist/build-ideal-tree.js TAP allow updating when peer outside of explicit update set conflict, but resolves appropriately with --force > succeed if force applied 1`] = ` ArboristNode { "children": Map { diff --git a/test/arborist/build-ideal-tree.js b/test/arborist/build-ideal-tree.js index 1835f1902..fa99d374f 100644 --- a/test/arborist/build-ideal-tree.js +++ b/test/arborist/build-ideal-tree.js @@ -1,4 +1,4 @@ -const {basename, resolve} = require('path') +const {basename, resolve, relative} = require('path') const t = require('tap') const Arborist = require('../..') const fixtures = resolve(__dirname, '../fixtures') @@ -1236,6 +1236,32 @@ t.test('workspaces', t => { t.end() }) +t.test('adding tarball to global prefix that is a symlink at a different path depth', async t => { + const fixt = t.testdir({ + 'real-root': {}, + 'another-path': { + 'global-root': t.fixture('symlink', '../real-root'), + }, + }) + const path = resolve(fixt, 'another-path/global-root') + const arb = new Arborist({ + path, + global: true, + ...OPT, + }) + + const tarballpath = resolve(__dirname, '../fixtures/registry-mocks/content/mkdirp/-/mkdirp-1.0.2.tgz') + const tree = await arb.buildIdealTree({ + path, + global: true, + add: [ + // this will be a relative path to the tarball above + relative(process.cwd(), tarballpath), + ], + }) + t.matchSnapshot(printTree(tree)) +}) + t.test('add symlink that points to a symlink', t => { const fixt = t.testdir({ 'global-prefix': {