]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/lib/config/core.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / lib / config / core.js
1
2 var CC = require("config-chain").ConfigChain
3 var inherits = require("inherits")
4 var configDefs = require("./defaults.js")
5 var types = configDefs.types
6 var once = require("once")
7 var fs = require("fs")
8 var path = require("path")
9 var nopt = require("nopt")
10 var ini = require("ini")
11 var Umask = configDefs.Umask
12 var mkdirp = require("mkdirp")
13 var umask = require("../utils/umask")
14
15 exports.load = load
16 exports.Conf = Conf
17 exports.loaded = false
18 exports.rootConf = null
19 exports.usingBuiltin = false
20 exports.defs = configDefs
21
22 Object.defineProperty(exports, "defaults", { get: function () {
23   return configDefs.defaults
24 }, enumerable: true })
25
26 Object.defineProperty(exports, "types", { get: function () {
27   return configDefs.types
28 }, enumerable: true })
29
30 exports.validate = validate
31
32 var myUid = process.env.SUDO_UID !== undefined
33           ? process.env.SUDO_UID : (process.getuid && process.getuid())
34 var myGid = process.env.SUDO_GID !== undefined
35           ? process.env.SUDO_GID : (process.getgid && process.getgid())
36
37
38 var loading = false
39 var loadCbs = []
40 function load () {
41   var cli, builtin, cb
42   for (var i = 0; i < arguments.length; i++)
43     switch (typeof arguments[i]) {
44       case "string": builtin = arguments[i]; break
45       case "object": cli = arguments[i]; break
46       case "function": cb = arguments[i]; break
47     }
48
49   if (!cb)
50     cb = function () {}
51
52   if (exports.loaded) {
53     var ret = exports.loaded
54     if (cli) {
55       ret = new Conf(ret)
56       ret.unshift(cli)
57     }
58     return process.nextTick(cb.bind(null, null, ret))
59   }
60
61   // either a fresh object, or a clone of the passed in obj
62   if (!cli)
63     cli = {}
64   else
65     cli = Object.keys(cli).reduce(function (c, k) {
66       c[k] = cli[k]
67       return c
68     }, {})
69
70   loadCbs.push(cb)
71   if (loading)
72     return
73
74   loading = true
75
76   cb = once(function (er, conf) {
77     if (!er) {
78       exports.loaded = conf
79       loading = false
80     }
81     loadCbs.forEach(function (fn) {
82       fn(er, conf)
83     })
84     loadCbs.length = 0
85   })
86
87   // check for a builtin if provided.
88   exports.usingBuiltin = !!builtin
89   var rc = exports.rootConf = new Conf()
90   if (builtin)
91     rc.addFile(builtin, "builtin")
92   else
93     rc.add({}, "builtin")
94
95   rc.on("load", function () {
96     load_(builtin, rc, cli, cb)
97   })
98   rc.on("error", cb)
99 }
100
101 function load_(builtin, rc, cli, cb) {
102   var defaults = configDefs.defaults
103   var conf = new Conf(rc)
104
105   conf.usingBuiltin = !!builtin
106   conf.add(cli, "cli")
107   conf.addEnv()
108
109   conf.loadPrefix(function(er) {
110     if (er)
111       return cb(er)
112
113     // If you're doing `npm --userconfig=~/foo.npmrc` then you'd expect
114     // that ~/.npmrc won't override the stuff in ~/foo.npmrc (or, indeed
115     // be used at all).
116     //
117     // However, if the cwd is ~, then ~/.npmrc is the home for the project
118     // config, and will override the userconfig.
119     //
120     // If you're not setting the userconfig explicitly, then it will be loaded
121     // twice, which is harmless but excessive.  If you *are* setting the
122     // userconfig explicitly then it will override your explicit intent, and
123     // that IS harmful and unexpected.
124     //
125     // Solution: Do not load project config file that is the same as either
126     // the default or resolved userconfig value.  npm will log a "verbose"
127     // message about this when it happens, but it is a rare enough edge case
128     // that we don't have to be super concerned about it.
129     var projectConf = path.resolve(conf.localPrefix, ".npmrc")
130     var defaultUserConfig = rc.get("userconfig")
131     var resolvedUserConfig = conf.get("userconfig")
132     if (!conf.get("global") &&
133         projectConf !== defaultUserConfig &&
134         projectConf !== resolvedUserConfig) {
135       conf.addFile(projectConf, "project")
136       conf.once("load", afterPrefix)
137     } else {
138       conf.add({}, "project")
139       afterPrefix()
140     }
141   })
142
143   function afterPrefix() {
144     conf.addFile(conf.get("userconfig"), "user")
145     conf.once("error", cb)
146     conf.once("load", afterUser)
147   }
148
149   function afterUser () {
150     // globalconfig and globalignorefile defaults
151     // need to respond to the 'prefix' setting up to this point.
152     // Eg, `npm config get globalconfig --prefix ~/local` should
153     // return `~/local/etc/npmrc`
154     // annoying humans and their expectations!
155     if (conf.get("prefix")) {
156       var etc = path.resolve(conf.get("prefix"), "etc")
157       mkdirp(etc, function (err) {
158         defaults.globalconfig = path.resolve(etc, "npmrc")
159         defaults.globalignorefile = path.resolve(etc, "npmignore")
160         afterUserContinuation()
161       })
162     } else {
163       afterUserContinuation()
164     }
165   }
166
167   function afterUserContinuation() {
168     conf.addFile(conf.get("globalconfig"), "global")
169
170     // move the builtin into the conf stack now.
171     conf.root = defaults
172     conf.add(rc.shift(), "builtin")
173     conf.once("load", function () {
174       conf.loadExtras(afterExtras)
175     })
176   }
177
178   function afterExtras(er) {
179     if (er)
180       return cb(er)
181
182     // warn about invalid bits.
183     validate(conf)
184
185     var cafile = conf.get("cafile")
186
187     if (cafile) {
188       return conf.loadCAFile(cafile, finalize)
189     }
190
191     finalize()
192   }
193
194   function finalize(er) {
195     if (er) {
196       return cb(er)
197     }
198
199     exports.loaded = conf
200     cb(er, conf)
201   }
202 }
203
204 // Basically the same as CC, but:
205 // 1. Always ini
206 // 2. Parses environment variable names in field values
207 // 3. Field values that start with ~/ are replaced with process.env.HOME
208 // 4. Can inherit from another Conf object, using it as the base.
209 inherits(Conf, CC)
210 function Conf (base) {
211   if (!(this instanceof Conf))
212     return new Conf(base)
213
214   CC.apply(this)
215
216   if (base)
217     if (base instanceof Conf)
218       this.root = base.list[0] || base.root
219     else
220       this.root = base
221   else
222     this.root = configDefs.defaults
223 }
224
225 Conf.prototype.loadPrefix = require("./load-prefix.js")
226 Conf.prototype.loadCAFile = require("./load-cafile.js")
227 Conf.prototype.loadUid = require("./load-uid.js")
228 Conf.prototype.setUser = require("./set-user.js")
229 Conf.prototype.findPrefix = require("./find-prefix.js")
230 Conf.prototype.getCredentialsByURI = require("./get-credentials-by-uri.js")
231 Conf.prototype.setCredentialsByURI = require("./set-credentials-by-uri.js")
232 Conf.prototype.clearCredentialsByURI = require("./clear-credentials-by-uri.js")
233
234 Conf.prototype.loadExtras = function(cb) {
235   this.setUser(function(er) {
236     if (er)
237       return cb(er)
238     this.loadUid(function(er) {
239       if (er)
240         return cb(er)
241       // Without prefix, nothing will ever work
242       mkdirp(this.prefix, cb)
243     }.bind(this))
244   }.bind(this))
245 }
246
247 Conf.prototype.save = function (where, cb) {
248   var target = this.sources[where]
249   if (!target || !(target.path || target.source) || !target.data) {
250     if (where !== "builtin")
251       var er = new Error("bad save target: " + where)
252     if (cb) {
253       process.nextTick(cb.bind(null, er))
254       return this
255     }
256     return this.emit("error", er)
257   }
258
259   if (target.source) {
260     var pref = target.prefix || ""
261     Object.keys(target.data).forEach(function (k) {
262       target.source[pref + k] = target.data[k]
263     })
264     if (cb) process.nextTick(cb)
265     return this
266   }
267
268   var data = ini.stringify(target.data)
269
270   then = then.bind(this)
271   done = done.bind(this)
272   this._saving ++
273
274   var mode = where === "user" ? "0600" : "0666"
275   if (!data.trim()) {
276     fs.unlink(target.path, function () {
277       // ignore the possible error (e.g. the file doesn't exist)
278       done(null)
279     })
280   } else {
281     mkdirp(path.dirname(target.path), function (er) {
282       if (er)
283         return then(er)
284       fs.writeFile(target.path, data, "utf8", function (er) {
285         if (er)
286           return then(er)
287         if (where === "user" && myUid && myGid)
288           fs.chown(target.path, +myUid, +myGid, then)
289         else
290           then()
291       })
292     })
293   }
294
295   function then (er) {
296     if (er)
297       return done(er)
298     fs.chmod(target.path, mode, done)
299   }
300
301   function done (er) {
302     if (er) {
303       if (cb) return cb(er)
304       else return this.emit("error", er)
305     }
306     this._saving --
307     if (this._saving === 0) {
308       if (cb) cb()
309       this.emit("save")
310     }
311   }
312
313   return this
314 }
315
316 Conf.prototype.addFile = function (file, name) {
317   name = name || file
318   var marker = {__source__:name}
319   this.sources[name] = { path: file, type: "ini" }
320   this.push(marker)
321   this._await()
322   fs.readFile(file, "utf8", function (er, data) {
323     if (er) // just ignore missing files.
324       return this.add({}, marker)
325     this.addString(data, file, "ini", marker)
326   }.bind(this))
327   return this
328 }
329
330 // always ini files.
331 Conf.prototype.parse = function (content, file) {
332   return CC.prototype.parse.call(this, content, file, "ini")
333 }
334
335 Conf.prototype.add = function (data, marker) {
336   try {
337     Object.keys(data).forEach(function (k) {
338       data[k] = parseField(data[k], k)
339     })
340   }
341   catch (e) {
342     this.emit("error", e)
343     return this
344   }
345   return CC.prototype.add.call(this, data, marker)
346 }
347
348 Conf.prototype.addEnv = function (env) {
349   env = env || process.env
350   var conf = {}
351   Object.keys(env)
352     .filter(function (k) { return k.match(/^npm_config_/i) })
353     .forEach(function (k) {
354       if (!env[k])
355         return
356
357       // leave first char untouched, even if
358       // it is a "_" - convert all other to "-"
359       var p = k.toLowerCase()
360                .replace(/^npm_config_/, "")
361                .replace(/(?!^)_/g, "-")
362       conf[p] = env[k]
363     })
364   return CC.prototype.addEnv.call(this, "", conf, "env")
365 }
366
367 function parseField (f, k) {
368   if (typeof f !== "string" && !(f instanceof String))
369     return f
370
371   // type can be an array or single thing.
372   var typeList = [].concat(types[k])
373   var isPath = -1 !== typeList.indexOf(path)
374   var isBool = -1 !== typeList.indexOf(Boolean)
375   var isString = -1 !== typeList.indexOf(String)
376   var isUmask = -1 !== typeList.indexOf(Umask)
377   var isNumber = -1 !== typeList.indexOf(Number)
378
379   f = (""+f).trim()
380
381   if (f.match(/^".*"$/)) {
382     try {
383       f = JSON.parse(f)
384     }
385     catch (e) {
386       throw new Error("Failed parsing JSON config key " + k + ": " + f)
387     }
388   }
389
390   if (isBool && !isString && f === "")
391     return true
392
393   switch (f) {
394     case "true": return true
395     case "false": return false
396     case "null": return null
397     case "undefined": return undefined
398   }
399
400   f = envReplace(f)
401
402   if (isPath) {
403     var homePattern = process.platform === "win32" ? /^~(\/|\\)/ : /^~\//
404     if (f.match(homePattern) && process.env.HOME) {
405       f = path.resolve(process.env.HOME, f.substr(2))
406     }
407     f = path.resolve(f)
408   }
409
410   if (isUmask)
411     f = umask.fromString(f)
412
413   if (isNumber && !isNaN(f))
414     f = +f
415
416   return f
417 }
418
419 function envReplace (f) {
420   if (typeof f !== "string" || !f) return f
421
422   // replace any ${ENV} values with the appropriate environ.
423   var envExpr = /(\\*)\$\{([^}]+)\}/g
424   return f.replace(envExpr, function (orig, esc, name) {
425     esc = esc.length && esc.length % 2
426     if (esc)
427       return orig
428     if (undefined === process.env[name])
429       throw new Error("Failed to replace env in config: "+orig)
430     return process.env[name]
431   })
432 }
433
434 function validate (cl) {
435   // warn about invalid configs at every level.
436   cl.list.forEach(function (conf) {
437     nopt.clean(conf, configDefs.types)
438   })
439
440   nopt.clean(cl.root, configDefs.types)
441 }