1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.executeWorkspaceAccessibleBinary = exports.executePackageAccessibleBinary = exports.getWorkspaceAccessibleBinaries = exports.getPackageAccessibleBinaries = exports.maybeExecuteWorkspaceLifecycleScript = exports.executeWorkspaceLifecycleScript = exports.hasWorkspaceScript = exports.executeWorkspaceScript = exports.executePackageShellcode = exports.executePackageScript = exports.hasPackageScript = exports.prepareExternalProject = exports.makeScriptEnv = void 0;
|
4 | const tslib_1 = require("tslib");
|
5 | const fslib_1 = require("@yarnpkg/fslib");
|
6 | const fslib_2 = require("@yarnpkg/fslib");
|
7 | const libzip_1 = require("@yarnpkg/libzip");
|
8 | const shell_1 = require("@yarnpkg/shell");
|
9 | const binjumper_1 = require("binjumper");
|
10 | const capitalize_1 = tslib_1.__importDefault(require("lodash/capitalize"));
|
11 | const p_limit_1 = tslib_1.__importDefault(require("p-limit"));
|
12 | const stream_1 = require("stream");
|
13 | const Manifest_1 = require("./Manifest");
|
14 | const MessageName_1 = require("./MessageName");
|
15 | const Report_1 = require("./Report");
|
16 | const StreamReport_1 = require("./StreamReport");
|
17 | const YarnVersion_1 = require("./YarnVersion");
|
18 | const execUtils = tslib_1.__importStar(require("./execUtils"));
|
19 | const formatUtils = tslib_1.__importStar(require("./formatUtils"));
|
20 | const miscUtils = tslib_1.__importStar(require("./miscUtils"));
|
21 | const structUtils = tslib_1.__importStar(require("./structUtils"));
|
22 | var PackageManager;
|
23 | (function (PackageManager) {
|
24 | PackageManager["Yarn1"] = "Yarn Classic";
|
25 | PackageManager["Yarn2"] = "Yarn";
|
26 | PackageManager["Npm"] = "npm";
|
27 | PackageManager["Pnpm"] = "pnpm";
|
28 | })(PackageManager || (PackageManager = {}));
|
29 | async function makePathWrapper(location, name, argv0, args = []) {
|
30 | if (process.platform === `win32`) {
|
31 | await Promise.all([
|
32 | fslib_2.xfs.writeFilePromise(fslib_2.ppath.format({ dir: location, name, ext: `.exe` }), binjumper_1.getBinjumper()),
|
33 | fslib_2.xfs.writeFilePromise(fslib_2.ppath.format({ dir: location, name, ext: `.exe.info` }), [argv0, ...args].join(`\n`)),
|
34 | fslib_2.xfs.writeFilePromise(fslib_2.ppath.format({ dir: location, name, ext: `.cmd` }), `@"${argv0}" ${args.map(arg => `"${arg.replace(`"`, `""`)}"`).join(` `)} %*\n`),
|
35 | ]);
|
36 | }
|
37 | await fslib_2.xfs.writeFilePromise(fslib_2.ppath.join(location, name), `#!/bin/sh\nexec "${argv0}" ${args.map(arg => `'${arg.replace(/'/g, `'"'"'`)}'`).join(` `)} "$@"\n`);
|
38 | await fslib_2.xfs.chmodPromise(fslib_2.ppath.join(location, name), 0o755);
|
39 | }
|
40 | async function detectPackageManager(location) {
|
41 | let yarnLock = null;
|
42 | try {
|
43 | yarnLock = await fslib_2.xfs.readFilePromise(fslib_2.ppath.join(location, fslib_1.Filename.lockfile), `utf8`);
|
44 | }
|
45 | catch (_a) { }
|
46 | if (yarnLock !== null) {
|
47 | if (yarnLock.match(/^__metadata:$/m)) {
|
48 | return PackageManager.Yarn2;
|
49 | }
|
50 | else {
|
51 | return PackageManager.Yarn1;
|
52 | }
|
53 | }
|
54 | if (fslib_2.xfs.existsSync(fslib_2.ppath.join(location, `package-lock.json`)))
|
55 | return PackageManager.Npm;
|
56 | if (fslib_2.xfs.existsSync(fslib_2.ppath.join(location, `pnpm-lock.yaml`)))
|
57 | return PackageManager.Pnpm;
|
58 | return null;
|
59 | }
|
60 | async function makeScriptEnv({ project, binFolder, lifecycleScript }) {
|
61 | const scriptEnv = {};
|
62 | for (const [key, value] of Object.entries(process.env))
|
63 | if (typeof value !== `undefined`)
|
64 | scriptEnv[key.toLowerCase() !== `path` ? key : `PATH`] = value;
|
65 | const nBinFolder = fslib_2.npath.fromPortablePath(binFolder);
|
66 |
|
67 |
|
68 | scriptEnv.BERRY_BIN_FOLDER = fslib_2.npath.fromPortablePath(nBinFolder);
|
69 |
|
70 |
|
71 | await makePathWrapper(binFolder, `node`, process.execPath);
|
72 | if (YarnVersion_1.YarnVersion !== null) {
|
73 | await makePathWrapper(binFolder, `run`, process.execPath, [process.argv[1], `run`]);
|
74 | await makePathWrapper(binFolder, `yarn`, process.execPath, [process.argv[1]]);
|
75 | await makePathWrapper(binFolder, `yarnpkg`, process.execPath, [process.argv[1]]);
|
76 | await makePathWrapper(binFolder, `node-gyp`, process.execPath, [process.argv[1], `run`, `--top-level`, `node-gyp`]);
|
77 | }
|
78 | if (project)
|
79 | scriptEnv.INIT_CWD = fslib_2.npath.fromPortablePath(project.configuration.startingCwd);
|
80 | scriptEnv.PATH = scriptEnv.PATH
|
81 | ? `${nBinFolder}${fslib_2.npath.delimiter}${scriptEnv.PATH}`
|
82 | : `${nBinFolder}`;
|
83 | scriptEnv.npm_execpath = `${nBinFolder}${fslib_2.npath.sep}yarn`;
|
84 | scriptEnv.npm_node_execpath = `${nBinFolder}${fslib_2.npath.sep}node`;
|
85 | const version = YarnVersion_1.YarnVersion !== null
|
86 | ? `yarn/${YarnVersion_1.YarnVersion}`
|
87 | : `yarn/${miscUtils.dynamicRequire(`@yarnpkg/core`).version}-core`;
|
88 | scriptEnv.npm_config_user_agent = `${version} npm/? node/${process.versions.node} ${process.platform} ${process.arch}`;
|
89 | if (lifecycleScript)
|
90 | scriptEnv.npm_lifecycle_event = lifecycleScript;
|
91 | if (project) {
|
92 | await project.configuration.triggerHook(hook => hook.setupScriptEnvironment, project, scriptEnv, async (name, argv0, args) => {
|
93 | return await makePathWrapper(binFolder, fslib_2.toFilename(name), argv0, args);
|
94 | });
|
95 | }
|
96 | return scriptEnv;
|
97 | }
|
98 | exports.makeScriptEnv = makeScriptEnv;
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | const MAX_PREPARE_CONCURRENCY = 2;
|
104 | const prepareLimit = p_limit_1.default(MAX_PREPARE_CONCURRENCY);
|
105 | async function prepareExternalProject(cwd, outputPath, { configuration, report, workspace = null }) {
|
106 | await prepareLimit(async () => {
|
107 | await fslib_2.xfs.mktempPromise(async (logDir) => {
|
108 | const logFile = fslib_2.ppath.join(logDir, `pack.log`);
|
109 | const stdin = null;
|
110 | const { stdout, stderr } = configuration.getSubprocessStreams(logFile, { prefix: cwd, report });
|
111 | const packageManager = await detectPackageManager(cwd);
|
112 | let effectivePackageManager;
|
113 | if (packageManager !== null) {
|
114 | stdout.write(`Installing the project using ${packageManager}\n\n`);
|
115 | effectivePackageManager = packageManager;
|
116 | }
|
117 | else {
|
118 | stdout.write(`No package manager detected; defaulting to Yarn\n\n`);
|
119 | effectivePackageManager = PackageManager.Yarn2;
|
120 | }
|
121 | await fslib_2.xfs.mktempPromise(async (binFolder) => {
|
122 | const env = await makeScriptEnv({ binFolder });
|
123 | const workflows = new Map([
|
124 | [PackageManager.Yarn1, async () => {
|
125 | const workspaceCli = workspace !== null
|
126 | ? [`workspace`, workspace]
|
127 | : [];
|
128 |
|
129 | const version = await execUtils.pipevp(`yarn`, [`set`, `version`, `classic`, `--only-if-needed`], { cwd, env, stdin, stdout, stderr, end: execUtils.EndStrategy.ErrorCode });
|
130 | if (version.code !== 0)
|
131 | return version.code;
|
132 |
|
133 | await fslib_2.xfs.appendFilePromise(fslib_2.ppath.join(cwd, `.npmignore`), `/.yarn\n`);
|
134 | stdout.write(`\n`);
|
135 |
|
136 |
|
137 |
|
138 | const install = await execUtils.pipevp(`yarn`, [`install`], { cwd, env, stdin, stdout, stderr, end: execUtils.EndStrategy.ErrorCode });
|
139 | if (install.code !== 0)
|
140 | return install.code;
|
141 | stdout.write(`\n`);
|
142 | const pack = await execUtils.pipevp(`yarn`, [...workspaceCli, `pack`, `--filename`, fslib_2.npath.fromPortablePath(outputPath)], { cwd, env, stdin, stdout, stderr });
|
143 | if (pack.code !== 0)
|
144 | return pack.code;
|
145 | return 0;
|
146 | }],
|
147 | [PackageManager.Yarn2, async () => {
|
148 | const workspaceCli = workspace !== null
|
149 | ? [`workspace`, workspace]
|
150 | : [];
|
151 |
|
152 |
|
153 | env.YARN_ENABLE_INLINE_BUILDS = `1`;
|
154 |
|
155 |
|
156 |
|
157 |
|
158 | const pack = await execUtils.pipevp(`yarn`, [...workspaceCli, `pack`, `--install-if-needed`, `--filename`, fslib_2.npath.fromPortablePath(outputPath)], { cwd, env, stdin, stdout, stderr });
|
159 | if (pack.code !== 0)
|
160 | return pack.code;
|
161 | return 0;
|
162 | }],
|
163 | [PackageManager.Npm, async () => {
|
164 | if (workspace !== null)
|
165 | throw new Error(`Workspaces aren't supported by npm, which has been detected as the primary package manager for ${cwd}`);
|
166 |
|
167 |
|
168 | delete env.npm_config_user_agent;
|
169 |
|
170 |
|
171 |
|
172 | const install = await execUtils.pipevp(`npm`, [`install`], { cwd, env, stdin, stdout, stderr, end: execUtils.EndStrategy.ErrorCode });
|
173 | if (install.code !== 0)
|
174 | return install.code;
|
175 | const packStream = new stream_1.PassThrough();
|
176 | const packPromise = miscUtils.bufferStream(packStream);
|
177 | packStream.pipe(stdout);
|
178 |
|
179 |
|
180 | const pack = await execUtils.pipevp(`npm`, [`pack`, `--silent`], { cwd, env, stdin, stdout: packStream, stderr });
|
181 | if (pack.code !== 0)
|
182 | return pack.code;
|
183 | const packOutput = (await packPromise).toString().trim();
|
184 | const packTarget = fslib_2.ppath.resolve(cwd, fslib_2.npath.toPortablePath(packOutput));
|
185 |
|
186 | await fslib_2.xfs.renamePromise(packTarget, outputPath);
|
187 | return 0;
|
188 | }],
|
189 | ]);
|
190 | const workflow = workflows.get(effectivePackageManager);
|
191 | if (typeof workflow === `undefined`)
|
192 | throw new Error(`Assertion failed: Unsupported workflow`);
|
193 | const code = await workflow();
|
194 | if (code === 0 || typeof code === `undefined`)
|
195 | return;
|
196 | fslib_2.xfs.detachTemp(logDir);
|
197 | throw new Report_1.ReportError(MessageName_1.MessageName.PACKAGE_PREPARATION_FAILED, `Packing the package failed (exit code ${code}, logs can be found here: ${logFile})`);
|
198 | });
|
199 | });
|
200 | });
|
201 | }
|
202 | exports.prepareExternalProject = prepareExternalProject;
|
203 | async function hasPackageScript(locator, scriptName, { project }) {
|
204 | const pkg = project.storedPackages.get(locator.locatorHash);
|
205 | if (!pkg)
|
206 | throw new Error(`Package for ${structUtils.prettyLocator(project.configuration, locator)} not found in the project`);
|
207 | return await fslib_1.ZipOpenFS.openPromise(async (zipOpenFs) => {
|
208 | const configuration = project.configuration;
|
209 | const linkers = project.configuration.getLinkers();
|
210 | const linkerOptions = { project, report: new StreamReport_1.StreamReport({ stdout: new stream_1.PassThrough(), configuration }) };
|
211 | const linker = linkers.find(linker => linker.supportsPackage(pkg, linkerOptions));
|
212 | if (!linker)
|
213 | throw new Error(`The package ${structUtils.prettyLocator(project.configuration, pkg)} isn't supported by any of the available linkers`);
|
214 | const packageLocation = await linker.findPackageLocation(pkg, linkerOptions);
|
215 | const packageFs = new fslib_1.CwdFS(packageLocation, { baseFs: zipOpenFs });
|
216 | const manifest = await Manifest_1.Manifest.find(fslib_1.PortablePath.dot, { baseFs: packageFs });
|
217 | return manifest.scripts.has(scriptName);
|
218 | }, {
|
219 | libzip: await libzip_1.getLibzipPromise(),
|
220 | });
|
221 | }
|
222 | exports.hasPackageScript = hasPackageScript;
|
223 | async function executePackageScript(locator, scriptName, args, { cwd, project, stdin, stdout, stderr }) {
|
224 | return await fslib_2.xfs.mktempPromise(async (binFolder) => {
|
225 | const { manifest, env, cwd: realCwd } = await initializePackageEnvironment(locator, { project, binFolder, cwd, lifecycleScript: scriptName });
|
226 | const script = manifest.scripts.get(scriptName);
|
227 | if (typeof script === `undefined`)
|
228 | return 1;
|
229 | const realExecutor = async () => {
|
230 | return await shell_1.execute(script, args, { cwd: realCwd, env, stdin, stdout, stderr });
|
231 | };
|
232 | const executor = await project.configuration.reduceHook(hooks => {
|
233 | return hooks.wrapScriptExecution;
|
234 | }, realExecutor, project, locator, scriptName, {
|
235 | script, args, cwd: realCwd, env, stdin, stdout, stderr,
|
236 | });
|
237 | return await executor();
|
238 | });
|
239 | }
|
240 | exports.executePackageScript = executePackageScript;
|
241 | async function executePackageShellcode(locator, command, args, { cwd, project, stdin, stdout, stderr }) {
|
242 | return await fslib_2.xfs.mktempPromise(async (binFolder) => {
|
243 | const { env, cwd: realCwd } = await initializePackageEnvironment(locator, { project, binFolder, cwd });
|
244 | return await shell_1.execute(command, args, { cwd: realCwd, env, stdin, stdout, stderr });
|
245 | });
|
246 | }
|
247 | exports.executePackageShellcode = executePackageShellcode;
|
248 | async function initializePackageEnvironment(locator, { project, binFolder, cwd, lifecycleScript }) {
|
249 | const pkg = project.storedPackages.get(locator.locatorHash);
|
250 | if (!pkg)
|
251 | throw new Error(`Package for ${structUtils.prettyLocator(project.configuration, locator)} not found in the project`);
|
252 | return await fslib_1.ZipOpenFS.openPromise(async (zipOpenFs) => {
|
253 | const configuration = project.configuration;
|
254 | const linkers = project.configuration.getLinkers();
|
255 | const linkerOptions = { project, report: new StreamReport_1.StreamReport({ stdout: new stream_1.PassThrough(), configuration }) };
|
256 | const linker = linkers.find(linker => linker.supportsPackage(pkg, linkerOptions));
|
257 | if (!linker)
|
258 | throw new Error(`The package ${structUtils.prettyLocator(project.configuration, pkg)} isn't supported by any of the available linkers`);
|
259 | const env = await makeScriptEnv({ project, binFolder, lifecycleScript });
|
260 | for (const [binaryName, [, binaryPath]] of await getPackageAccessibleBinaries(locator, { project }))
|
261 | await makePathWrapper(binFolder, fslib_2.toFilename(binaryName), process.execPath, [binaryPath]);
|
262 | const packageLocation = await linker.findPackageLocation(pkg, linkerOptions);
|
263 | const packageFs = new fslib_1.CwdFS(packageLocation, { baseFs: zipOpenFs });
|
264 | const manifest = await Manifest_1.Manifest.find(fslib_1.PortablePath.dot, { baseFs: packageFs });
|
265 | if (typeof cwd === `undefined`)
|
266 | cwd = packageLocation;
|
267 | return { manifest, binFolder, env, cwd };
|
268 | }, {
|
269 | libzip: await libzip_1.getLibzipPromise(),
|
270 | });
|
271 | }
|
272 | async function executeWorkspaceScript(workspace, scriptName, args, { cwd, stdin, stdout, stderr }) {
|
273 | return await executePackageScript(workspace.anchoredLocator, scriptName, args, { cwd, project: workspace.project, stdin, stdout, stderr });
|
274 | }
|
275 | exports.executeWorkspaceScript = executeWorkspaceScript;
|
276 | function hasWorkspaceScript(workspace, scriptName) {
|
277 | return workspace.manifest.scripts.has(scriptName);
|
278 | }
|
279 | exports.hasWorkspaceScript = hasWorkspaceScript;
|
280 | async function executeWorkspaceLifecycleScript(workspace, lifecycleScriptName, { cwd, report }) {
|
281 | const { configuration } = workspace.project;
|
282 | const stdin = null;
|
283 | await fslib_2.xfs.mktempPromise(async (logDir) => {
|
284 | const logFile = fslib_2.ppath.join(logDir, `${lifecycleScriptName}.log`);
|
285 | const header = `# This file contains the result of Yarn calling the "${lifecycleScriptName}" lifecycle script inside a workspace ("${workspace.cwd}")\n`;
|
286 | const { stdout, stderr } = configuration.getSubprocessStreams(logFile, {
|
287 | report,
|
288 | prefix: structUtils.prettyLocator(configuration, workspace.anchoredLocator),
|
289 | header,
|
290 | });
|
291 | report.reportInfo(MessageName_1.MessageName.LIFECYCLE_SCRIPT, `Calling the "${lifecycleScriptName}" lifecycle script`);
|
292 | const exitCode = await executeWorkspaceScript(workspace, lifecycleScriptName, [], { cwd, stdin, stdout, stderr });
|
293 | stdout.end();
|
294 | stderr.end();
|
295 | if (exitCode !== 0) {
|
296 | fslib_2.xfs.detachTemp(logDir);
|
297 | throw new Report_1.ReportError(MessageName_1.MessageName.LIFECYCLE_SCRIPT, `${capitalize_1.default(lifecycleScriptName)} script failed (exit code ${formatUtils.pretty(configuration, exitCode, formatUtils.Type.NUMBER)}, logs can be found here: ${formatUtils.pretty(configuration, logFile, formatUtils.Type.PATH)}); run ${formatUtils.pretty(configuration, `yarn ${lifecycleScriptName}`, formatUtils.Type.CODE)} to investigate`);
|
298 | }
|
299 | });
|
300 | }
|
301 | exports.executeWorkspaceLifecycleScript = executeWorkspaceLifecycleScript;
|
302 | async function maybeExecuteWorkspaceLifecycleScript(workspace, lifecycleScriptName, opts) {
|
303 | if (hasWorkspaceScript(workspace, lifecycleScriptName)) {
|
304 | await executeWorkspaceLifecycleScript(workspace, lifecycleScriptName, opts);
|
305 | }
|
306 | }
|
307 | exports.maybeExecuteWorkspaceLifecycleScript = maybeExecuteWorkspaceLifecycleScript;
|
308 |
|
309 |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 | async function getPackageAccessibleBinaries(locator, { project }) {
|
315 | const configuration = project.configuration;
|
316 | const binaries = new Map();
|
317 | const pkg = project.storedPackages.get(locator.locatorHash);
|
318 | if (!pkg)
|
319 | throw new Error(`Package for ${structUtils.prettyLocator(configuration, locator)} not found in the project`);
|
320 | const stdout = new stream_1.Writable();
|
321 | const linkers = configuration.getLinkers();
|
322 | const linkerOptions = { project, report: new StreamReport_1.StreamReport({ configuration, stdout }) };
|
323 | const visibleLocators = new Set([locator.locatorHash]);
|
324 | for (const descriptor of pkg.dependencies.values()) {
|
325 | const resolution = project.storedResolutions.get(descriptor.descriptorHash);
|
326 | if (!resolution)
|
327 | throw new Error(`Assertion failed: The resolution (${structUtils.prettyDescriptor(configuration, descriptor)}) should have been registered`);
|
328 | visibleLocators.add(resolution);
|
329 | }
|
330 | for (const locatorHash of visibleLocators) {
|
331 | const dependency = project.storedPackages.get(locatorHash);
|
332 | if (!dependency)
|
333 | throw new Error(`Assertion failed: The package (${locatorHash}) should have been registered`);
|
334 | if (dependency.bin.size === 0)
|
335 | continue;
|
336 | const linker = linkers.find(linker => linker.supportsPackage(dependency, linkerOptions));
|
337 | if (!linker)
|
338 | continue;
|
339 | const packageLocation = await linker.findPackageLocation(dependency, linkerOptions);
|
340 | for (const [name, target] of dependency.bin) {
|
341 | binaries.set(name, [dependency, fslib_2.npath.fromPortablePath(fslib_2.ppath.resolve(packageLocation, target))]);
|
342 | }
|
343 | }
|
344 | return binaries;
|
345 | }
|
346 | exports.getPackageAccessibleBinaries = getPackageAccessibleBinaries;
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 | async function getWorkspaceAccessibleBinaries(workspace) {
|
353 | return await getPackageAccessibleBinaries(workspace.anchoredLocator, { project: workspace.project });
|
354 | }
|
355 | exports.getWorkspaceAccessibleBinaries = getWorkspaceAccessibleBinaries;
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 | async function executePackageAccessibleBinary(locator, binaryName, args, { cwd, project, stdin, stdout, stderr, nodeArgs = [] }) {
|
368 | const packageAccessibleBinaries = await getPackageAccessibleBinaries(locator, { project });
|
369 | const binary = packageAccessibleBinaries.get(binaryName);
|
370 | if (!binary)
|
371 | throw new Error(`Binary not found (${binaryName}) for ${structUtils.prettyLocator(project.configuration, locator)}`);
|
372 | return await fslib_2.xfs.mktempPromise(async (binFolder) => {
|
373 | const [, binaryPath] = binary;
|
374 | const env = await makeScriptEnv({ project, binFolder });
|
375 | for (const [binaryName, [, binaryPath]] of packageAccessibleBinaries)
|
376 | await makePathWrapper(env.BERRY_BIN_FOLDER, fslib_2.toFilename(binaryName), process.execPath, [binaryPath]);
|
377 | let result;
|
378 | try {
|
379 | result = await execUtils.pipevp(process.execPath, [...nodeArgs, binaryPath, ...args], { cwd, env, stdin, stdout, stderr });
|
380 | }
|
381 | finally {
|
382 | await fslib_2.xfs.removePromise(env.BERRY_BIN_FOLDER);
|
383 | }
|
384 | return result.code;
|
385 | });
|
386 | }
|
387 | exports.executePackageAccessibleBinary = executePackageAccessibleBinary;
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 |
|
394 |
|
395 | async function executeWorkspaceAccessibleBinary(workspace, binaryName, args, { cwd, stdin, stdout, stderr }) {
|
396 | return await executePackageAccessibleBinary(workspace.anchoredLocator, binaryName, args, { project: workspace.project, cwd, stdin, stdout, stderr });
|
397 | }
|
398 | exports.executeWorkspaceAccessibleBinary = executeWorkspaceAccessibleBinary;
|