diff options
author | isaacs <i@izs.me> | 2014-05-14 04:44:56 +0400 |
---|---|---|
committer | isaacs <i@izs.me> | 2014-05-14 23:41:32 +0400 |
commit | 1707fcedb7503251eb77719aba7ac52931721205 (patch) | |
tree | 2dbb06489bdb58ecbb02d96464e0ce430b6675fd | |
parent | 08e0b101f3190d9548a6530096844674b16ce8d7 (diff) |
npmconf@1.0.0, Refactor config/uid/prefix loading process
Closes #4751
-rw-r--r-- | lib/npm.js | 126 | ||||
-rw-r--r-- | node_modules/npmconf/lib/find-prefix.js (renamed from lib/utils/find-prefix.js) | 5 | ||||
-rw-r--r-- | node_modules/npmconf/lib/load-prefix.js | 51 | ||||
-rw-r--r-- | node_modules/npmconf/lib/load-uid.js | 15 | ||||
-rw-r--r-- | node_modules/npmconf/lib/set-user.js | 23 | ||||
-rw-r--r-- | node_modules/npmconf/npmconf.js | 103 | ||||
-rw-r--r-- | node_modules/npmconf/package.json | 13 | ||||
-rw-r--r-- | node_modules/npmconf/test/basic.js | 13 | ||||
-rw-r--r-- | node_modules/npmconf/test/builtin.js | 13 | ||||
-rw-r--r-- | node_modules/npmconf/test/fixtures/.npmrc | 1 | ||||
-rw-r--r-- | node_modules/npmconf/test/fixtures/package.json | 0 | ||||
-rw-r--r-- | node_modules/npmconf/test/project.js | 85 | ||||
-rw-r--r-- | package.json | 3 |
13 files changed, 285 insertions, 166 deletions
diff --git a/lib/npm.js b/lib/npm.js index d1932a1e4..c0c744f99 100644 --- a/lib/npm.js +++ b/lib/npm.js @@ -24,11 +24,6 @@ var EventEmitter = require("events").EventEmitter , abbrev = require("abbrev") , which = require("which") , semver = require("semver") - , findPrefix = require("./utils/find-prefix.js") - , getUid = require("uid-number") - , mkdirp = require("mkdirp") - , slide = require("slide") - , chain = slide.chain , RegClient = require("npm-registry-client") , charSpin = require("char-spinner") @@ -42,23 +37,6 @@ npm.config = { } } -// /usr/local is often a read-only fs, which is not -// well handled by node or mkdirp. Just double-check -// in the case of errors when making the prefix dirs. -function mkdir (p, cb) { - mkdirp(p, function (er, made) { - // it could be that we couldn't create it, because it - // already exists, and is on a read-only fs. - if (er) { - return fs.stat(p, function (er2, st) { - if (er2 || !st.isDirectory()) return cb(er) - return cb(null, made) - }) - } - return cb(er, made) - }) -} - npm.commands = {} try { @@ -370,118 +348,24 @@ function load (npm, cli, cb) { // at this point the configs are all set. // go ahead and spin up the registry client. - var token = config.get("_token") - if (typeof token === "string") { - try { - token = JSON.parse(token) - config.set("_token", token, "user") - config.save("user") - } catch (e) { token = null } - } - npm.registry = new RegClient(npm.config) - // save the token cookie in the config file - if (npm.registry.couchLogin) { - npm.registry.couchLogin.tokenSet = function (tok) { - npm.config.set("_token", tok, "user") - // ignore save error. best effort. - npm.config.save("user") - } - } - var umask = npm.config.get("umask") npm.modes = { exec: 0777 & (~umask) , file: 0666 & (~umask) , umask: umask } - chain([ [ loadPrefix, npm, cli ] - , [ setUser, config, config.root ] - , [ loadUid, npm ] - ], cb) - }) - }) -} - -function loadPrefix (npm, config, cb) { - // try to guess at a good node_modules location. - var p - , gp - if (!Object.prototype.hasOwnProperty.call(config, "prefix")) { - p = process.cwd() - } else { - p = npm.config.get("prefix") - } - gp = npm.config.get("prefix") - - findPrefix(p, function (er, p) { - Object.defineProperty(npm, "localPrefix", - { get : function () { return p } - , set : function (r) { return p = r } - , enumerable : true - }) - // the prefix MUST exist, or else nothing works. - if (!npm.config.get("global")) { - mkdir(p, next) - } else { - next(er) - } - }) - - gp = path.resolve(gp) - Object.defineProperty(npm, "globalPrefix", - { get : function () { return gp } - , set : function (r) { return gp = r } - , enumerable : true - }) - // the prefix MUST exist, or else nothing works. - mkdir(gp, next) - - - var i = 2 - , errState = null - function next (er) { - if (errState) return - if (er) return cb(errState = er) - if (--i === 0) return cb() - } -} - + var gp = Object.getOwnPropertyDescriptor(config, "globalPrefix") + Object.defineProperty(npm, "globalPrefix", gp) -function loadUid (npm, cb) { - // if we're not in unsafe-perm mode, then figure out who - // to run stuff as. Do this first, to support `npm update npm -g` - if (!npm.config.get("unsafe-perm")) { - getUid(npm.config.get("user"), npm.config.get("group"), cb) - } else { - process.nextTick(cb) - } -} + var lp = Object.getOwnPropertyDescriptor(config, "localPrefix") + Object.defineProperty(npm, "localPrefix", lp) -function setUser (cl, dc, cb) { - // If global, leave it as-is. - // If not global, then set the user to the owner of the prefix folder. - // Just set the default, so it can be overridden. - if (cl.get("global")) return cb() - if (process.env.SUDO_UID) { - dc.user = +(process.env.SUDO_UID) - return cb() - } - - var prefix = path.resolve(cl.get("prefix")) - mkdir(prefix, function (er) { - if (er) { - log.error("could not create prefix dir", prefix) - return cb(er) - } - fs.stat(prefix, function (er, st) { - dc.user = st && st.uid - return cb(er) + return cb() }) }) } - Object.defineProperty(npm, "prefix", { get : function () { return npm.config.get("global") ? npm.globalPrefix : npm.localPrefix diff --git a/lib/utils/find-prefix.js b/node_modules/npmconf/lib/find-prefix.js index a61d9e136..bb00cd6b1 100644 --- a/lib/utils/find-prefix.js +++ b/node_modules/npmconf/lib/find-prefix.js @@ -2,9 +2,8 @@ module.exports = findPrefix -var fs = require("graceful-fs") - , path = require("path") - , npm = require("../npm.js") +var fs = require("fs") +var path = require("path") function findPrefix (p, cb_) { function cb (er, p) { diff --git a/node_modules/npmconf/lib/load-prefix.js b/node_modules/npmconf/lib/load-prefix.js new file mode 100644 index 000000000..c161b0649 --- /dev/null +++ b/node_modules/npmconf/lib/load-prefix.js @@ -0,0 +1,51 @@ +module.exports = loadPrefix + +var findPrefix = require("./find-prefix.js") +var mkdirp = require("mkdirp") +var path = require('path') + +function loadPrefix (cb) { + var cli = this.list[0] + + // try to guess at a good node_modules location. + var p + , gp + + if (!Object.prototype.hasOwnProperty.call(cli, "prefix")) { + p = process.cwd() + } else { + p = this.get("prefix") + } + gp = this.get("prefix") + + findPrefix(p, function (er, p) { + Object.defineProperty(this, "localPrefix", + { get : function () { return p } + , set : function (r) { return p = r } + , enumerable : true + }) + // the prefix MUST exist, or else nothing works. + if (!this.get("global")) { + mkdirp(p, next.bind(this)) + } else { + next.bind(this)(er) + } + }.bind(this)) + + gp = path.resolve(gp) + Object.defineProperty(this, "globalPrefix", + { get : function () { return gp } + , set : function (r) { return gp = r } + , enumerable : true + }) + // the prefix MUST exist, or else nothing works. + mkdirp(gp, next.bind(this)) + + var i = 2 + var errState = null + function next (er) { + if (errState) return + if (er) return cb(errState = er) + if (--i === 0) return cb() + } +} diff --git a/node_modules/npmconf/lib/load-uid.js b/node_modules/npmconf/lib/load-uid.js new file mode 100644 index 000000000..3ca798773 --- /dev/null +++ b/node_modules/npmconf/lib/load-uid.js @@ -0,0 +1,15 @@ +module.exports = loadUid + +var getUid = require("uid-number") + +// Call in the context of a npmconf object + +function loadUid (cb) { + // if we're not in unsafe-perm mode, then figure out who + // to run stuff as. Do this first, to support `npm update npm -g` + if (!this.get("unsafe-perm")) { + getUid(this.get("user"), this.get("group"), cb) + } else { + process.nextTick(cb) + } +} diff --git a/node_modules/npmconf/lib/set-user.js b/node_modules/npmconf/lib/set-user.js new file mode 100644 index 000000000..2e7774aec --- /dev/null +++ b/node_modules/npmconf/lib/set-user.js @@ -0,0 +1,23 @@ +module.exports = setUser + +var path = require('path') +var fs = require('fs') + +function setUser (cb) { + var defaultConf = Object.getPrototypeOf(this.root) + + // If global, leave it as-is. + // If not global, then set the user to the owner of the prefix folder. + // Just set the default, so it can be overridden. + if (this.get("global")) return cb() + if (process.env.SUDO_UID) { + defaultConf.user = +(process.env.SUDO_UID) + return cb() + } + + var prefix = path.resolve(this.get("prefix")) + fs.stat(prefix, function (er, st) { + defaultConf.user = st && st.uid + return cb(er) + }) +} diff --git a/node_modules/npmconf/npmconf.js b/node_modules/npmconf/npmconf.js index 46ff2b813..aa2c7b2e6 100644 --- a/node_modules/npmconf/npmconf.js +++ b/node_modules/npmconf/npmconf.js @@ -10,6 +10,7 @@ var nopt = require('nopt') var ini = require('ini') var Octal = configDefs.Octal var mkdirp = require('mkdirp') +var path = require('path') exports.load = load exports.Conf = Conf @@ -17,9 +18,11 @@ exports.loaded = false exports.rootConf = null exports.usingBuiltin = false exports.defs = configDefs + Object.defineProperty(exports, 'defaults', { get: function () { return configDefs.defaults }, enumerable: true }) + Object.defineProperty(exports, 'types', { get: function () { return configDefs.types }, enumerable: true }) @@ -67,6 +70,7 @@ function load (cli_, builtin_, cb_) { loadCbs.push(cb) if (loading) return + loading = true cb = once(function (er, conf) { @@ -81,46 +85,68 @@ function load (cli_, builtin_, cb_) { // check for a builtin if provided. exports.usingBuiltin = !!builtin var rc = exports.rootConf = new Conf() - var defaults = configDefs.defaults if (builtin) rc.addFile(builtin, 'builtin') else rc.add({}, 'builtin') rc.on('load', function () { - var conf = new Conf(rc) - conf.usingBuiltin = !!builtin - conf.add(cli, 'cli') - conf.addEnv() + load_(builtin, rc, cli, cb) + }) +} + +function load_(builtin, rc, cli, cb) { + var defaults = configDefs.defaults + var conf = new Conf(rc) + + conf.usingBuiltin = !!builtin + conf.add(cli, 'cli') + conf.addEnv() + + conf.loadExtras(function(er) { + if (er) + return cb(er) + + if (!conf.get('global')) { + var projectConf = path.resolve(conf.localPrefix, '.npmrc') + conf.addFile(projectConf, 'project') + conf.once('load', afterPrefix) + } + else return afterPrefix() + }) + + function afterPrefix() { conf.addFile(conf.get('userconfig'), 'user') conf.once('error', cb) + conf.once('load', afterUser) + } + + function afterUser () { + // globalconfig and globalignorefile defaults + // need to respond to the 'prefix' setting up to this point. + // Eg, `npm config get globalconfig --prefix ~/local` should + // return `~/local/etc/npmrc` + // annoying humans and their expectations! + if (conf.get('prefix')) { + var etc = path.resolve(conf.get('prefix'), 'etc') + defaults.globalconfig = path.resolve(etc, 'npmrc') + defaults.globalignorefile = path.resolve(etc, 'npmignore') + } + + conf.addFile(conf.get('globalconfig'), 'global') + + // move the builtin into the conf stack now. + conf.root = defaults + conf.add(rc.shift(), 'builtin') conf.once('load', function () { - // globalconfig and globalignorefile defaults - // need to respond to the "prefix" setting up to this point. - // Eg, `npm config get globalconfig --prefix ~/local` should - // return `~/local/etc/npmrc` - // annoying humans and their expectations! - if (conf.get('prefix')) { - var etc = path.resolve(conf.get("prefix"), "etc") - defaults.globalconfig = path.resolve(etc, "npmrc") - defaults.globalignorefile = path.resolve(etc, "npmignore") - } - conf.addFile(conf.get('globalconfig'), 'global') - - // move the builtin into the conf stack now. - conf.root = defaults - conf.add(rc.shift(), 'builtin') - conf.once('load', function () { - // warn about invalid bits. - validate(conf) - exports.loaded = conf - cb(null, conf) - }) + // warn about invalid bits. + validate(conf) + exports.loaded = conf + cb(null, conf) }) - }) + } } - // Basically the same as CC, but: // 1. Always ini // 2. Parses environment variable names in field values @@ -142,6 +168,23 @@ function Conf (base) { this.root = configDefs.defaults } +Conf.prototype.loadPrefix = require('./lib/load-prefix.js') +Conf.prototype.loadUid = require('./lib/load-uid.js') +Conf.prototype.setUser = require('./lib/set-user.js') +Conf.prototype.findPrefix = require('./lib/find-prefix.js') + +Conf.prototype.loadExtras = function(cb) { + this.loadPrefix(function(er) { + if (er) + return cb(er) + this.setUser(function(er) { + if (er) + return cb(er) + this.loadUid(cb) + }.bind(this)) + }.bind(this)) +} + Conf.prototype.save = function (where, cb) { var target = this.sources[where] if (!target || !(target.path || target.source) || !target.data) { @@ -316,7 +359,7 @@ function parseField (f, k, emptyIsFalse) { } function envReplace (f) { - if (typeof f !== "string" || !f) return f + if (typeof f !== 'string' || !f) return f // replace any ${ENV} values with the appropriate environ. var envExpr = /(\\*)\$\{([^}]+)\}/g @@ -325,7 +368,7 @@ function envReplace (f) { if (esc) return orig if (undefined === process.env[name]) - throw new Error("Failed to replace env in config: "+orig) + throw new Error('Failed to replace env in config: '+orig) return process.env[name] }) } diff --git a/node_modules/npmconf/package.json b/node_modules/npmconf/package.json index 0ac83acf3..4708b9bc5 100644 --- a/node_modules/npmconf/package.json +++ b/node_modules/npmconf/package.json @@ -1,6 +1,6 @@ { "name": "npmconf", - "version": "0.2.0", + "version": "1.0.0", "description": "The config thing npm uses", "main": "npmconf.js", "directories": { @@ -9,12 +9,13 @@ "dependencies": { "config-chain": "~1.1.8", "inherits": "~2.0.0", - "once": "~1.3.0", + "ini": "~1.1.0", "mkdirp": "~0.3.3", - "osenv": "0.0.3", "nopt": "2", + "once": "~1.3.0", + "osenv": "0.0.3", "semver": "2", - "ini": "~1.1.0" + "uid-number": "0.0.5" }, "devDependencies": { "tap": "~0.4.0" @@ -45,7 +46,7 @@ "url": "https://github.com/isaacs/npmconf/issues" }, "homepage": "https://github.com/isaacs/npmconf", - "_id": "npmconf@0.2.0", - "_shasum": "5c237d793aa50f8865cb8a289ae95ece009bde7c", + "_id": "npmconf@1.0.0", + "_shasum": "6015381e63743ecbbe1dcdda5eebafd6c49697c9", "_from": "npmconf@latest" } diff --git a/node_modules/npmconf/test/basic.js b/node_modules/npmconf/test/basic.js index 83832c2ef..f17f0fb8e 100644 --- a/node_modules/npmconf/test/basic.js +++ b/node_modules/npmconf/test/basic.js @@ -1,6 +1,9 @@ var test = require('tap').test var npmconf = require('../npmconf.js') var common = require('./00-setup.js') +var path = require('path') + +var projectData = {} var ucData = { globalconfig: common.globalconfig, @@ -29,6 +32,7 @@ var ucData = httponly: true } } var envData = { userconfig: common.userconfig, 'other-env-thing': '1000' } +var envDataFix = { userconfig: common.userconfig, 'other-env-thing': 1000 } var gcData = { 'package-config:foo': 'boo' } @@ -38,7 +42,8 @@ var cli = { foo: 'bar', umask: 022 } var expectList = [ cli, - envData, + envDataFix, + projectData, ucData, gcData, biData ] @@ -46,9 +51,13 @@ var expectList = var expectSources = { cli: { data: cli }, env: - { data: envData, + { data: envDataFix, source: envData, prefix: '' }, + project: + { path: path.resolve(__dirname, '..', '.npmrc'), + type: 'ini', + data: projectData }, user: { path: common.userconfig, type: 'ini', diff --git a/node_modules/npmconf/test/builtin.js b/node_modules/npmconf/test/builtin.js index c5216ed90..0a305d2a6 100644 --- a/node_modules/npmconf/test/builtin.js +++ b/node_modules/npmconf/test/builtin.js @@ -1,6 +1,7 @@ var test = require('tap').test var npmconf = require('../npmconf.js') var common = require('./00-setup.js') +var path = require('path') var ucData = { globalconfig: common.globalconfig, @@ -29,6 +30,7 @@ var ucData = httponly: true } } var envData = { userconfig: common.userconfig, 'other-env-thing': '1000' } +var envDataFix = { userconfig: common.userconfig, 'other-env-thing': 1000 } var gcData = { 'package-config:foo': 'boo' } @@ -36,9 +38,12 @@ var biData = { 'builtin-config': true } var cli = { foo: 'bar', heading: 'foo', 'git-tag-version': false } +var projectData = {} + var expectList = [ cli, - envData, + envDataFix, + projectData, ucData, gcData, biData ] @@ -46,9 +51,13 @@ var expectList = var expectSources = { cli: { data: cli }, env: - { data: envData, + { data: envDataFix, source: envData, prefix: '' }, + project: + { path: path.resolve(__dirname, '..', '.npmrc'), + type: 'ini', + data: projectData }, user: { path: common.userconfig, type: 'ini', diff --git a/node_modules/npmconf/test/fixtures/.npmrc b/node_modules/npmconf/test/fixtures/.npmrc new file mode 100644 index 000000000..7d59bd8be --- /dev/null +++ b/node_modules/npmconf/test/fixtures/.npmrc @@ -0,0 +1 @@ +just = testing diff --git a/node_modules/npmconf/test/fixtures/package.json b/node_modules/npmconf/test/fixtures/package.json new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/node_modules/npmconf/test/fixtures/package.json diff --git a/node_modules/npmconf/test/project.js b/node_modules/npmconf/test/project.js new file mode 100644 index 000000000..04e063855 --- /dev/null +++ b/node_modules/npmconf/test/project.js @@ -0,0 +1,85 @@ +var test = require('tap').test +var npmconf = require('../npmconf.js') +var common = require('./00-setup.js') +var path = require('path') +var fix = path.resolve(__dirname, 'fixtures') +var projectRc = path.resolve(fix, '.npmrc') + +var projectData = { just: 'testing' } + +var ucData = + { globalconfig: common.globalconfig, + email: 'i@izs.me', + 'env-thing': 'asdf', + 'init.author.name': 'Isaac Z. Schlueter', + 'init.author.email': 'i@izs.me', + 'init.author.url': 'http://blog.izs.me/', + 'proprietary-attribs': false, + 'npm:publishtest': true, + '_npmjs.org:couch': 'https://admin:password@localhost:5984/registry', + _auth: 'dXNlcm5hbWU6cGFzc3dvcmQ=', + 'npm-www:nocache': '1', + nodedir: '/Users/isaacs/dev/js/node-v0.8', + 'sign-git-tag': true, + message: 'v%s', + 'strict-ssl': false, + 'tmp': process.env.HOME + '/.tmp', + username : "username", + _password : "password", + _token: + { AuthSession: 'yabba-dabba-doodle', + version: '1', + expires: '1345001053415', + path: '/', + httponly: true } } + +var envData = { userconfig: common.userconfig, 'other-env-thing': '1000' } +var envDataFix = { userconfig: common.userconfig, 'other-env-thing': 1000 } + +var gcData = { 'package-config:foo': 'boo' } + +var biData = {} + +var cli = { foo: 'bar', umask: 022, prefix: fix } + +var expectList = +[ cli, + envDataFix, + projectData, + ucData, + gcData, + biData ] + +var expectSources = +{ cli: { data: cli }, + env: + { data: envDataFix, + source: envData, + prefix: '' }, + project: + { path: projectRc, + type: 'ini', + data: projectData }, + user: + { path: common.userconfig, + type: 'ini', + data: ucData }, + global: + { path: common.globalconfig, + type: 'ini', + data: gcData }, + builtin: { data: biData } } + +test('no builtin', function (t) { + npmconf.load(cli, function (er, conf) { + if (er) throw er + t.same(conf.list, expectList) + t.same(conf.sources, expectSources) + t.same(npmconf.rootConf.list, []) + t.equal(npmconf.rootConf.root, npmconf.defs.defaults) + t.equal(conf.root, npmconf.defs.defaults) + t.equal(conf.get('umask'), 022) + t.equal(conf.get('heading'), 'npm') + t.end() + }) +}) diff --git a/package.json b/package.json index f30dbf7dd..d63f84147 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "npm-install-checks": "~1.0.0", "npm-registry-client": "~0.4.11", "npm-user-validate": "~0.1.0", - "npmconf": "~0.2.0", + "npmconf": "~1.0.0", "npmlog": "0.0.6", "once": "~1.3.0", "opener": "~1.3.0", @@ -83,7 +83,6 @@ "sorted-object": "~1.0.0", "tar": "~0.1.19", "text-table": "~0.2.0", - "uid-number": "0.0.5", "which": "1" }, "bundleDependencies": [ |