1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | var npm = require("./npm.js")
|
11 | , log = require("npmlog")
|
12 | , chain = require("slide").chain
|
13 | , fs = require("graceful-fs")
|
14 | , path = require("path")
|
15 | , lifecycle = require("./utils/lifecycle.js")
|
16 | , readJson = require("read-package-json")
|
17 | , link = require("./utils/link.js")
|
18 | , linkIfExists = link.ifExists
|
19 | , cmdShim = require("cmd-shim")
|
20 | , cmdShimIfExists = cmdShim.ifExists
|
21 | , asyncMap = require("slide").asyncMap
|
22 |
|
23 | module.exports = build
|
24 | build.usage = "npm build <folder>\n(this is plumbing)"
|
25 |
|
26 | build._didBuild = {}
|
27 | build._noLC = {}
|
28 | function build (args, global, didPre, didRB, cb) {
|
29 | if (typeof cb !== "function") cb = didRB, didRB = false
|
30 | if (typeof cb !== "function") cb = didPre, didPre = false
|
31 | if (typeof cb !== "function") {
|
32 | cb = global, global = npm.config.get("global")
|
33 | }
|
34 |
|
35 |
|
36 | var builder = build_(global, didPre, didRB)
|
37 | chain(args.map(function (arg) { return function (cb) {
|
38 | builder(arg, cb)
|
39 | }}), cb)
|
40 | }
|
41 |
|
42 | function build_ (global, didPre, didRB) { return function (folder, cb) {
|
43 | folder = path.resolve(folder)
|
44 | build._didBuild[folder] = true
|
45 | log.info("build", folder)
|
46 | readJson(path.resolve(folder, "package.json"), function (er, pkg) {
|
47 | if (er) return cb(er)
|
48 | chain
|
49 | ( [ !didPre && [lifecycle, pkg, "preinstall", folder]
|
50 | , [linkStuff, pkg, folder, global, didRB]
|
51 | , pkg.name === "npm" && [writeBuiltinConf, folder]
|
52 | , didPre !== build._noLC && [lifecycle, pkg, "install", folder]
|
53 | , didPre !== build._noLC && [lifecycle, pkg, "postinstall", folder]
|
54 | , didPre !== build._noLC
|
55 | && npm.config.get("npat")
|
56 | && [lifecycle, pkg, "test", folder] ]
|
57 | , cb )
|
58 | })
|
59 | }}
|
60 |
|
61 | function writeBuiltinConf (folder, cb) {
|
62 |
|
63 |
|
64 | if (!npm.config.usingBuiltin
|
65 | || folder !== path.dirname(__dirname)) {
|
66 | return cb()
|
67 | }
|
68 | npm.config.save("builtin", cb)
|
69 | }
|
70 |
|
71 | function linkStuff (pkg, folder, global, didRB, cb) {
|
72 |
|
73 | if (npm.config.get("bin-links") === false) return cb()
|
74 |
|
75 |
|
76 |
|
77 |
|
78 | var parent = path.dirname(folder)
|
79 | , gnm = global && npm.globalDir
|
80 | , top = parent === npm.dir
|
81 | , gtop = parent === gnm
|
82 |
|
83 | log.verbose("linkStuff", [global, gnm, gtop, parent])
|
84 | log.info("linkStuff", pkg._id)
|
85 |
|
86 | shouldWarn(pkg, folder, global, function() {
|
87 | asyncMap( [linkBins, linkMans, !didRB && rebuildBundles]
|
88 | , function (fn, cb) {
|
89 | if (!fn) return cb()
|
90 | log.verbose(fn.name, pkg._id)
|
91 | fn(pkg, folder, parent, gtop, cb)
|
92 | }, cb)
|
93 | })
|
94 | }
|
95 |
|
96 | function shouldWarn(pkg, folder, global, cb) {
|
97 | var parent = path.dirname(folder)
|
98 | , top = parent === npm.dir
|
99 | , cwd = process.cwd()
|
100 |
|
101 | readJson(path.resolve(cwd, "package.json"), function(er, topPkg) {
|
102 | if (er) return cb(er)
|
103 |
|
104 | var linkedPkg = path.basename(cwd)
|
105 | , currentPkg = path.basename(folder)
|
106 |
|
107 |
|
108 | if (linkedPkg !== currentPkg) {
|
109 |
|
110 | if (!topPkg.dependencies) return cb()
|
111 |
|
112 |
|
113 | if (Object.keys(topPkg.dependencies).indexOf(currentPkg) === -1) {
|
114 |
|
115 | if (top && pkg.preferGlobal && !global) {
|
116 | log.warn("prefer global", pkg._id + " should be installed with -g")
|
117 | }
|
118 | }
|
119 | }
|
120 |
|
121 | cb()
|
122 | })
|
123 | }
|
124 |
|
125 | function rebuildBundles (pkg, folder, parent, gtop, cb) {
|
126 | if (!npm.config.get("rebuild-bundle")) return cb()
|
127 |
|
128 | var deps = Object.keys(pkg.dependencies || {})
|
129 | .concat(Object.keys(pkg.devDependencies || {}))
|
130 | , bundles = pkg.bundleDependencies || pkg.bundledDependencies || []
|
131 |
|
132 | fs.readdir(path.resolve(folder, "node_modules"), function (er, files) {
|
133 |
|
134 | if (er) return cb()
|
135 |
|
136 | log.verbose("rebuildBundles", files)
|
137 |
|
138 |
|
139 | chain(files.filter(function (file) {
|
140 |
|
141 |
|
142 | return !file.match(/^[\._-]/)
|
143 |
|
144 | && file.indexOf("@") === -1
|
145 |
|
146 | && (deps.indexOf(file) === -1 || bundles.indexOf(file) !== -1)
|
147 | }).map(function (file) {
|
148 | file = path.resolve(folder, "node_modules", file)
|
149 | return function (cb) {
|
150 | if (build._didBuild[file]) return cb()
|
151 | log.verbose("rebuild bundle", file)
|
152 |
|
153 | fs.lstat(path.resolve(file, "package.json"), function (er, st) {
|
154 | if (er) return cb()
|
155 | build_(false)(file, cb)
|
156 | })
|
157 | }}), cb)
|
158 | })
|
159 | }
|
160 |
|
161 | function linkBins (pkg, folder, parent, gtop, cb) {
|
162 | if (!pkg.bin || !gtop && path.basename(parent) !== "node_modules") {
|
163 | return cb()
|
164 | }
|
165 | var binRoot = gtop ? npm.globalBin
|
166 | : path.resolve(parent, ".bin")
|
167 | log.verbose("link bins", [pkg.bin, binRoot, gtop])
|
168 |
|
169 | asyncMap(Object.keys(pkg.bin), function (b, cb) {
|
170 | linkBin( path.resolve(folder, pkg.bin[b])
|
171 | , path.resolve(binRoot, b)
|
172 | , gtop && folder
|
173 | , function (er) {
|
174 | if (er) return cb(er)
|
175 |
|
176 |
|
177 | var src = path.resolve(folder, pkg.bin[b])
|
178 | fs.chmod(src, npm.modes.exec, function (er) {
|
179 | if (er && er.code === "ENOENT" && npm.config.get("ignore-scripts")) {
|
180 | return cb()
|
181 | }
|
182 | if (er || !gtop) return cb(er)
|
183 | var dest = path.resolve(binRoot, b)
|
184 | , out = npm.config.get("parseable")
|
185 | ? dest + "::" + src + ":BINFILE"
|
186 | : dest + " -> " + src
|
187 | console.log(out)
|
188 | cb()
|
189 | })
|
190 | })
|
191 | }, cb)
|
192 | }
|
193 |
|
194 | function linkBin (from, to, gently, cb) {
|
195 | if (process.platform !== "win32") {
|
196 | return linkIfExists(from, to, gently, cb)
|
197 | } else {
|
198 | return cmdShimIfExists(from, to, cb)
|
199 | }
|
200 | }
|
201 |
|
202 | function linkMans (pkg, folder, parent, gtop, cb) {
|
203 | if (!pkg.man || !gtop || process.platform === "win32") return cb()
|
204 |
|
205 | var manRoot = path.resolve(npm.config.get("prefix"), "share", "man")
|
206 |
|
207 |
|
208 |
|
209 | var set = pkg.man.reduce(function (acc, man) {
|
210 | acc[path.basename(man)] = man
|
211 | return acc
|
212 | }, {})
|
213 | pkg.man = pkg.man.filter(function (man) {
|
214 | return set[path.basename(man)] === man
|
215 | })
|
216 |
|
217 | asyncMap(pkg.man, function (man, cb) {
|
218 | if (typeof man !== "string") return cb()
|
219 | var parseMan = man.match(/(.*\.([0-9]+)(\.gz)?)$/)
|
220 | , stem = parseMan[1]
|
221 | , sxn = parseMan[2]
|
222 | , gz = parseMan[3] || ""
|
223 | , bn = path.basename(stem)
|
224 | , manDest = path.join(manRoot, "man" + sxn, bn)
|
225 |
|
226 | linkIfExists(man, manDest, gtop && folder, cb)
|
227 | }, cb)
|
228 | }
|