UNPKG

13.3 kBJavaScriptView Raw
1;(function(){
2// windows: running "npm blah" in this folder will invoke WSH, not node.
3if (typeof WScript !== "undefined") {
4 WScript.echo("npm does not work when run\n"
5 +"with the Windows Scripting Host\n\n"
6 +"'cd' to a different directory,\n"
7 +"or type 'npm.cmd <args>',\n"
8 +"or type 'node npm <args>'.")
9 WScript.quit(1)
10 return
11}
12
13// patch JSON.parse() to use custom fallback
14require('jju').utils.patch_JSON_parse()
15
16// monkey-patch support for 0.6 child processes
17require('child-process-close')
18
19var EventEmitter = require("events").EventEmitter
20 , npm = module.exports = new EventEmitter()
21 , npmconf = require("./config/core.js")
22 , log = require("npmlog")
23 , fs = require("graceful-fs")
24 , path = require("path")
25 , abbrev = require("abbrev")
26 , which = require("which")
27 , semver = require("semver")
28 , jju = require("jju")
29 , RegClient = require("npm-registry-client")
30 , CachingRegClient = require("./cache/caching-client.js")
31 , charSpin = require("char-spinner")
32
33npm.config = {
34 loaded: false,
35 get: function() {
36 throw new Error('npm.load() required')
37 },
38 set: function() {
39 throw new Error('npm.load() required')
40 }
41}
42
43npm.commands = {}
44
45npm.rollbacks = []
46
47try {
48 // startup, ok to do this synchronously
49 var j = jju.parse(fs.readFileSync(
50 path.join(__dirname, "../package.json5"))+"")
51 npm.name = j.name
52 npm.version = j.version
53 npm.origVersion = j.npm_version
54} catch (ex) {
55 try {
56 log.info("error reading version", ex)
57 } catch (er) {}
58 npm.version = ex
59}
60
61var commandCache = {}
62 // short names for common things
63 , aliases = { "rm" : "uninstall"
64 , "r" : "uninstall"
65 , "un" : "uninstall"
66 , "unlink" : "uninstall"
67 , "remove" : "uninstall"
68 , "rb" : "rebuild"
69 , "list" : "ls"
70 , "la" : "ls"
71 , "ll" : "ls"
72 , "ln" : "link"
73 , "i" : "install"
74 , "isntall" : "install"
75 , "up" : "update"
76 , "c" : "config"
77 , "dist-tags" : "dist-tag"
78 , "info" : "view"
79 , "show" : "view"
80 , "find" : "search"
81 , "s" : "search"
82 , "se" : "search"
83 , "author" : "owner"
84 , "home" : "docs"
85 , "issues": "bugs"
86 , "unstar": "star" // same function
87 , "apihelp" : "help"
88 , "login": "adduser"
89 , "add-user": "adduser"
90 , "tst": "test"
91 , "t": "test"
92 , "find-dupes": "dedupe"
93 , "ddp": "dedupe"
94 , "v": "view"
95 , "verison": "version"
96 }
97
98 , aliasNames = Object.keys(aliases)
99 // these are filenames in .
100 , cmdList = [ "install"
101 , "uninstall"
102 , "cache"
103 , "config"
104 , "set"
105 , "get"
106 , "update"
107 , "outdated"
108 , "prune"
109 , "pack"
110 , "dedupe"
111
112 , "rebuild"
113 , "link"
114
115 , "publish"
116 , "star"
117 , "stars"
118 , "tag"
119 , "adduser"
120 , "unpublish"
121 , "owner"
122 , "access"
123 , "deprecate"
124 , "shrinkwrap"
125
126 , "help"
127 , "help-search"
128 , "ls"
129 , "search"
130 , "view"
131 , "init"
132 , "version"
133 , "edit"
134 , "explore"
135 , "docs"
136 , "repo"
137 , "bugs"
138 , "faq"
139 , "root"
140 , "prefix"
141 , "bin"
142 , "whoami"
143 , "dist-tag"
144
145 , "test"
146 , "stop"
147 , "start"
148 , "restart"
149 , "run-script"
150 , "completion"
151 ]
152 , plumbing = [ "build"
153 , "unbuild"
154 , "xmas"
155 , "substack"
156 , "visnup"
157 ]
158 , littleGuys = [ "isntall" ]
159 , fullList = cmdList.concat(aliasNames).filter(function (c) {
160 return plumbing.indexOf(c) === -1
161 })
162 , abbrevs = abbrev(fullList)
163
164// we have our reasons
165fullList = npm.fullList = fullList.filter(function (c) {
166 return littleGuys.indexOf(c) === -1
167})
168
169npm.spinner =
170 { int: null
171 , started: false
172 , start: function () {
173 if (npm.spinner.int) return
174 var c = npm.config.get("spin")
175 if (!c) return
176 var stream = npm.config.get("logstream")
177 var opt = { tty: c !== "always", stream: stream }
178 opt.cleanup = !npm.spinner.started
179 npm.spinner.int = charSpin(opt)
180 npm.spinner.started = true
181 }
182 , stop: function () {
183 clearInterval(npm.spinner.int)
184 npm.spinner.int = null
185 }
186 }
187
188Object.keys(abbrevs).concat(plumbing).forEach(function addCommand (c) {
189 Object.defineProperty(npm.commands, c, { get : function () {
190 if (!loaded) throw new Error(
191 "Call npm.load(config, cb) before using this command.\n"+
192 "See the README.md or cli.js for example usage.")
193 var a = npm.deref(c)
194 if (c === "la" || c === "ll") {
195 npm.config.set("long", true)
196 }
197
198 npm.command = c
199 if (commandCache[a]) return commandCache[a]
200
201 var cmd = require(__dirname+"/"+a+".js")
202
203 commandCache[a] = function () {
204 var args = Array.prototype.slice.call(arguments, 0)
205 if (typeof args[args.length - 1] !== "function") {
206 args.push(defaultCb)
207 }
208 if (args.length === 1) args.unshift([])
209
210 npm.registry.version = npm.version
211 if (!npm.registry.refer) {
212 npm.registry.refer = [a].concat(args[0]).map(function (arg) {
213 // exclude anything that might be a URL, path, or private module
214 // Those things will always have a slash in them somewhere
215 if (arg && arg.match && arg.match(/\/|\\/)) {
216 return "[REDACTED]"
217 } else {
218 return arg
219 }
220 }).filter(function (arg) {
221 return arg && arg.match
222 }).join(" ")
223 }
224
225 cmd.apply(npm, args)
226 }
227
228 Object.keys(cmd).forEach(function (k) {
229 commandCache[a][k] = cmd[k]
230 })
231
232 return commandCache[a]
233 }, enumerable: fullList.indexOf(c) !== -1 })
234
235 // make css-case commands callable via camelCase as well
236 if (c.match(/\-([a-z])/)) {
237 addCommand(c.replace(/\-([a-z])/g, function (a, b) {
238 return b.toUpperCase()
239 }))
240 }
241})
242
243function defaultCb (er, data) {
244 if (er) console.error(er.stack || er.message)
245 else console.log(data)
246}
247
248npm.deref = function (c) {
249 if (!c) return ""
250 if (c.match(/[A-Z]/)) c = c.replace(/([A-Z])/g, function (m) {
251 return "-" + m.toLowerCase()
252 })
253 if (plumbing.indexOf(c) !== -1) return c
254 var a = abbrevs[c]
255 if (aliases[a]) a = aliases[a]
256 return a
257}
258
259var loaded = false
260 , loading = false
261 , loadErr = null
262 , loadListeners = []
263
264function loadCb (er) {
265 loadListeners.forEach(function (cb) {
266 process.nextTick(cb.bind(npm, er, npm))
267 })
268 loadListeners.length = 0
269}
270
271npm.load = function (cli, cb_) {
272 if (!cb_ && typeof cli === "function") cb_ = cli , cli = {}
273 if (!cb_) cb_ = function () {}
274 if (!cli) cli = {}
275 loadListeners.push(cb_)
276 if (loaded || loadErr) return cb(loadErr)
277 if (loading) return
278 loading = true
279 var onload = true
280
281 function cb (er) {
282 if (loadErr) return
283 loadErr = er
284 if (er) return cb_(er)
285 if (npm.config.get("force")) {
286 log.warn("using --force", "I sure hope you know what you are doing.")
287 }
288 npm.config.loaded = true
289 loaded = true
290 loadCb(loadErr = er)
291 if (onload = onload && npm.config.get("onload-script")) {
292 require(onload)
293 onload = false
294 }
295 }
296
297 log.pause()
298
299 load(npm, cli, cb)
300}
301
302function load (npm, cli, cb) {
303 which(process.argv[0], function (er, node) {
304 if (!er && node.toUpperCase() !== process.execPath.toUpperCase()) {
305 log.verbose("node symlink", node)
306 process.execPath = node
307 process.installPrefix = path.resolve(node, "..", "..")
308 }
309
310 // look up configs
311 //console.error("about to look up configs")
312
313 var builtin = path.resolve(__dirname, "..", "npmrc")
314 npmconf.load(cli, builtin, function (er, config) {
315 if (er === config) er = null
316
317 npm.config = config
318 if (er) return cb(er)
319
320 // if the "project" config is not a filename, and we're
321 // not in global mode, then that means that it collided
322 // with either the default or effective userland config
323 if (!config.get("global")
324 && config.sources.project
325 && config.sources.project.type !== "ini") {
326 log.verbose("config"
327 , "Skipping project config: %s. "
328 + "(matches userconfig)"
329 , config.localPrefix + "/.npmrc")
330 }
331
332 // Include npm-version and node-version in user-agent
333 var ua = config.get("user-agent") || ""
334 ua = ua.replace(/\{node-version\}/gi, process.version)
335 ua = ua.replace(/\{npm-version\}/gi, npm.origVersion)
336 ua = ua.replace(/\{yapm-version\}/gi, npm.version)
337 ua = ua.replace(/\{platform\}/gi, process.platform)
338 ua = ua.replace(/\{arch\}/gi, process.arch)
339 config.set("user-agent", ua)
340
341 var color = config.get("color")
342
343 log.level = config.get("loglevel")
344 log.heading = config.get("heading") || "npm"
345 log.stream = config.get("logstream")
346
347 switch (color) {
348 case "always":
349 log.enableColor()
350 npm.color = true
351 break
352 case false:
353 log.disableColor()
354 npm.color = false
355 break
356 default:
357 var tty = require("tty")
358 if (process.stdout.isTTY) npm.color = true
359 else if (!tty.isatty) npm.color = true
360 else if (tty.isatty(1)) npm.color = true
361 else npm.color = false
362 break
363 }
364
365 var progress_enabled
366 switch (npm.config.get('progress')) {
367 case "always": progress_enabled = true; break
368 case false: progress_enabled = false; break
369 default: progress_enabled = npm.color;
370 }
371 require('yapm-progress').enabled = progress_enabled
372
373 require('package-yaml').setup(npm.config.get('yapm-formats').split(','))
374
375 log.resume()
376
377 // at this point the configs are all set.
378 // go ahead and spin up the registry client.
379 npm.registry = new CachingRegClient(npm.config)
380
381 var umask = npm.config.get("umask")
382 npm.modes = { exec: 0777 & (~umask)
383 , file: 0666 & (~umask)
384 , umask: umask }
385
386 var gp = Object.getOwnPropertyDescriptor(config, "globalPrefix")
387 Object.defineProperty(npm, "globalPrefix", gp)
388
389 var lp = Object.getOwnPropertyDescriptor(config, "localPrefix")
390 Object.defineProperty(npm, "localPrefix", lp)
391
392 return cb(null, npm)
393 })
394 })
395}
396
397Object.defineProperty(npm, "prefix",
398 { get : function () {
399 return npm.config.get("global") ? npm.globalPrefix : npm.localPrefix
400 }
401 , set : function (r) {
402 var k = npm.config.get("global") ? "globalPrefix" : "localPrefix"
403 return npm[k] = r
404 }
405 , enumerable : true
406 })
407
408Object.defineProperty(npm, "bin",
409 { get : function () {
410 if (npm.config.get("global")) return npm.globalBin
411 return path.resolve(npm.root, ".bin")
412 }
413 , enumerable : true
414 })
415
416Object.defineProperty(npm, "globalBin",
417 { get : function () {
418 var b = npm.globalPrefix
419 if (process.platform !== "win32") b = path.resolve(b, "bin")
420 return b
421 }
422 })
423
424Object.defineProperty(npm, "dir",
425 { get : function () {
426 if (npm.config.get("global")) return npm.globalDir
427 return path.resolve(npm.prefix, "node_modules")
428 }
429 , enumerable : true
430 })
431
432Object.defineProperty(npm, "globalDir",
433 { get : function () {
434 return (process.platform !== "win32")
435 ? path.resolve(npm.globalPrefix, "lib", "node_modules")
436 : path.resolve(npm.globalPrefix, "node_modules")
437 }
438 , enumerable : true
439 })
440
441Object.defineProperty(npm, "root",
442 { get : function () { return npm.dir } })
443
444Object.defineProperty(npm, "cache",
445 { get : function () { return npm.config.get("cache") }
446 , set : function (r) { return npm.config.set("cache", r) }
447 , enumerable : true
448 })
449
450var tmpFolder
451var rand = require("crypto").randomBytes(4).toString("hex")
452Object.defineProperty(npm, "tmp",
453 { get : function () {
454 if (!tmpFolder) tmpFolder = "npm-" + process.pid + "-" + rand
455 return path.resolve(npm.config.get("tmp"), tmpFolder)
456 }
457 , enumerable : true
458 })
459
460// the better to repl you with
461Object.getOwnPropertyNames(npm.commands).forEach(function (n) {
462 if (npm.hasOwnProperty(n) || n === "config") return
463
464 Object.defineProperty(npm, n, { get: function () {
465 return function () {
466 var args = Array.prototype.slice.call(arguments, 0)
467 , cb = defaultCb
468
469 if (args.length === 1 && Array.isArray(args[0])) {
470 args = args[0]
471 }
472
473 if (typeof args[args.length - 1] === "function") {
474 cb = args.pop()
475 }
476
477 npm.commands[n](args, cb)
478 }
479 }, enumerable: false, configurable: true })
480})
481
482})()