-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
npm-install.js
142 lines (110 loc) · 3.97 KB
/
npm-install.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"use strict";
const fs = require("fs-extra");
const log = require("npmlog");
const npa = require("npm-package-arg");
const onExit = require("signal-exit");
const writePkg = require("write-pkg");
const ChildProcessUtilities = require("@lerna/child-process");
const getExecOpts = require("@lerna/get-npm-exec-opts");
module.exports = npmInstall;
module.exports.dependencies = npmInstallDependencies;
function npmInstall(
pkg,
{ registry, npmClient, npmClientArgs, npmGlobalStyle, mutex, stdio = "pipe", subCommand = "install" }
) {
// build command, arguments, and options
const opts = getExecOpts(pkg, registry);
const args = [subCommand];
let cmd = npmClient || "npm";
if (npmGlobalStyle) {
cmd = "npm";
args.push("--global-style");
}
if (cmd === "yarn" && mutex) {
args.push("--mutex", mutex);
}
if (cmd === "yarn") {
args.push("--non-interactive");
}
if (npmClientArgs && npmClientArgs.length) {
args.push(...npmClientArgs);
}
// potential override, e.g. "inherit" in root-only bootstrap
opts.stdio = stdio;
log.silly("npmInstall", [cmd, args]);
return ChildProcessUtilities.exec(cmd, args, opts);
}
function npmInstallDependencies(pkg, dependencies, config) {
log.silly("npmInstallDependencies", pkg.name, dependencies);
// Nothing to do if we weren't given any deps.
if (!(dependencies && dependencies.length)) {
log.verbose("npmInstallDependencies", "no dependencies to install");
return Promise.resolve();
}
const packageJsonBkp = `${pkg.manifestLocation}.lerna_backup`;
log.silly("npmInstallDependencies", "backup", pkg.manifestLocation);
return fs.rename(pkg.manifestLocation, packageJsonBkp).then(() => {
const cleanup = () => {
log.silly("npmInstallDependencies", "cleanup", pkg.manifestLocation);
// Need to do this one synchronously because we might be doing it on exit.
fs.renameSync(packageJsonBkp, pkg.manifestLocation);
};
// If we die we need to be sure to put things back the way we found them.
const unregister = onExit(cleanup);
// We have a few housekeeping tasks to take care of whether we succeed or fail.
const done = finalError => {
cleanup();
unregister();
if (finalError) {
throw finalError;
}
};
// mutate a clone of the manifest with our new versions
const tempJson = transformManifest(pkg, dependencies);
log.silly("npmInstallDependencies", "writing tempJson", tempJson);
// Write out our temporary cooked up package.json and then install.
return writePkg(pkg.manifestLocation, tempJson)
.then(() => npmInstall(pkg, config))
.then(() => done(), done);
});
}
function transformManifest(pkg, dependencies) {
const json = pkg.toJSON();
// a map of depName => depVersion (resolved by npm-package-arg)
const depMap = new Map(
dependencies.map(dep => {
const { name, rawSpec } = npa(dep, pkg.location);
return [name, rawSpec || "*"];
})
);
// don't run lifecycle scripts
delete json.scripts;
// filter all types of dependencies
["dependencies", "devDependencies", "optionalDependencies"].forEach(depType => {
const collection = json[depType];
if (collection) {
Object.keys(collection).forEach(depName => {
if (depMap.has(depName)) {
// overwrite version to ensure it's always present (and accurate)
collection[depName] = depMap.get(depName);
// only add to one collection, also keeps track of leftovers
depMap.delete(depName);
} else {
// filter out localDependencies and _duplicate_ external deps
delete collection[depName];
}
});
}
});
// add all leftovers (root hoisted)
if (depMap.size) {
if (!json.dependencies) {
// TODO: this should definitely be versioned, not blown away after install :/
json.dependencies = {};
}
depMap.forEach((depVersion, depName) => {
json.dependencies[depName] = depVersion;
});
}
return json;
}