setup-cpp/src/llvm/llvm_installer.ts

93 lines
3.1 KiB
TypeScript

import { execRoot } from "admina"
import { execa } from "execa"
import { addPath } from "../utils/env/addEnv"
import { hasNala, isPackageInstalled, setupAptPack } from "../utils/setup/setupAptPack"
import { InstallationInfo } from "../utils/setup/setupBin"
import { promises } from "fs"
import { info } from "console"
import { DEFAULT_TIMEOUT } from "../installTool"
const { readFile, writeFile, chmod } = promises
export async function setupLLVMApt(majorVersion: number): Promise<InstallationInfo> {
// TODO for older versions, this also includes the minor version
const installationFolder = `/usr/lib/llvm-${majorVersion}`
await setupAptPack([{ name: "curl" }])
await execa("curl", ["-LJO", "https://apt.llvm.org/llvm.sh"], { cwd: "/tmp" })
const neededPackages = await patchAptLLVMScript("/tmp/llvm.sh", "/tmp/llvm-setup-cpp.sh")
await setupAptPack(neededPackages)
await chmod("/tmp/llvm-setup-cpp.sh", "755")
await execRoot("bash", ["/tmp/llvm-setup-cpp.sh", `${majorVersion}`, "all"], {
stdio: "inherit",
shell: true,
timeout: DEFAULT_TIMEOUT,
})
await addPath(`${installationFolder}/bin`)
return {
installDir: `${installationFolder}`,
binDir: `${installationFolder}/bin`,
bin: `${installationFolder}/bin/clang++`,
}
}
async function patchAptLLVMScript(path: string, target_path: string) {
let script = await readFile(path, "utf-8")
script = debugScript(script)
script = nonInteractiveScript(script)
script = await removeConflictingPAckages(script)
script = useNalaScript(script)
await writeFile(target_path, script)
// the packages needed by the script
return [{ name: "lsb-release" }, { name: "wget" }, { name: "software-properties-common" }, { name: "gnupg" }]
}
function debugScript(script: string) {
if (!process.env.NODE_DEBUG) {
return script.replace(/set -eux/g, "set -eu")
}
return script
}
function nonInteractiveScript(script: string) {
// make the scirpt non-interactive and fix broken packages
return script.replace(
/add-apt-repository "\${REPO_NAME}"/g,
// eslint-disable-next-line no-template-curly-in-string
'add-apt-repository -y "${REPO_NAME}"',
)
}
async function removeConflictingPAckages(givenScript: string) {
// fix conflicts between libclang-rt and libclang
let script = givenScript.replace(
/apt-get install -y/g,
'apt-get install -o Dpkg::Options::="--force-overwrite" -y --fix-broken',
)
// check if these are installed and if so, remove them from the script as they conflict
const conflictingPackages = ["libc++-$LLVM_VERSION-dev", "libc++abi-$LLVM_VERSION-dev", "libunwind-$LLVM_VERSION-dev"]
await Promise.all(
conflictingPackages.map(async (pack) => {
const installingPack = pack.replace("$LLVM_VERSION", "*")
if (await isPackageInstalled(installingPack)) {
info(`Removing conflicting package ${installingPack}`)
script = script.replace(pack, "")
}
}),
)
return script
}
function useNalaScript(script: string) {
// use nala if it is available
if (hasNala()) {
return script.replace(/apt-get/g, "nala")
}
return script
}