|
|
|
module.exports = config
|
|
|
|
|
|
|
|
var log = require('npmlog')
|
|
|
|
var npm = require('./npm.js')
|
|
|
|
var npmconf = require('./config/core.js')
|
|
|
|
var fs = require('graceful-fs')
|
|
|
|
var writeFileAtomic = require('write-file-atomic')
|
|
|
|
var types = npmconf.defs.types
|
|
|
|
var ini = require('ini')
|
|
|
|
var editor = require('editor')
|
|
|
|
var os = require('os')
|
|
|
|
var umask = require('./utils/umask')
|
|
|
|
var usage = require('./utils/usage')
|
|
|
|
var output = require('./utils/output')
|
|
|
|
|
|
|
|
config.usage = usage(
|
|
|
|
'config',
|
|
|
|
'npm config set <key> <value>' +
|
|
|
|
'\nnpm config get [<key>]' +
|
|
|
|
'\nnpm config delete <key>' +
|
|
|
|
'\nnpm config list' +
|
|
|
|
'\nnpm config edit' +
|
|
|
|
'\nnpm set <key> <value>' +
|
|
|
|
'\nnpm get [<key>]'
|
|
|
|
)
|
|
|
|
config.completion = function (opts, cb) {
|
|
|
|
var argv = opts.conf.argv.remain
|
|
|
|
if (argv[1] !== 'config') argv.unshift('config')
|
|
|
|
if (argv.length === 2) {
|
|
|
|
var cmds = ['get', 'set', 'delete', 'ls', 'rm', 'edit']
|
|
|
|
if (opts.partialWord !== 'l') cmds.push('list')
|
|
|
|
return cb(null, cmds)
|
|
|
|
}
|
|
|
|
|
|
|
|
var action = argv[2]
|
|
|
|
switch (action) {
|
|
|
|
case 'set':
|
|
|
|
// todo: complete with valid values, if possible.
|
|
|
|
if (argv.length > 3) return cb(null, [])
|
|
|
|
// fallthrough
|
|
|
|
/*eslint no-fallthrough:0*/
|
|
|
|
case 'get':
|
|
|
|
case 'delete':
|
|
|
|
case 'rm':
|
|
|
|
return cb(null, Object.keys(types))
|
|
|
|
case 'edit':
|
|
|
|
case 'list': case 'ls':
|
|
|
|
return cb(null, [])
|
|
|
|
default: return cb(null, [])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// npm config set key value
|
|
|
|
// npm config get key
|
|
|
|
// npm config list
|
|
|
|
function config (args, cb) {
|
|
|
|
var action = args.shift()
|
|
|
|
switch (action) {
|
|
|
|
case 'set': return set(args[0], args[1], cb)
|
|
|
|
case 'get': return get(args[0], cb)
|
|
|
|
case 'delete': case 'rm': case 'del': return del(args[0], cb)
|
|
|
|
case 'list': case 'ls': return list(cb)
|
|
|
|
case 'edit': return edit(cb)
|
|
|
|
default: return unknown(action, cb)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function edit (cb) {
|
|
|
|
var e = npm.config.get('editor')
|
|
|
|
var which = npm.config.get('global') ? 'global' : 'user'
|
|
|
|
var f = npm.config.get(which + 'config')
|
|
|
|
if (!e) return cb(new Error('No EDITOR config or environ set.'))
|
|
|
|
npm.config.save(which, function (er) {
|
|
|
|
if (er) return cb(er)
|
|
|
|
fs.readFile(f, 'utf8', function (er, data) {
|
|
|
|
if (er) data = ''
|
|
|
|
data = [
|
|
|
|
';;;;',
|
|
|
|
'; npm ' + (npm.config.get('global')
|
|
|
|
? 'globalconfig' : 'userconfig') + ' file',
|
|
|
|
'; this is a simple ini-formatted file',
|
|
|
|
'; lines that start with semi-colons are comments.',
|
|
|
|
'; read `npm help config` for help on the various options',
|
|
|
|
';;;;',
|
|
|
|
'',
|
|
|
|
data
|
|
|
|
].concat([
|
|
|
|
';;;;',
|
|
|
|
'; all options with default values',
|
|
|
|
';;;;'
|
|
|
|
]).concat(Object.keys(npmconf.defaults).reduce(function (arr, key) {
|
|
|
|
var obj = {}
|
|
|
|
obj[key] = npmconf.defaults[key]
|
|
|
|
if (key === 'logstream') return arr
|
|
|
|
return arr.concat(
|
|
|
|
ini.stringify(obj)
|
|
|
|
.replace(/\n$/m, '')
|
|
|
|
.replace(/^/g, '; ')
|
|
|
|
.replace(/\n/g, '\n; ')
|
|
|
|
.split('\n'))
|
|
|
|
}, []))
|
|
|
|
.concat([''])
|
|
|
|
.join(os.EOL)
|
|
|
|
writeFileAtomic(
|
|
|
|
f,
|
|
|
|
data,
|
|
|
|
function (er) {
|
|
|
|
if (er) return cb(er)
|
|
|
|
editor(f, { editor: e }, cb)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function del (key, cb) {
|
|
|
|
if (!key) return cb(new Error('no key provided'))
|
|
|
|
var where = npm.config.get('global') ? 'global' : 'user'
|
|
|
|
npm.config.del(key, where)
|
|
|
|
npm.config.save(where, cb)
|
|
|
|
}
|
|
|
|
|
|
|
|
function set (key, val, cb) {
|
|
|
|
if (key === undefined) {
|
|
|
|
return unknown('', cb)
|
|
|
|
}
|
|
|
|
if (val === undefined) {
|
|
|
|
if (key.indexOf('=') !== -1) {
|
|
|
|
var k = key.split('=')
|
|
|
|
key = k.shift()
|
|
|
|
val = k.join('=')
|
|
|
|
} else {
|
|
|
|
val = ''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
key = key.trim()
|
|
|
|
val = val.trim()
|
|
|
|
log.info('config', 'set %j %j', key, val)
|
|
|
|
var where = npm.config.get('global') ? 'global' : 'user'
|
|
|
|
if (key.match(/umask/)) val = umask.fromString(val)
|
|
|
|
npm.config.set(key, val, where)
|
|
|
|
npm.config.save(where, cb)
|
|
|
|
}
|
|
|
|
|
|
|
|
function get (key, cb) {
|
|
|
|
if (!key) return list(cb)
|
|
|
|
if (!publicVar(key)) {
|
|
|
|
return cb(new Error('---sekretz---'))
|
|
|
|
}
|
|
|
|
var val = npm.config.get(key)
|
|
|
|
if (key.match(/umask/)) val = umask.toString(val)
|
|
|
|
output(val)
|
|
|
|
cb()
|
|
|
|
}
|
|
|
|
|
|
|
|
function sort (a, b) {
|
|
|
|
return a > b ? 1 : -1
|
|
|
|
}
|
|
|
|
|
|
|
|
function publicVar (k) {
|
|
|
|
return !(k.charAt(0) === '_' ||
|
|
|
|
k.indexOf(':_') !== -1 ||
|
|
|
|
types[k] !== types[k])
|
|
|
|
}
|
|
|
|
|
|
|
|
function getKeys (data) {
|
|
|
|
return Object.keys(data).filter(publicVar).sort(sort)
|
|
|
|
}
|
|
|
|
|
|
|
|
function list (cb) {
|
|
|
|
var msg = ''
|
|
|
|
var long = npm.config.get('long')
|
|
|
|
|
|
|
|
var cli = npm.config.sources.cli.data
|
|
|
|
var cliKeys = getKeys(cli)
|
|
|
|
if (cliKeys.length) {
|
|
|
|
msg += '; cli configs\n'
|
|
|
|
cliKeys.forEach(function (k) {
|
|
|
|
if (cli[k] && typeof cli[k] === 'object') return
|
|
|
|
if (k === 'argv') return
|
|
|
|
msg += k + ' = ' + JSON.stringify(cli[k]) + '\n'
|
|
|
|
})
|
|
|
|
msg += '\n'
|
|
|
|
}
|
|
|
|
|
|
|
|
// env configs
|
|
|
|
var env = npm.config.sources.env.data
|
|
|
|
var envKeys = getKeys(env)
|
|
|
|
if (envKeys.length) {
|
|
|
|
msg += '; environment configs\n'
|
|
|
|
envKeys.forEach(function (k) {
|
|
|
|
if (env[k] !== npm.config.get(k)) {
|
|
|
|
if (!long) return
|
|
|
|
msg += '; ' + k + ' = ' +
|
|
|
|
JSON.stringify(env[k]) + ' (overridden)\n'
|
|
|
|
} else msg += k + ' = ' + JSON.stringify(env[k]) + '\n'
|
|
|
|
})
|
|
|
|
msg += '\n'
|
|
|
|
}
|
|
|
|
|
|
|
|
// project config file
|
|
|
|
var project = npm.config.sources.project
|
|
|
|
var pconf = project.data
|
|
|
|
var ppath = project.path
|
|
|
|
var pconfKeys = getKeys(pconf)
|
|
|
|
if (pconfKeys.length) {
|
|
|
|
msg += '; project config ' + ppath + '\n'
|
|
|
|
pconfKeys.forEach(function (k) {
|
|
|
|
var val = (k.charAt(0) === '_')
|
|
|
|
? '---sekretz---'
|
|
|
|
: JSON.stringify(pconf[k])
|
|
|
|
if (pconf[k] !== npm.config.get(k)) {
|
|
|
|
if (!long) return
|
|
|
|
msg += '; ' + k + ' = ' + val + ' (overridden)\n'
|
|
|
|
} else msg += k + ' = ' + val + '\n'
|
|
|
|
})
|
|
|
|
msg += '\n'
|
|
|
|
}
|
|
|
|
|
|
|
|
// user config file
|
|
|
|
var uconf = npm.config.sources.user.data
|
|
|
|
var uconfKeys = getKeys(uconf)
|
|
|
|
if (uconfKeys.length) {
|
|
|
|
msg += '; userconfig ' + npm.config.get('userconfig') + '\n'
|
|
|
|
uconfKeys.forEach(function (k) {
|
|
|
|
var val = (k.charAt(0) === '_')
|
|
|
|
? '---sekretz---'
|
|
|
|
: JSON.stringify(uconf[k])
|
|
|
|
if (uconf[k] !== npm.config.get(k)) {
|
|
|
|
if (!long) return
|
|
|
|
msg += '; ' + k + ' = ' + val + ' (overridden)\n'
|
|
|
|
} else msg += k + ' = ' + val + '\n'
|
|
|
|
})
|
|
|
|
msg += '\n'
|
|
|
|
}
|
|
|
|
|
|
|
|
// global config file
|
|
|
|
var gconf = npm.config.sources.global.data
|
|
|
|
var gconfKeys = getKeys(gconf)
|
|
|
|
if (gconfKeys.length) {
|
|
|
|
msg += '; globalconfig ' + npm.config.get('globalconfig') + '\n'
|
|
|
|
gconfKeys.forEach(function (k) {
|
|
|
|
var val = (k.charAt(0) === '_')
|
|
|
|
? '---sekretz---'
|
|
|
|
: JSON.stringify(gconf[k])
|
|
|
|
if (gconf[k] !== npm.config.get(k)) {
|
|
|
|
if (!long) return
|
|
|
|
msg += '; ' + k + ' = ' + val + ' (overridden)\n'
|
|
|
|
} else msg += k + ' = ' + val + '\n'
|
|
|
|
})
|
|
|
|
msg += '\n'
|
|
|
|
}
|
|
|
|
|
|
|
|
// builtin config file
|
|
|
|
var builtin = npm.config.sources.builtin || {}
|
|
|
|
if (builtin && builtin.data) {
|
|
|
|
var bconf = builtin.data
|
|
|
|
var bpath = builtin.path
|
|
|
|
var bconfKeys = getKeys(bconf)
|
|
|
|
if (bconfKeys.length) {
|
|
|
|
msg += '; builtin config ' + bpath + '\n'
|
|
|
|
bconfKeys.forEach(function (k) {
|
|
|
|
var val = (k.charAt(0) === '_')
|
|
|
|
? '---sekretz---'
|
|
|
|
: JSON.stringify(bconf[k])
|
|
|
|
if (bconf[k] !== npm.config.get(k)) {
|
|
|
|
if (!long) return
|
|
|
|
msg += '; ' + k + ' = ' + val + ' (overridden)\n'
|
|
|
|
} else msg += k + ' = ' + val + '\n'
|
|
|
|
})
|
|
|
|
msg += '\n'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// only show defaults if --long
|
|
|
|
if (!long) {
|
|
|
|
msg += '; node bin location = ' + process.execPath + '\n' +
|
|
|
|
'; cwd = ' + process.cwd() + '\n' +
|
|
|
|
'; HOME = ' + process.env.HOME + '\n' +
|
|
|
|
'; "npm config ls -l" to show all defaults.\n'
|
|
|
|
|
|
|
|
output(msg)
|
|
|
|
return cb()
|
|
|
|
}
|
|
|
|
|
|
|
|
var defaults = npmconf.defaults
|
|
|
|
var defKeys = getKeys(defaults)
|
|
|
|
msg += '; default values\n'
|
|
|
|
defKeys.forEach(function (k) {
|
|
|
|
if (defaults[k] && typeof defaults[k] === 'object') return
|
|
|
|
var val = JSON.stringify(defaults[k])
|
|
|
|
if (defaults[k] !== npm.config.get(k)) {
|
|
|
|
msg += '; ' + k + ' = ' + val + ' (overridden)\n'
|
|
|
|
} else msg += k + ' = ' + val + '\n'
|
|
|
|
})
|
|
|
|
msg += '\n'
|
|
|
|
|
|
|
|
output(msg)
|
|
|
|
return cb()
|
|
|
|
}
|
|
|
|
|
|
|
|
function unknown (action, cb) {
|
|
|
|
cb('Usage:\n' + config.usage)
|
|
|
|
}
|