Skip to content
This repository has been archived by the owner on Aug 11, 2022. It is now read-only.

Commit

Permalink
deps: Allow partial and full disabling of flat trees
Browse files Browse the repository at this point in the history
PR-URL: #10337
Credit: @iarna
Reviewed By: @othiym23
  • Loading branch information
iarna committed Nov 20, 2015
1 parent 3c1960a commit 231c58a
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 0 deletions.
10 changes: 10 additions & 0 deletions doc/cli/npm-install.md
Expand Up @@ -257,6 +257,16 @@ local copy exists on disk.
The `-g` or `--global` argument will cause npm to install the package globally
rather than locally. See `npm-folders(5)`.

The `--global-style` argument will cause npm to install the package into
your local `node_modules` folder with the same layout it uses with the
global `node_modules` folder. Only your direct dependencies will show in
`node_modules` and everything they depend on will be flattened in their
`node_modules` folders. This obviously will elminate some deduping.

The `--legacy-bundling` argument will cause npm to install the package such
that versions of npm prior to 1.4, such as the one included with node 0.8,
can install the package. This eliminates all automatic deduping.

The `--link` argument will cause npm to link global installs into the
local space in some cases.

Expand Down
22 changes: 22 additions & 0 deletions doc/misc/npm-config.md
Expand Up @@ -385,6 +385,18 @@ Operates in "global" mode, so that packages are installed into the

The config file to read for global config options.

### global-style

* Default: false
* Type: Boolean

Causes npm to install the package into your local `node_modules` folder with
the same layout it uses with the global `node_modules` folder. Only your
direct dependencies will show in `node_modules` and everything they depend
on will be flattened in their `node_modules` folders. This obviously will
elminate some deduping. If used with `legacy-bundling`, `legacy-bundling` will be
preferred.

### group

* Default: GID of the current process
Expand Down Expand Up @@ -491,6 +503,16 @@ change. Only the output from `npm ls --json` is currently valid.

A client key to pass when accessing the registry.

### legacy-bundling

* Default: false
* Type: Boolean

Causes npm to install the package such that versions of npm prior to 1.4,
such as the one included with node 0.8, can install the package. This
eliminates all automatic deduping. If used with `global-style` this option
will be preferred.

### link

* Default: false
Expand Down
4 changes: 4 additions & 0 deletions lib/config/defaults.js
Expand Up @@ -145,6 +145,7 @@ Object.defineProperty(exports, 'defaults', {get: function () {

global: false,
globalconfig: path.resolve(globalPrefix, 'etc', 'npmrc'),
'global-style': false,
group: process.platform === 'win32' ? 0
: process.env.SUDO_GID || (process.getgid && process.getgid()),
heading: 'npm',
Expand All @@ -158,6 +159,7 @@ Object.defineProperty(exports, 'defaults', {get: function () {
'init-license': 'ISC',
json: false,
key: null,
'legacy-bundling': false,
link: false,
'local-address': undefined,
loglevel: 'warn',
Expand Down Expand Up @@ -251,6 +253,7 @@ exports.types = {
'git-tag-version': Boolean,
global: Boolean,
globalconfig: path,
'global-style': Boolean,
group: [Number, String],
'https-proxy': [null, url],
'user-agent': String,
Expand All @@ -265,6 +268,7 @@ exports.types = {
'init-version': semver,
json: Boolean,
key: [null, String],
'legacy-bundling': Boolean,
link: Boolean,
// local-address must be listed as an IP for a local network interface
// must be IPv4 due to node bug
Expand Down
3 changes: 3 additions & 0 deletions lib/install/deps.js
Expand Up @@ -577,5 +577,8 @@ var earliestInstallable = exports.earliestInstallable = function (requiredBy, tr
if (!tree.parent) return tree
if (tree.isGlobal) return tree

if (npm.config.get('global-style') && !tree.parent.parent) return tree
if (npm.config.get('legacy-bundling')) return tree

return (earliestInstallable(requiredBy, tree.parent, pkg) || tree)
}
116 changes: 116 additions & 0 deletions test/tap/tree-style.js
@@ -0,0 +1,116 @@
'use strict'
var test = require('tap').test
var path = require('path')
var mkdirp = require('mkdirp')
var rimraf = require('rimraf')
var fs = require('graceful-fs')
var common = require('../common-tap')

var base = path.resolve(__dirname, path.basename(__filename, '.js'))
var modA = path.resolve(base, 'modA')
var modB = path.resolve(base, 'modB')
var modC = path.resolve(base, 'modC')
var testNormal = path.resolve(base, 'testNormal')
var testGlobal = path.resolve(base, 'testGlobal')
var testLegacy = path.resolve(base, 'testLegacy')

var json = {
'name': 'test-tree-style',
'version': '1.0.0',
'dependencies': {
'modA': modA
}
}

var modAJson = {
'name': 'modA',
'version': '1.0.0',
'dependencies': {
'modB': modB
}
}

var modBJson = {
'name': 'modB',
'version': '1.0.0',
'dependencies': {
'modC': modC
}
}

var modCJson = {
'name': 'modC',
'version': '1.0.0'
}

function modJoin () {
var modules = Array.prototype.slice.call(arguments)
return modules.reduce(function (a, b) {
return path.resolve(a, 'node_modules', b)
})
}

function writeJson (mod, data) {
fs.writeFileSync(path.resolve(mod, 'package.json'), JSON.stringify(data))
}

function setup () {
cleanup()
;[modA, modB, modC, testNormal, testGlobal, testLegacy].forEach(function (mod) {
mkdirp.sync(mod)
})
writeJson(modA, modAJson)
writeJson(modB, modBJson)
writeJson(modC, modCJson)
;[testNormal, testGlobal, testLegacy].forEach(function (mod) { writeJson(mod, json) })
}

function cleanup () {
rimraf.sync(base)
}

test('setup', function (t) {
setup()
t.end()
})

function exists (t, filepath, msg) {
try {
fs.statSync(filepath)
t.pass(msg)
return true
} catch (ex) {
t.fail(msg, {found: null, wanted: 'exists', compare: 'fs.stat(' + filepath + ')'})
return false
}
}

test('tree-style', function (t) {
t.plan(12)
common.npm(['install'], {cwd: testNormal}, function (err, code, stdout, stderr) {
if (err) throw err
t.is(code, 0, 'normal install; result code')
t.is(stderr, '', 'normal install; no errors')
exists(t, modJoin(testNormal, 'modA'), 'normal install; module A')
exists(t, modJoin(testNormal, 'modB'), 'normal install; module B')
exists(t, modJoin(testNormal, 'modC'), 'normal install; module C')
})
common.npm(['install', '--global-style'], {cwd: testGlobal}, function (err, code, stdout, stderr) {
if (err) throw err
t.is(code, 0, 'global-style install; result code')
t.is(stderr, '', 'global-style install; no errors')
exists(t, modJoin(testGlobal, 'modA', 'modB'), 'global-style install; module B')
exists(t, modJoin(testGlobal, 'modA', 'modC'), 'global-style install; module C')
})
common.npm(['install', '--legacy-bundling'], {cwd: testLegacy}, function (err, code, stdout, stderr) {
if (err) throw err
t.is(code, 0, 'legacy-bundling install; result code')
t.is(stderr, '', 'legacy-bundling install; no errors')
exists(t, modJoin(testLegacy, 'modA', 'modB', 'modC'), 'legacy-bundling install; module C')
})
})

test('cleanup', function (t) {
cleanup()
t.end()
})

0 comments on commit 231c58a

Please sign in to comment.