npm.js 14 KB

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