diff --git a/lib/install/inflate-shrinkwrap.js b/lib/install/inflate-shrinkwrap.js index bf1ab7065724c..395cc11191309 100644 --- a/lib/install/inflate-shrinkwrap.js +++ b/lib/install/inflate-shrinkwrap.js @@ -177,7 +177,7 @@ function makeFakeChild (name, topPath, tree, sw, requested) { realpath: requested.type === 'directory' ? requested.fetchSpec : childPath(tree.realpath, pkg), location: (tree.location === '/' ? '' : tree.location + '/') + pkg.name, isLink: requested.type === 'directory', - isInLink: tree.isLink, + isInLink: tree.isLink || tree.isInLink, swRequires: sw.requires }) tree.children.push(child) diff --git a/lib/shrinkwrap.js b/lib/shrinkwrap.js index 90a4426523cab..5495892a25afb 100644 --- a/lib/shrinkwrap.js +++ b/lib/shrinkwrap.js @@ -110,11 +110,13 @@ function shrinkwrapDeps (deps, top, tree, seen) { var childIsOnlyDev = isOnlyDev(child) var pkginfo = deps[moduleName(child)] = {} var requested = getRequested(child) || child.package._requested || {} + var linked = child.isLink || child.isInLink + var linkedFromHere = linked && path.relative(top.realpath, child.realpath)[0] !== '.' pkginfo.version = childVersion(top, child, requested) if (requested.type === 'git' && child.package._from) { pkginfo.from = child.package._from } - if (child.fromBundle || child.isInLink) { + if (child.fromBundle && !linked) { pkginfo.bundled = true } else { if (isRegistry(requested)) { @@ -139,7 +141,8 @@ function shrinkwrapDeps (deps, top, tree, seen) { pkginfo.requires[moduleName(required)] = childRequested(top, required, requested) }) } - if (child.children.length) { + // iterate into children on non-links and links contained within the top level package + if (child.children.length && (!child.isLink || linkedFromHere)) { pkginfo.dependencies = {} shrinkwrapDeps(pkginfo.dependencies, top, child, seen) } diff --git a/test/tap/install-at-sub-path-locally.js b/test/tap/install-at-sub-path-locally.js new file mode 100644 index 0000000000000..e16b75179ebaf --- /dev/null +++ b/test/tap/install-at-sub-path-locally.js @@ -0,0 +1,69 @@ +var fs = require('graceful-fs') +var path = require('path') + +var mkdirp = require('mkdirp') +var osenv = require('osenv') +var rimraf = require('rimraf') +var test = require('tap').test + +var common = require('../common-tap.js') + +var pkg = path.join(__dirname, 'install-at-sub-path-locally') + +var EXEC_OPTS = { cwd: pkg, stdio: [0, 1, 2] } + +var json = { + name: 'install-at-sub-path-locally-mock', + version: '0.0.0' +} + +var target = '../package@1.2.3' + +test('setup', function (t) { + cleanup() + t.end() +}) + +test('\'npm install ../package@1.2.3\' should install local pkg from sub path', function (t) { + setup() + common.npm(['install', '--loglevel=silent', target], EXEC_OPTS, function (err, code) { + if (err) throw err + var p = path.resolve(pkg, 'node_modules/install-at-sub-path-locally-mock/package.json') + t.equal(code, 0, 'npm install exited with code') + t.ok(JSON.parse(fs.readFileSync(p, 'utf8'))) + t.end() + }) +}) + +test('\'running npm install ../package@1.2.3\' should not break on sub path re-install', function (t) { + common.npm(['install', '--loglevel=silent', target], EXEC_OPTS, function (err, code) { + if (err) throw err + var p = path.resolve(pkg, 'node_modules/install-at-sub-path-locally-mock/package.json') + t.equal(code, 0, 'npm install exited with code') + t.ok(JSON.parse(fs.readFileSync(p, 'utf8'))) + t.end() + }) +}) + +test('cleanup', function (t) { + cleanup() + t.end() +}) + +function cleanup () { + process.chdir(osenv.tmpdir()) + rimraf.sync(pkg) + rimraf.sync(path.resolve(pkg, target)) +} + +function setup () { + cleanup() + var root = path.resolve(pkg, target) + mkdirp.sync(root) + fs.writeFileSync( + path.join(root, 'package.json'), + JSON.stringify(json, null, 2) + ) + mkdirp.sync(path.resolve(pkg, 'node_modules')) + process.chdir(pkg) +} diff --git a/test/tap/shrinkwrap-local-dependency.js b/test/tap/shrinkwrap-local-dependency.js index 58974ad72431a..d1c33b99a5a0b 100644 --- a/test/tap/shrinkwrap-local-dependency.js +++ b/test/tap/shrinkwrap-local-dependency.js @@ -20,8 +20,7 @@ var shrinkwrap = { version: 'file:' + unixFormatPath(path.join('mods', 'mod2')), dependencies: { mod1: { - version: 'file:' + unixFormatPath(path.join('mods', 'mod1')), - bundled: true + version: 'file:' + unixFormatPath(path.join('mods', 'mod1')) } } } diff --git a/test/tap/spec-local-specifiers.js b/test/tap/spec-local-specifiers.js index d149b7ea0ea3a..3601eee5f3c5f 100644 --- a/test/tap/spec-local-specifiers.js +++ b/test/tap/spec-local-specifiers.js @@ -585,9 +585,7 @@ test('save behavior', function (t) { var deps = pjson.dependencies || {} t.is(deps['sb-transitive'], 'file:../sb-transitive', 'package.json') var sdep = shrinkwrap.dependencies['sb-transitive'] || {} - var tdep = sdep.dependencies.sbta - t.like(tdep, {bundled: true, version: 'file:../sb-transitive/sbta'}, 'npm-shrinkwrap.json transitive dep') - t.like(sdep, {bundled: null, version: 'file:../sb-transitive'}, 'npm-shrinkwrap.json direct dep') + t.like(sdep, {bundled: null, dependencies: null, version: 'file:../sb-transitive'}, 'npm-shrinkwrap.json direct dep') t.done() }) })