/* Copyright 2024 New Vector Ltd. Copyright 2020 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ import path from "path"; import os from "os"; import fsProm from "fs/promises"; import childProcess from "child_process"; import HakEnv from "./hakEnv"; import { DependencyInfo } from "./dep"; export default async function link(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise { const yarnrc = path.join(hakEnv.projectRoot, ".yarnrc"); // this is fairly terrible but it's reasonably clunky to either parse a yarnrc // properly or get yarn to do it, so this will probably suffice for now. // We just check to see if there is a local .yarnrc at all, and assume that // if you've put one there yourself, you probably know what you're doing and // we won't meddle with it. // Also we do this for each module which is unnecessary, but meh. try { await fsProm.stat(yarnrc); } catch (e) { await fsProm.writeFile( yarnrc, // XXX: 1. This must be absolute, as yarn will resolve link directories // relative to the closest project root, which means when we run it // in the dependency project, it will put the link directory in its // own project folder rather than the main project. // 2. The parser gets very confused by strings with colons in them // (ie. Windows absolute paths) but strings in quotes get parsed as // JSON so need to be valid JSON encoded strings (ie. have the // backslashes escaped). JSON.stringify will add quotes and escape. "--link-folder " + JSON.stringify(path.join(hakEnv.dotHakDir, "links")) + os.EOL, ); } const yarnCmd = "yarn" + (hakEnv.isWin() ? ".cmd" : ""); await new Promise((resolve, reject) => { const proc = childProcess.spawn(yarnCmd, ["link"], { cwd: moduleInfo.moduleOutDir, stdio: "inherit", // We need shell mode on Windows to be able to launch `.cmd` executables // See https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2 shell: hakEnv.isWin(), }); proc.on("exit", (code) => { code ? reject(code) : resolve(); }); }); await new Promise((resolve, reject) => { const proc = childProcess.spawn(yarnCmd, ["link", moduleInfo.name], { cwd: hakEnv.projectRoot, stdio: "inherit", // We need shell mode on Windows to be able to launch `.cmd` executables // See https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2 shell: hakEnv.isWin(), }); proc.on("exit", (code) => { code ? reject(code) : resolve(); }); }); }