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