build.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // npm build command
  2. // everything about the installation after the creation of
  3. // the .npm/{name}/{version}/package folder.
  4. // linking the modules into the npm.root,
  5. // resolving dependencies, etc.
  6. // This runs AFTER install or link are completed.
  7. var npm = require('./npm.js')
  8. var log = require('npmlog')
  9. var chain = require('slide').chain
  10. var path = require('path')
  11. var fs = require('graceful-fs')
  12. var lifecycle = require('./utils/lifecycle.js')
  13. var readJson = require('read-package-json')
  14. var binLinks = require('bin-links')
  15. var binLinksConfig = require('./config/bin-links.js')
  16. var ini = require('ini')
  17. var writeFile = require('write-file-atomic')
  18. module.exports = build
  19. build.usage = 'npm build [<folder>]'
  20. build._didBuild = {}
  21. build._noLC = {}
  22. function build (args, global, didPre, didRB, cb) {
  23. if (typeof cb !== 'function') {
  24. cb = didRB
  25. didRB = false
  26. }
  27. if (typeof cb !== 'function') {
  28. cb = didPre
  29. didPre = false
  30. }
  31. if (typeof cb !== 'function') {
  32. cb = global
  33. global = npm.config.get('global')
  34. }
  35. if (!args.length) {
  36. readJson(path.resolve(npm.localPrefix, 'package.json'), function (er, pkg) {
  37. if (!args.length && pkg && pkg.scripts && pkg.scripts.build) {
  38. log.warn('build', '`npm build` called with no arguments. Did you mean to `npm run-script build`?')
  39. }
  40. cb()
  41. })
  42. } else {
  43. // it'd be nice to asyncMap these, but actually, doing them
  44. // in parallel generally munges up the output from node-waf
  45. var builder = build_(global, didPre, didRB)
  46. chain(args.map(function (arg) {
  47. return function (cb) {
  48. builder(arg, cb)
  49. }
  50. }), cb)
  51. }
  52. }
  53. function build_ (global, didPre, didRB) {
  54. return function (folder, cb) {
  55. folder = path.resolve(folder)
  56. if (build._didBuild[folder]) log.info('build', 'already built', folder)
  57. build._didBuild[folder] = true
  58. log.info('build', folder)
  59. readJson(path.resolve(folder, 'package.json'), function (er, pkg) {
  60. if (er) return cb(er)
  61. chain([
  62. !didPre && [lifecycle, pkg, 'preinstall', folder],
  63. [linkStuff, pkg, folder, global],
  64. !didRB && [rebuildBundles, pkg, folder],
  65. [writeBuiltinConf, pkg, folder],
  66. didPre !== build._noLC && [lifecycle, pkg, 'install', folder],
  67. didPre !== build._noLC && [lifecycle, pkg, 'postinstall', folder]
  68. ],
  69. cb)
  70. })
  71. }
  72. }
  73. var writeBuiltinConf = build.writeBuiltinConf = function (pkg, folder, cb) {
  74. // the builtin config is "sticky". Any time npm installs
  75. // itself globally, it puts its builtin config file there
  76. var parent = path.dirname(folder)
  77. var dir = npm.globalDir
  78. // Make this count for canary, too
  79. if ((pkg.name !== 'npm' && pkg.name !== 'npmc') ||
  80. !npm.config.get('global') ||
  81. !npm.config.usingBuiltin ||
  82. dir !== parent) {
  83. return cb()
  84. }
  85. var data = ini.stringify(npm.config.sources.builtin.data)
  86. writeFile(path.resolve(folder, 'npmrc'), data, cb)
  87. }
  88. var linkStuff = build.linkStuff = function (pkg, folder, global, cb) {
  89. // allow to opt out of linking binaries.
  90. if (npm.config.get('bin-links') === false) return cb()
  91. return binLinks(pkg, folder, global, binLinksConfig(pkg), cb)
  92. }
  93. function rebuildBundles (pkg, folder, cb) {
  94. if (!npm.config.get('rebuild-bundle')) return cb()
  95. var deps = Object.keys(pkg.dependencies || {})
  96. .concat(Object.keys(pkg.devDependencies || {}))
  97. var bundles = pkg.bundleDependencies || pkg.bundledDependencies || []
  98. fs.readdir(path.resolve(folder, 'node_modules'), function (er, files) {
  99. // error means no bundles
  100. if (er) return cb()
  101. log.verbose('rebuildBundles', files)
  102. // don't asyncMap these, because otherwise build script output
  103. // gets interleaved and is impossible to read
  104. chain(files.filter(function (file) {
  105. // rebuild if:
  106. // not a .folder, like .bin or .hooks
  107. return !file.match(/^[._-]/) &&
  108. // not some old 0.x style bundle
  109. file.indexOf('@') === -1 &&
  110. // either not a dep, or explicitly bundled
  111. (deps.indexOf(file) === -1 || bundles.indexOf(file) !== -1)
  112. }).map(function (file) {
  113. file = path.resolve(folder, 'node_modules', file)
  114. return function (cb) {
  115. if (build._didBuild[file]) return cb()
  116. log.verbose('rebuild bundle', file)
  117. // if file is not a package dir, then don't do it.
  118. fs.lstat(path.resolve(file, 'package.json'), function (er) {
  119. if (er) return cb()
  120. build_(false)(file, cb)
  121. })
  122. }
  123. }), cb)
  124. })
  125. }