UNPKG

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