1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.installDependencies = exports.runPackageJsonScript = exports.runPipInstall = exports.runBundleInstall = exports.runNpmInstall = exports.walkParentDirs = exports.getNodeVersion = exports.getSpawnOptions = exports.runShellScript = exports.getNodeBinPath = exports.execCommand = exports.spawnCommand = exports.execAsync = exports.spawnAsync = void 0;
|
7 | const assert_1 = __importDefault(require("assert"));
|
8 | const fs_extra_1 = __importDefault(require("fs-extra"));
|
9 | const path_1 = __importDefault(require("path"));
|
10 | const debug_1 = __importDefault(require("../debug"));
|
11 | const cross_spawn_1 = __importDefault(require("cross-spawn"));
|
12 | const util_1 = require("util");
|
13 | const os_1 = require("os");
|
14 | const errors_1 = require("../errors");
|
15 | const node_version_1 = require("./node-version");
|
16 | function spawnAsync(command, args, opts = {}) {
|
17 | return new Promise((resolve, reject) => {
|
18 | const stderrLogs = [];
|
19 | opts = { stdio: 'inherit', ...opts };
|
20 | const child = cross_spawn_1.default(command, args, opts);
|
21 | if (opts.stdio === 'pipe' && child.stderr) {
|
22 | child.stderr.on('data', data => stderrLogs.push(data));
|
23 | }
|
24 | child.on('error', reject);
|
25 | child.on('close', (code, signal) => {
|
26 | if (code === 0) {
|
27 | return resolve();
|
28 | }
|
29 | const cmd = opts.prettyCommand
|
30 | ? `Command "${opts.prettyCommand}"`
|
31 | : 'Command';
|
32 | reject(new errors_1.NowBuildError({
|
33 | code: `BUILD_UTILS_SPAWN_${code || signal}`,
|
34 | message: opts.stdio === 'inherit'
|
35 | ? `${cmd} exited with ${code || signal}`
|
36 | : stderrLogs.map(line => line.toString()).join(''),
|
37 | }));
|
38 | });
|
39 | });
|
40 | }
|
41 | exports.spawnAsync = spawnAsync;
|
42 | function execAsync(command, args, opts = {}) {
|
43 | return new Promise((resolve, reject) => {
|
44 | opts.stdio = 'pipe';
|
45 | const stdoutList = [];
|
46 | const stderrList = [];
|
47 | const child = cross_spawn_1.default(command, args, opts);
|
48 | child.stderr.on('data', data => {
|
49 | stderrList.push(data);
|
50 | });
|
51 | child.stdout.on('data', data => {
|
52 | stdoutList.push(data);
|
53 | });
|
54 | child.on('error', reject);
|
55 | child.on('close', (code, signal) => {
|
56 | if (code !== 0) {
|
57 | const cmd = opts.prettyCommand
|
58 | ? `Command "${opts.prettyCommand}"`
|
59 | : 'Command';
|
60 | return reject(new errors_1.NowBuildError({
|
61 | code: `BUILD_UTILS_EXEC_${code || signal}`,
|
62 | message: `${cmd} exited with ${code || signal}`,
|
63 | }));
|
64 | }
|
65 | return resolve({
|
66 | code,
|
67 | stdout: Buffer.concat(stdoutList).toString(),
|
68 | stderr: Buffer.concat(stderrList).toString(),
|
69 | });
|
70 | });
|
71 | });
|
72 | }
|
73 | exports.execAsync = execAsync;
|
74 | function spawnCommand(command, options = {}) {
|
75 | const opts = { ...options, prettyCommand: command };
|
76 | if (process.platform === 'win32') {
|
77 | return cross_spawn_1.default('cmd.exe', ['/C', command], opts);
|
78 | }
|
79 | return cross_spawn_1.default('sh', ['-c', command], opts);
|
80 | }
|
81 | exports.spawnCommand = spawnCommand;
|
82 | async function execCommand(command, options = {}) {
|
83 | const opts = { ...options, prettyCommand: command };
|
84 | if (process.platform === 'win32') {
|
85 | await spawnAsync('cmd.exe', ['/C', command], opts);
|
86 | }
|
87 | else {
|
88 | await spawnAsync('sh', ['-c', command], opts);
|
89 | }
|
90 | return true;
|
91 | }
|
92 | exports.execCommand = execCommand;
|
93 | async function getNodeBinPath({ cwd }) {
|
94 | const { stdout } = await execAsync('npm', ['bin'], { cwd });
|
95 | return stdout.trim();
|
96 | }
|
97 | exports.getNodeBinPath = getNodeBinPath;
|
98 | async function chmodPlusX(fsPath) {
|
99 | const s = await fs_extra_1.default.stat(fsPath);
|
100 | const newMode = s.mode | 64 | 8 | 1;
|
101 | if (s.mode === newMode)
|
102 | return;
|
103 | const base8 = newMode.toString(8).slice(-3);
|
104 | await fs_extra_1.default.chmod(fsPath, base8);
|
105 | }
|
106 | async function runShellScript(fsPath, args = [], spawnOpts) {
|
107 | assert_1.default(path_1.default.isAbsolute(fsPath));
|
108 | const destPath = path_1.default.dirname(fsPath);
|
109 | await chmodPlusX(fsPath);
|
110 | const command = `./${path_1.default.basename(fsPath)}`;
|
111 | await spawnAsync(command, args, {
|
112 | ...spawnOpts,
|
113 | cwd: destPath,
|
114 | prettyCommand: command,
|
115 | });
|
116 | return true;
|
117 | }
|
118 | exports.runShellScript = runShellScript;
|
119 | function getSpawnOptions(meta, nodeVersion) {
|
120 | const opts = {
|
121 | env: { ...process.env },
|
122 | };
|
123 | if (!meta.isDev) {
|
124 | opts.env.PATH = `/node${nodeVersion.major}/bin:${opts.env.PATH}`;
|
125 | }
|
126 | return opts;
|
127 | }
|
128 | exports.getSpawnOptions = getSpawnOptions;
|
129 | async function getNodeVersion(destPath, _nodeVersion, _config, meta) {
|
130 | if (meta && meta.isDev) {
|
131 |
|
132 | const latest = node_version_1.getLatestNodeVersion();
|
133 | return { ...latest, runtime: 'nodejs' };
|
134 | }
|
135 | const { packageJson } = await scanParentDirs(destPath, true);
|
136 | let range;
|
137 | let isAuto = true;
|
138 | if (packageJson && packageJson.engines && packageJson.engines.node) {
|
139 | range = packageJson.engines.node;
|
140 | isAuto = false;
|
141 | }
|
142 | return node_version_1.getSupportedNodeVersion(range, isAuto);
|
143 | }
|
144 | exports.getNodeVersion = getNodeVersion;
|
145 | async function scanParentDirs(destPath, readPackageJson = false) {
|
146 | assert_1.default(path_1.default.isAbsolute(destPath));
|
147 | let cliType = 'yarn';
|
148 | let packageJson;
|
149 | let currentDestPath = destPath;
|
150 |
|
151 | while (true) {
|
152 | const packageJsonPath = path_1.default.join(currentDestPath, 'package.json');
|
153 |
|
154 | if (await fs_extra_1.default.pathExists(packageJsonPath)) {
|
155 |
|
156 | if (readPackageJson) {
|
157 | packageJson = JSON.parse(await fs_extra_1.default.readFile(packageJsonPath, 'utf8'));
|
158 | }
|
159 |
|
160 | const [hasPackageLockJson, hasYarnLock] = await Promise.all([
|
161 | fs_extra_1.default.pathExists(path_1.default.join(currentDestPath, 'package-lock.json')),
|
162 | fs_extra_1.default.pathExists(path_1.default.join(currentDestPath, 'yarn.lock')),
|
163 | ]);
|
164 | if (hasPackageLockJson && !hasYarnLock) {
|
165 | cliType = 'npm';
|
166 | }
|
167 | break;
|
168 | }
|
169 | const newDestPath = path_1.default.dirname(currentDestPath);
|
170 | if (currentDestPath === newDestPath)
|
171 | break;
|
172 | currentDestPath = newDestPath;
|
173 | }
|
174 | return { cliType, packageJson };
|
175 | }
|
176 | async function walkParentDirs({ base, start, filename, }) {
|
177 | assert_1.default(path_1.default.isAbsolute(base), 'Expected "base" to be absolute path');
|
178 | assert_1.default(path_1.default.isAbsolute(start), 'Expected "start" to be absolute path');
|
179 | let parent = '';
|
180 | for (let current = start; base.length <= current.length; current = parent) {
|
181 | const fullPath = path_1.default.join(current, filename);
|
182 |
|
183 | if (await fs_extra_1.default.pathExists(fullPath)) {
|
184 | return fullPath;
|
185 | }
|
186 | parent = path_1.default.dirname(current);
|
187 | }
|
188 | return null;
|
189 | }
|
190 | exports.walkParentDirs = walkParentDirs;
|
191 | async function runNpmInstall(destPath, args = [], spawnOpts, meta) {
|
192 | if (meta && meta.isDev) {
|
193 | debug_1.default('Skipping dependency installation because dev mode is enabled');
|
194 | return;
|
195 | }
|
196 | assert_1.default(path_1.default.isAbsolute(destPath));
|
197 | debug_1.default(`Installing to ${destPath}`);
|
198 | const { cliType } = await scanParentDirs(destPath);
|
199 | const opts = { cwd: destPath, ...spawnOpts };
|
200 | const env = opts.env ? { ...opts.env } : { ...process.env };
|
201 | delete env.NODE_ENV;
|
202 | opts.env = env;
|
203 | let command;
|
204 | let commandArgs;
|
205 | if (cliType === 'npm') {
|
206 | opts.prettyCommand = 'npm install';
|
207 | command = 'npm';
|
208 | commandArgs = args
|
209 | .filter(a => a !== '--prefer-offline')
|
210 | .concat(['install', '--no-audit', '--unsafe-perm']);
|
211 | }
|
212 | else {
|
213 | opts.prettyCommand = 'yarn install';
|
214 | command = 'yarn';
|
215 | commandArgs = ['install', ...args];
|
216 | }
|
217 | if (process.env.NPM_ONLY_PRODUCTION) {
|
218 | commandArgs.push('--production');
|
219 | }
|
220 | await spawnAsync(command, commandArgs, opts);
|
221 | }
|
222 | exports.runNpmInstall = runNpmInstall;
|
223 | async function runBundleInstall(destPath, args = [], spawnOpts, meta) {
|
224 | if (meta && meta.isDev) {
|
225 | debug_1.default('Skipping dependency installation because dev mode is enabled');
|
226 | return;
|
227 | }
|
228 | assert_1.default(path_1.default.isAbsolute(destPath));
|
229 | const opts = { ...spawnOpts, cwd: destPath, prettyCommand: 'bundle install' };
|
230 | await spawnAsync('bundle', args.concat([
|
231 | 'install',
|
232 | '--no-prune',
|
233 | '--retry',
|
234 | '3',
|
235 | '--jobs',
|
236 | String(os_1.cpus().length || 1),
|
237 | ]), opts);
|
238 | }
|
239 | exports.runBundleInstall = runBundleInstall;
|
240 | async function runPipInstall(destPath, args = [], spawnOpts, meta) {
|
241 | if (meta && meta.isDev) {
|
242 | debug_1.default('Skipping dependency installation because dev mode is enabled');
|
243 | return;
|
244 | }
|
245 | assert_1.default(path_1.default.isAbsolute(destPath));
|
246 | const opts = { ...spawnOpts, cwd: destPath, prettyCommand: 'pip3 install' };
|
247 | await spawnAsync('pip3', ['install', '--disable-pip-version-check', ...args], opts);
|
248 | }
|
249 | exports.runPipInstall = runPipInstall;
|
250 | async function runPackageJsonScript(destPath, scriptName, spawnOpts) {
|
251 | assert_1.default(path_1.default.isAbsolute(destPath));
|
252 | const { packageJson, cliType } = await scanParentDirs(destPath, true);
|
253 | const hasScript = Boolean(packageJson &&
|
254 | packageJson.scripts &&
|
255 | scriptName &&
|
256 | packageJson.scripts[scriptName]);
|
257 | if (!hasScript)
|
258 | return false;
|
259 | if (cliType === 'npm') {
|
260 | const prettyCommand = `npm run ${scriptName}`;
|
261 | console.log(`Running "${prettyCommand}"`);
|
262 | await spawnAsync('npm', ['run', scriptName], {
|
263 | ...spawnOpts,
|
264 | cwd: destPath,
|
265 | prettyCommand,
|
266 | });
|
267 | }
|
268 | else {
|
269 | const prettyCommand = `yarn run ${scriptName}`;
|
270 | console.log(`Running "${prettyCommand}"`);
|
271 | await spawnAsync('yarn', ['run', scriptName], {
|
272 | ...spawnOpts,
|
273 | cwd: destPath,
|
274 | prettyCommand,
|
275 | });
|
276 | }
|
277 | return true;
|
278 | }
|
279 | exports.runPackageJsonScript = runPackageJsonScript;
|
280 |
|
281 |
|
282 |
|
283 |
|
284 | exports.installDependencies = util_1.deprecate(runNpmInstall, 'installDependencies() is deprecated. Please use runNpmInstall() instead.');
|