122 lines
3.6 KiB
TypeScript
122 lines
3.6 KiB
TypeScript
import { Command, Option } from "clipanion";
|
|
import { Filename, PortablePath, npath, ppath, xfs } from "@yarnpkg/fslib";
|
|
import { getPnpPath } from "@yarnpkg/plugin-pnp";
|
|
import { scriptUtils } from "@yarnpkg/core";
|
|
|
|
import {
|
|
CommandContext,
|
|
Configuration,
|
|
Project,
|
|
StreamReport,
|
|
} from "@yarnpkg/core";
|
|
|
|
import binWrapperNodeModulesTmpl from "./tmpl/bin-wrapper-node-modules.sh.in";
|
|
import binWrapperPnpTmpl from "./tmpl/bin-wrapper-pnp.sh.in";
|
|
import { renderTmpl } from "./textUtils";
|
|
import { pathToFileURL } from "url";
|
|
|
|
// Internal command that creates wrappers for binaries.
|
|
// Used inside the Nix install phase.
|
|
export default class InstallBinCommand extends Command<CommandContext> {
|
|
static paths = [[`nixify`, `install-bin`]];
|
|
binDir = Option.String();
|
|
|
|
async execute() {
|
|
const configuration = await Configuration.find(
|
|
this.context.cwd,
|
|
this.context.plugins
|
|
);
|
|
const { project, workspace } = await Project.find(
|
|
configuration,
|
|
this.context.cwd
|
|
);
|
|
|
|
const report = await StreamReport.start(
|
|
{ configuration, stdout: this.context.stdout },
|
|
async (report) => {
|
|
if (!workspace) {
|
|
return;
|
|
}
|
|
|
|
const binDir = npath.toPortablePath(this.binDir);
|
|
|
|
for (const [name, binaryFile] of workspace.manifest.bin) {
|
|
const wrapperPath = ppath.join(binDir, name as Filename);
|
|
const binaryPath = ppath.join(
|
|
project.cwd,
|
|
npath.toPortablePath(binaryFile)
|
|
);
|
|
await this.writeWrapper(wrapperPath, binaryPath, {
|
|
configuration,
|
|
project,
|
|
});
|
|
}
|
|
|
|
if (configuration.get(`installNixBinariesForDependencies`)) {
|
|
await project.resolveEverything({ report, lockfileOnly: true });
|
|
const binaries = await scriptUtils.getPackageAccessibleBinaries(
|
|
project.topLevelWorkspace.anchoredLocator,
|
|
{ project }
|
|
);
|
|
for (const [name, [_, binaryPath]] of binaries.entries()) {
|
|
const wrapperPath = ppath.join(binDir, name as Filename);
|
|
await this.writeWrapper(
|
|
wrapperPath,
|
|
npath.toPortablePath(binaryPath),
|
|
{ configuration, project }
|
|
);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
return report.exitCode();
|
|
}
|
|
|
|
private async writeWrapper(
|
|
wrapperPath: PortablePath,
|
|
binaryPath: PortablePath,
|
|
{
|
|
configuration,
|
|
project,
|
|
}: { configuration: Configuration; project: Project }
|
|
) {
|
|
let wrapper;
|
|
switch (configuration.get(`nodeLinker`)) {
|
|
case `pnp`: {
|
|
const pnpPath = getPnpPath(project);
|
|
const nodeOptions = [];
|
|
if (await xfs.existsPromise(pnpPath.cjs)) {
|
|
nodeOptions.push(
|
|
`--require "${npath.fromPortablePath(pnpPath.cjs)}"`
|
|
);
|
|
}
|
|
if (await xfs.existsPromise(pnpPath.esmLoader)) {
|
|
nodeOptions.push(
|
|
`--experimental-loader "${
|
|
pathToFileURL(npath.fromPortablePath(pnpPath.esmLoader)).href
|
|
}"`
|
|
);
|
|
}
|
|
wrapper = renderTmpl(binWrapperPnpTmpl, {
|
|
NODE_PATH: process.execPath,
|
|
NODE_OPTIONS: nodeOptions.join(" "),
|
|
BINARY_PATH: binaryPath,
|
|
});
|
|
break;
|
|
}
|
|
case `node-modules`:
|
|
wrapper = renderTmpl(binWrapperNodeModulesTmpl, {
|
|
NODE_PATH: process.execPath,
|
|
BINARY_PATH: binaryPath,
|
|
});
|
|
break;
|
|
default:
|
|
throw Error(`Assertion failed: Invalid nodeLinker`);
|
|
}
|
|
|
|
await xfs.writeFilePromise(wrapperPath, wrapper);
|
|
await xfs.chmodPromise(wrapperPath, 0o755);
|
|
}
|
|
}
|