• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1;(function () {
2  // windows: running 'npm blah' in this folder will invoke WSH, not node.
3  /* globals WScript */
4  if (typeof WScript !== 'undefined') {
5    WScript.echo(
6      'npm does not work when run\n' +
7      'with the Windows Scripting Host\n\n' +
8      '"cd" to a different directory,\n' +
9      'or type "npm.cmd <args>",\n' +
10      'or type "node npm <args>".'
11    )
12    WScript.quit(1)
13    return
14  }
15
16  var unsupported = require('../lib/utils/unsupported.js')
17  unsupported.checkForBrokenNode()
18
19  var gfs = require('graceful-fs')
20  // Patch the global fs module here at the app level
21  var fs = gfs.gracefulify(require('fs'))
22
23  var EventEmitter = require('events').EventEmitter
24  var npm = module.exports = new EventEmitter()
25  var npmconf = require('./config/core.js')
26  var log = require('npmlog')
27  var inspect = require('util').inspect
28
29  // capture global logging
30  process.on('log', function (level) {
31    try {
32      return log[level].apply(log, [].slice.call(arguments, 1))
33    } catch (ex) {
34      log.verbose('attempt to log ' + inspect(arguments) + ' crashed: ' + ex.message)
35    }
36  })
37
38  var path = require('path')
39  var abbrev = require('abbrev')
40  var which = require('which')
41  var glob = require('glob')
42  var rimraf = require('rimraf')
43  var parseJSON = require('./utils/parse-json.js')
44  var aliases = require('./config/cmd-list').aliases
45  var cmdList = require('./config/cmd-list').cmdList
46  var plumbing = require('./config/cmd-list').plumbing
47  var output = require('./utils/output.js')
48  var startMetrics = require('./utils/metrics.js').start
49  var perf = require('./utils/perf.js')
50
51  perf.emit('time', 'npm')
52  perf.on('timing', function (name, finished) {
53    log.timing(name, 'Completed in', finished + 'ms')
54  })
55
56  npm.config = {
57    loaded: false,
58    get: function () {
59      throw new Error('npm.load() required')
60    },
61    set: function () {
62      throw new Error('npm.load() required')
63    }
64  }
65
66  npm.commands = {}
67
68  // TUNING
69  npm.limit = {
70    fetch: 10,
71    action: 50
72  }
73  // ***
74
75  npm.lockfileVersion = 1
76
77  npm.rollbacks = []
78
79  try {
80    // startup, ok to do this synchronously
81    var j = parseJSON(fs.readFileSync(
82      path.join(__dirname, '../package.json')) + '')
83    npm.name = j.name
84    npm.version = j.version
85  } catch (ex) {
86    try {
87      log.info('error reading version', ex)
88    } catch (er) {}
89    npm.version = ex
90  }
91
92  var commandCache = {}
93  var aliasNames = Object.keys(aliases)
94
95  var littleGuys = [ 'isntall', 'verison' ]
96  var fullList = cmdList.concat(aliasNames).filter(function (c) {
97    return plumbing.indexOf(c) === -1
98  })
99  var abbrevs = abbrev(fullList)
100
101  // we have our reasons
102  fullList = npm.fullList = fullList.filter(function (c) {
103    return littleGuys.indexOf(c) === -1
104  })
105
106  var registryRefer
107
108  Object.keys(abbrevs).concat(plumbing).forEach(function addCommand (c) {
109    Object.defineProperty(npm.commands, c, { get: function () {
110      if (!loaded) {
111        throw new Error(
112          'Call npm.load(config, cb) before using this command.\n' +
113            'See the README.md or bin/npm-cli.js for example usage.'
114        )
115      }
116      var a = npm.deref(c)
117      if (c === 'la' || c === 'll') {
118        npm.config.set('long', true)
119      }
120
121      npm.command = c
122      if (commandCache[a]) return commandCache[a]
123
124      var cmd = require(path.join(__dirname, a + '.js'))
125
126      commandCache[a] = function () {
127        var args = Array.prototype.slice.call(arguments, 0)
128        if (typeof args[args.length - 1] !== 'function') {
129          args.push(defaultCb)
130        }
131        if (args.length === 1) args.unshift([])
132
133        // Options are prefixed by a hyphen-minus (-, \u2d).
134        // Other dash-type chars look similar but are invalid.
135        Array(args[0]).forEach(function (arg) {
136          if (/^[\u2010-\u2015\u2212\uFE58\uFE63\uFF0D]/.test(arg)) {
137            log.error('arg', 'Argument starts with non-ascii dash, this is probably invalid:', arg)
138          }
139        })
140
141        if (!registryRefer) {
142          registryRefer = [a].concat(args[0]).map(function (arg) {
143            // exclude anything that might be a URL, path, or private module
144            // Those things will always have a slash in them somewhere
145            if (arg && arg.match && arg.match(/\/|\\/)) {
146              return '[REDACTED]'
147            } else {
148              return arg
149            }
150          }).filter(function (arg) {
151            return arg && arg.match
152          }).join(' ')
153          npm.referer = registryRefer
154        }
155
156        cmd.apply(npm, args)
157      }
158
159      Object.keys(cmd).forEach(function (k) {
160        commandCache[a][k] = cmd[k]
161      })
162
163      return commandCache[a]
164    },
165    enumerable: fullList.indexOf(c) !== -1,
166    configurable: true })
167
168    // make css-case commands callable via camelCase as well
169    if (c.match(/-([a-z])/)) {
170      addCommand(c.replace(/-([a-z])/g, function (a, b) {
171        return b.toUpperCase()
172      }))
173    }
174  })
175
176  function defaultCb (er, data) {
177    log.disableProgress()
178    if (er) console.error(er.stack || er.message)
179    else output(data)
180  }
181
182  npm.deref = function (c) {
183    if (!c) return ''
184    if (c.match(/[A-Z]/)) {
185      c = c.replace(/([A-Z])/g, function (m) {
186        return '-' + m.toLowerCase()
187      })
188    }
189    if (plumbing.indexOf(c) !== -1) return c
190    var a = abbrevs[c]
191    while (aliases[a]) {
192      a = aliases[a]
193    }
194    return a
195  }
196
197  var loaded = false
198  var loading = false
199  var loadErr = null
200  var loadListeners = []
201
202  function loadCb (er) {
203    loadListeners.forEach(function (cb) {
204      process.nextTick(cb.bind(npm, er, npm))
205    })
206    loadListeners.length = 0
207  }
208
209  npm.load = function (cli, cb_) {
210    if (!cb_ && typeof cli === 'function') {
211      cb_ = cli
212      cli = {}
213    }
214    if (!cb_) cb_ = function () {}
215    if (!cli) cli = {}
216    loadListeners.push(cb_)
217    if (loaded || loadErr) return cb(loadErr)
218    if (loading) return
219    loading = true
220    var onload = true
221
222    function cb (er) {
223      if (loadErr) return
224      loadErr = er
225      if (er) return cb_(er)
226      if (npm.config.get('force')) {
227        log.warn('using --force', 'I sure hope you know what you are doing.')
228      }
229      npm.config.loaded = true
230      loaded = true
231      loadCb(loadErr = er)
232      onload = onload && npm.config.get('onload-script')
233      if (onload) {
234        try {
235          require(onload)
236        } catch (err) {
237          log.warn('onload-script', 'failed to require onload script', onload)
238          log.warn('onload-script', err)
239        }
240        onload = false
241      }
242    }
243
244    log.pause()
245
246    load(npm, cli, cb)
247  }
248
249  function load (npm, cli, cb) {
250    which(process.argv[0], function (er, node) {
251      if (!er && node.toUpperCase() !== process.execPath.toUpperCase()) {
252        log.verbose('node symlink', node)
253        process.execPath = node
254        process.installPrefix = path.resolve(node, '..', '..')
255      }
256
257      // look up configs
258      var builtin = path.resolve(__dirname, '..', 'npmrc')
259      npmconf.load(cli, builtin, function (er, config) {
260        if (er === config) er = null
261
262        npm.config = config
263        if (er) return cb(er)
264
265        // if the 'project' config is not a filename, and we're
266        // not in global mode, then that means that it collided
267        // with either the default or effective userland config
268        if (!config.get('global') &&
269            config.sources.project &&
270            config.sources.project.type !== 'ini') {
271          log.verbose(
272            'config',
273            'Skipping project config: %s. (matches userconfig)',
274            config.localPrefix + '/.npmrc'
275          )
276        }
277
278        // Include npm-version and node-version in user-agent
279        var ua = config.get('user-agent') || ''
280        ua = ua.replace(/\{node-version\}/gi, process.version)
281        ua = ua.replace(/\{npm-version\}/gi, npm.version)
282        ua = ua.replace(/\{platform\}/gi, process.platform)
283        ua = ua.replace(/\{arch\}/gi, process.arch)
284
285        // continuous integration platforms
286        const ciName = process.env.GERRIT_PROJECT ? 'gerrit'
287          : process.env.GITLAB_CI ? 'gitlab'
288            : process.env.APPVEYOR ? 'appveyor'
289              : process.env.CIRCLECI ? 'circle-ci'
290                : process.env.SEMAPHORE ? 'semaphore'
291                  : process.env.DRONE ? 'drone'
292                    : process.env.GITHUB_ACTION ? 'github-actions'
293                      : process.env.TDDIUM ? 'tddium'
294                        : process.env.JENKINS_URL ? 'jenkins'
295                          : process.env['bamboo.buildKey'] ? 'bamboo'
296                            : process.env.GO_PIPELINE_NAME ? 'gocd'
297                            // codeship and a few others
298                              : process.env.CI_NAME ? process.env.CI_NAME
299                              // test travis after the others, since several CI systems mimic it
300                                : process.env.TRAVIS ? 'travis-ci'
301                                // aws CodeBuild/CodePipeline
302                                  : process.env.CODEBUILD_SRC_DIR ? 'aws-codebuild'
303                                    : process.env.CI === 'true' || process.env.CI === '1' ? 'custom'
304                                    // Google Cloud Build - it sets almost nothing
305                                      : process.env.BUILDER_OUTPUT ? 'builder'
306                                        : false
307        const ci = ciName ? `ci/${ciName}` : ''
308        ua = ua.replace(/\{ci\}/gi, ci)
309
310        config.set('user-agent', ua.trim())
311
312        if (config.get('metrics-registry') == null) {
313          config.set('metrics-registry', config.get('registry'))
314        }
315
316        var color = config.get('color')
317
318        if (npm.config.get('timing') && npm.config.get('loglevel') === 'notice') {
319          log.level = 'timing'
320        } else {
321          log.level = config.get('loglevel')
322        }
323        log.heading = config.get('heading') || 'npm'
324        log.stream = config.get('logstream')
325
326        switch (color) {
327          case 'always':
328            npm.color = true
329            break
330          case false:
331            npm.color = false
332            break
333          default:
334            npm.color = process.stdout.isTTY && process.env['TERM'] !== 'dumb'
335            break
336        }
337        if (npm.color) {
338          log.enableColor()
339        } else {
340          log.disableColor()
341        }
342
343        if (config.get('unicode')) {
344          log.enableUnicode()
345        } else {
346          log.disableUnicode()
347        }
348
349        if (config.get('progress') && process.stderr.isTTY && process.env['TERM'] !== 'dumb') {
350          log.enableProgress()
351        } else {
352          log.disableProgress()
353        }
354
355        glob(path.resolve(npm.cache, '_logs', '*-debug.log'), function (er, files) {
356          if (er) return cb(er)
357
358          while (files.length >= npm.config.get('logs-max')) {
359            rimraf.sync(files[0])
360            files.splice(0, 1)
361          }
362        })
363
364        log.resume()
365
366        var umask = npm.config.get('umask')
367        npm.modes = {
368          exec: parseInt('0777', 8) & (~umask),
369          file: parseInt('0666', 8) & (~umask),
370          umask: umask
371        }
372
373        var gp = Object.getOwnPropertyDescriptor(config, 'globalPrefix')
374        Object.defineProperty(npm, 'globalPrefix', gp)
375
376        var lp = Object.getOwnPropertyDescriptor(config, 'localPrefix')
377        Object.defineProperty(npm, 'localPrefix', lp)
378
379        config.set('scope', scopeifyScope(config.get('scope')))
380        npm.projectScope = config.get('scope') ||
381         scopeifyScope(getProjectScope(npm.prefix))
382
383        startMetrics()
384
385        return cb(null, npm)
386      })
387    })
388  }
389
390  Object.defineProperty(npm, 'prefix',
391    {
392      get: function () {
393        return npm.config.get('global') ? npm.globalPrefix : npm.localPrefix
394      },
395      set: function (r) {
396        var k = npm.config.get('global') ? 'globalPrefix' : 'localPrefix'
397        npm[k] = r
398        return r
399      },
400      enumerable: true
401    })
402
403  Object.defineProperty(npm, 'bin',
404    {
405      get: function () {
406        if (npm.config.get('global')) return npm.globalBin
407        return path.resolve(npm.root, '.bin')
408      },
409      enumerable: true
410    })
411
412  Object.defineProperty(npm, 'globalBin',
413    {
414      get: function () {
415        var b = npm.globalPrefix
416        if (process.platform !== 'win32') b = path.resolve(b, 'bin')
417        return b
418      }
419    })
420
421  Object.defineProperty(npm, 'dir',
422    {
423      get: function () {
424        if (npm.config.get('global')) return npm.globalDir
425        return path.resolve(npm.prefix, 'node_modules')
426      },
427      enumerable: true
428    })
429
430  Object.defineProperty(npm, 'globalDir',
431    {
432      get: function () {
433        return (process.platform !== 'win32')
434          ? path.resolve(npm.globalPrefix, 'lib', 'node_modules')
435          : path.resolve(npm.globalPrefix, 'node_modules')
436      },
437      enumerable: true
438    })
439
440  Object.defineProperty(npm, 'root',
441    { get: function () { return npm.dir } })
442
443  Object.defineProperty(npm, 'cache',
444    { get: function () { return npm.config.get('cache') },
445      set: function (r) { return npm.config.set('cache', r) },
446      enumerable: true
447    })
448
449  var tmpFolder
450  var rand = require('crypto').randomBytes(4).toString('hex')
451  Object.defineProperty(npm, 'tmp',
452    {
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
461  Object.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        var 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        npm.commands[n](args, cb)
477      }
478    },
479    enumerable: false,
480    configurable: true })
481  })
482
483  if (require.main === module) {
484    require('../bin/npm-cli.js')
485  }
486
487  function scopeifyScope (scope) {
488    return (!scope || scope[0] === '@') ? scope : ('@' + scope)
489  }
490
491  function getProjectScope (prefix) {
492    try {
493      var pkg = JSON.parse(fs.readFileSync(path.join(prefix, 'package.json')))
494      if (typeof pkg.name !== 'string') return ''
495      var sep = pkg.name.indexOf('/')
496      if (sep === -1) return ''
497      return pkg.name.slice(0, sep)
498    } catch (ex) {
499      return ''
500    }
501  }
502})()
503