UNPKG

8.47 kBJavaScriptView Raw
1module.exports = config
2
3var log = require('npmlog')
4var npm = require('./npm.js')
5var npmconf = require('./config/core.js')
6var fs = require('graceful-fs')
7var writeFileAtomic = require('write-file-atomic')
8var types = npmconf.defs.types
9var ini = require('ini')
10var editor = require('editor')
11var os = require('os')
12var umask = require('./utils/umask')
13var usage = require('./utils/usage')
14var output = require('./utils/output')
15var noProgressTillDone = require('./utils/no-progress-while-running').tillDone
16
17config.usage = usage(
18 'config',
19 'npm config set <key> <value>' +
20 '\nnpm config get [<key>]' +
21 '\nnpm config delete <key>' +
22 '\nnpm config list' +
23 '\nnpm config edit' +
24 '\nnpm set <key> <value>' +
25 '\nnpm get [<key>]'
26)
27config.completion = function (opts, cb) {
28 var argv = opts.conf.argv.remain
29 if (argv[1] !== 'config') argv.unshift('config')
30 if (argv.length === 2) {
31 var cmds = ['get', 'set', 'delete', 'ls', 'rm', 'edit']
32 if (opts.partialWord !== 'l') cmds.push('list')
33 return cb(null, cmds)
34 }
35
36 var action = argv[2]
37 switch (action) {
38 case 'set':
39 // todo: complete with valid values, if possible.
40 if (argv.length > 3) return cb(null, [])
41 // fallthrough
42 /*eslint no-fallthrough:0*/
43 case 'get':
44 case 'delete':
45 case 'rm':
46 return cb(null, Object.keys(types))
47 case 'edit':
48 case 'list': case 'ls':
49 return cb(null, [])
50 default: return cb(null, [])
51 }
52}
53
54// npm config set key value
55// npm config get key
56// npm config list
57function config (args, cb) {
58 var action = args.shift()
59 switch (action) {
60 case 'set': return set(args[0], args[1], cb)
61 case 'get': return get(args[0], cb)
62 case 'delete': case 'rm': case 'del': return del(args[0], cb)
63 case 'list': case 'ls': return list(cb)
64 case 'edit': return edit(cb)
65 default: return unknown(action, cb)
66 }
67}
68
69function edit (cb) {
70 var e = npm.config.get('editor')
71 var which = npm.config.get('global') ? 'global' : 'user'
72 var f = npm.config.get(which + 'config')
73 if (!e) return cb(new Error('No EDITOR config or environ set.'))
74 npm.config.save(which, function (er) {
75 if (er) return cb(er)
76 fs.readFile(f, 'utf8', function (er, data) {
77 if (er) data = ''
78 data = [
79 ';;;;',
80 '; npm ' + (npm.config.get('global')
81 ? 'globalconfig' : 'userconfig') + ' file',
82 '; this is a simple ini-formatted file',
83 '; lines that start with semi-colons are comments.',
84 '; read `npm help config` for help on the various options',
85 ';;;;',
86 '',
87 data
88 ].concat([
89 ';;;;',
90 '; all options with default values',
91 ';;;;'
92 ]).concat(Object.keys(npmconf.defaults).reduce(function (arr, key) {
93 var obj = {}
94 obj[key] = npmconf.defaults[key]
95 if (key === 'logstream') return arr
96 return arr.concat(
97 ini.stringify(obj)
98 .replace(/\n$/m, '')
99 .replace(/^/g, '; ')
100 .replace(/\n/g, '\n; ')
101 .split('\n'))
102 }, []))
103 .concat([''])
104 .join(os.EOL)
105 writeFileAtomic(
106 f,
107 data,
108 function (er) {
109 if (er) return cb(er)
110 editor(f, { editor: e }, noProgressTillDone(cb))
111 }
112 )
113 })
114 })
115}
116
117function del (key, cb) {
118 if (!key) return cb(new Error('no key provided'))
119 var where = npm.config.get('global') ? 'global' : 'user'
120 npm.config.del(key, where)
121 npm.config.save(where, cb)
122}
123
124function set (key, val, cb) {
125 if (key === undefined) {
126 return unknown('', cb)
127 }
128 if (val === undefined) {
129 if (key.indexOf('=') !== -1) {
130 var k = key.split('=')
131 key = k.shift()
132 val = k.join('=')
133 } else {
134 val = ''
135 }
136 }
137 key = key.trim()
138 val = val.trim()
139 log.info('config', 'set %j %j', key, val)
140 var where = npm.config.get('global') ? 'global' : 'user'
141 if (key.match(/umask/)) val = umask.fromString(val)
142 npm.config.set(key, val, where)
143 npm.config.save(where, cb)
144}
145
146function get (key, cb) {
147 if (!key) return list(cb)
148 if (!publicVar(key)) {
149 return cb(new Error('---sekretz---'))
150 }
151 var val = npm.config.get(key)
152 if (key.match(/umask/)) val = umask.toString(val)
153 output(val)
154 cb()
155}
156
157function sort (a, b) {
158 return a > b ? 1 : -1
159}
160
161function publicVar (k) {
162 return !(k.charAt(0) === '_' ||
163 k.indexOf(':_') !== -1 ||
164 types[k] !== types[k])
165}
166
167function getKeys (data) {
168 return Object.keys(data).filter(publicVar).sort(sort)
169}
170
171function list (cb) {
172 var msg = ''
173 var long = npm.config.get('long')
174
175 var cli = npm.config.sources.cli.data
176 var cliKeys = getKeys(cli)
177 if (cliKeys.length) {
178 msg += '; cli configs\n'
179 cliKeys.forEach(function (k) {
180 if (cli[k] && typeof cli[k] === 'object') return
181 if (k === 'argv') return
182 msg += k + ' = ' + JSON.stringify(cli[k]) + '\n'
183 })
184 msg += '\n'
185 }
186
187 // env configs
188 var env = npm.config.sources.env.data
189 var envKeys = getKeys(env)
190 if (envKeys.length) {
191 msg += '; environment configs\n'
192 envKeys.forEach(function (k) {
193 if (env[k] !== npm.config.get(k)) {
194 if (!long) return
195 msg += '; ' + k + ' = ' +
196 JSON.stringify(env[k]) + ' (overridden)\n'
197 } else msg += k + ' = ' + JSON.stringify(env[k]) + '\n'
198 })
199 msg += '\n'
200 }
201
202 // project config file
203 var project = npm.config.sources.project
204 var pconf = project.data
205 var ppath = project.path
206 var pconfKeys = getKeys(pconf)
207 if (pconfKeys.length) {
208 msg += '; project config ' + ppath + '\n'
209 pconfKeys.forEach(function (k) {
210 var val = (k.charAt(0) === '_')
211 ? '---sekretz---'
212 : JSON.stringify(pconf[k])
213 if (pconf[k] !== npm.config.get(k)) {
214 if (!long) return
215 msg += '; ' + k + ' = ' + val + ' (overridden)\n'
216 } else msg += k + ' = ' + val + '\n'
217 })
218 msg += '\n'
219 }
220
221 // user config file
222 var uconf = npm.config.sources.user.data
223 var uconfKeys = getKeys(uconf)
224 if (uconfKeys.length) {
225 msg += '; userconfig ' + npm.config.get('userconfig') + '\n'
226 uconfKeys.forEach(function (k) {
227 var val = (k.charAt(0) === '_')
228 ? '---sekretz---'
229 : JSON.stringify(uconf[k])
230 if (uconf[k] !== npm.config.get(k)) {
231 if (!long) return
232 msg += '; ' + k + ' = ' + val + ' (overridden)\n'
233 } else msg += k + ' = ' + val + '\n'
234 })
235 msg += '\n'
236 }
237
238 // global config file
239 var gconf = npm.config.sources.global.data
240 var gconfKeys = getKeys(gconf)
241 if (gconfKeys.length) {
242 msg += '; globalconfig ' + npm.config.get('globalconfig') + '\n'
243 gconfKeys.forEach(function (k) {
244 var val = (k.charAt(0) === '_')
245 ? '---sekretz---'
246 : JSON.stringify(gconf[k])
247 if (gconf[k] !== npm.config.get(k)) {
248 if (!long) return
249 msg += '; ' + k + ' = ' + val + ' (overridden)\n'
250 } else msg += k + ' = ' + val + '\n'
251 })
252 msg += '\n'
253 }
254
255 // builtin config file
256 var builtin = npm.config.sources.builtin || {}
257 if (builtin && builtin.data) {
258 var bconf = builtin.data
259 var bpath = builtin.path
260 var bconfKeys = getKeys(bconf)
261 if (bconfKeys.length) {
262 msg += '; builtin config ' + bpath + '\n'
263 bconfKeys.forEach(function (k) {
264 var val = (k.charAt(0) === '_')
265 ? '---sekretz---'
266 : JSON.stringify(bconf[k])
267 if (bconf[k] !== npm.config.get(k)) {
268 if (!long) return
269 msg += '; ' + k + ' = ' + val + ' (overridden)\n'
270 } else msg += k + ' = ' + val + '\n'
271 })
272 msg += '\n'
273 }
274 }
275
276 // only show defaults if --long
277 if (!long) {
278 msg += '; node bin location = ' + process.execPath + '\n' +
279 '; cwd = ' + process.cwd() + '\n' +
280 '; HOME = ' + process.env.HOME + '\n' +
281 '; "npm config ls -l" to show all defaults.\n'
282
283 output(msg)
284 return cb()
285 }
286
287 var defaults = npmconf.defaults
288 var defKeys = getKeys(defaults)
289 msg += '; default values\n'
290 defKeys.forEach(function (k) {
291 if (defaults[k] && typeof defaults[k] === 'object') return
292 var val = JSON.stringify(defaults[k])
293 if (defaults[k] !== npm.config.get(k)) {
294 msg += '; ' + k + ' = ' + val + ' (overridden)\n'
295 } else msg += k + ' = ' + val + '\n'
296 })
297 msg += '\n'
298
299 output(msg)
300 return cb()
301}
302
303function unknown (action, cb) {
304 cb('Usage:\n' + config.usage)
305}