/
installPackage.js
124 lines (103 loc) 路 3.09 KB
/
installPackage.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
const config = require('./config');
const promisify = require('./promisify');
const resolve = promisify(require('resolve'));
const commandExists = require('command-exists');
const logger = require('@parcel/logger');
const pipeSpawn = require('./pipeSpawn');
const PromiseQueue = require('./PromiseQueue');
const path = require('path');
const fs = require('./fs');
const WorkerFarm = require('@parcel/workers');
const YARN_LOCK = 'yarn.lock';
async function install(modules, filepath, options = {}) {
let {installPeers = true, saveDev = true, packageManager} = options;
if (typeof modules === 'string') {
modules = [modules];
}
logger.progress(`Installing ${modules.join(', ')}...`);
let packageLocation = await config.resolve(filepath, ['package.json']);
let cwd = packageLocation ? path.dirname(packageLocation) : process.cwd();
if (!packageManager) {
packageManager = await determinePackageManager(filepath);
}
let commandToUse = packageManager === 'npm' ? 'install' : 'add';
let args = [commandToUse, ...modules];
if (saveDev) {
args.push('-D');
} else if (packageManager === 'npm') {
args.push('--save');
}
// npm doesn't auto-create a package.json when installing,
// so create an empty one if needed.
if (packageManager === 'npm' && !packageLocation) {
await fs.writeFile(path.join(cwd, 'package.json'), '{}');
}
try {
await pipeSpawn(packageManager, args, {cwd});
} catch (err) {
throw new Error(`Failed to install ${modules.join(', ')}.`);
}
if (installPeers) {
await Promise.all(
modules.map(m => installPeerDependencies(filepath, m, options))
);
}
}
async function installPeerDependencies(filepath, name, options) {
let basedir = path.dirname(filepath);
const [resolved] = await resolve(name, {basedir});
const pkg = await config.load(resolved, ['package.json']);
const peers = pkg.peerDependencies || {};
const modules = [];
for (const peer in peers) {
modules.push(`${peer}@${peers[peer]}`);
}
if (modules.length) {
await install(
modules,
filepath,
Object.assign({}, options, {installPeers: false})
);
}
}
async function determinePackageManager(filepath) {
const yarnLockFile = await config.resolve(filepath, [YARN_LOCK]);
/**
* no yarn.lock => use npm
* yarn.lock => Use yarn, fallback to npm
*/
if (!yarnLockFile) {
return 'npm';
}
const hasYarn = await checkForYarnCommand();
if (hasYarn) {
return 'yarn';
}
return 'npm';
}
let hasYarn = null;
async function checkForYarnCommand() {
if (hasYarn != null) {
return hasYarn;
}
try {
hasYarn = await commandExists('yarn');
} catch (err) {
hasYarn = false;
}
return hasYarn;
}
let queue = new PromiseQueue(install, {maxConcurrent: 1, retry: false});
module.exports = async function(...args) {
// Ensure that this function is always called on the master process so we
// don't call multiple installs in parallel.
if (WorkerFarm.isWorker()) {
await WorkerFarm.callMaster({
location: __filename,
args
});
return;
}
queue.add(...args);
return queue.run();
};