import path, { join } from "path" import { fileURLToPath } from "url" import { info } from "ci-log" import { execa } from "execa" import { addExeExt } from "patha" import { hasAptGet, installAptPack } from "setup-apt" import type { InstallationInfo, PackageInfo } from "setup-bin" import { hasDnf, setupDnfPack } from "setup-dnf" import { type ArchiveToolDependencies, extractTarByExe } from "setup-extract" import { isArch, setupPacmanPack } from "setup-pacman" import { addVPrefix, removeVPrefix } from "setup-version" import { untildifyUser } from "untildify-user" import which from "which" import { setupCmake } from "../cmake/cmake.js" import { setupNinja } from "../ninja/ninja.js" import type { SetupOptions } from "../setup-options.js" import { setupTar } from "../tar/tar.js" import { getLegacyArchiveSetupOptions } from "../utils/archive-bootstrap.js" import { ubuntuVersion } from "../utils/env/ubuntu_version.js" import { setupBin } from "../utils/setup-bin.js" import { getVersion } from "../versions/versions.js" const dirname = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url)) function getDownloadKcovPackageInfo(version: string): PackageInfo { return { url: `https://github.com/SimonKagstrom/kcov/releases/download/${version}/kcov-amd64.tar.gz`, extractedFolderName: "", binRelativeDir: "usr/local/bin", binFileName: addExeExt("kcov"), } } function getBuildKcovPackageInfo(version: string, _platform: NodeJS.Platform, arch: string): PackageInfo { return { url: `https://github.com/SimonKagstrom/kcov/archive/refs/tags/${version}.tar.gz`, extractedFolderName: "", binRelativeDir: "build/src", binFileName: addExeExt("kcov"), extractFunction: (file, dest, dependencies) => buildKcov(file, dest, arch, dependencies), } } async function buildKcov(file: string, dest: string, arch: string, dependencies?: ArchiveToolDependencies) { const archiveSetupOptions = getLegacyArchiveSetupOptions() const out = await extractTarByExe(file, dest, 1, [], { ...dependencies, setupTar: () => setupTar(archiveSetupOptions.setupTar), }) // build after extraction using CMake const cmake = await getCmake(arch) if (process.platform === "linux") { if (isArch()) { await Promise.all([setupPacmanPack("libdwarf"), setupPacmanPack("libcurl-openssl")]) } else if (hasDnf()) { await setupDnfPack([{ name: "libdwarf-devel" }, { name: "libcurl-devel" }]) } else if (hasAptGet()) { await installAptPack([{ name: "libdw-dev" }, { name: "libcurl4-openssl-dev" }]) } } // apply gcc13.patch try { if (which.sync("patch", { nothrow: true }) !== null) { const patch = join(dirname, "gcc13.patch") await execa("patch", ["-N", "-p1", "-i", patch], { cwd: out, stdio: "inherit" }) } else { info("`patch` not found, skipping gcc13.patch, kcov may not build on gcc 13") } } catch { // ignore } const buildDir = join(out, "build") await execa( cmake, [ "-S", out, "-B", buildDir, "-DCMAKE_BUILD_TYPE=Release", "-DCMAKE_POLICY_VERSION_MINIMUM=3.5", "-G", "Ninja", ], { cwd: out, stdio: "inherit", }, ) await execa(cmake, ["--build", buildDir, "--config", "Release"], { cwd: out, stdio: "inherit" }) // execRootSync(cmake, ["--install", buildDir], out) // return "user/local/bin" // the cmake install prefix return out } async function getCmake(arch: string) { let cmake = which.sync("cmake", { nothrow: true }) if (cmake === null) { const { binDir } = await setupCmake({ version: getVersion("cmake", undefined, await ubuntuVersion()), setupDir: join(untildifyUser("~"), "cmake"), arch, }) cmake = join(binDir, "cmake") } const ninja = which.sync("ninja", { nothrow: true }) if (ninja === null) { await setupNinja({ version: getVersion("ninja", undefined, await ubuntuVersion()), setupDir: join(untildifyUser("~"), "ninja"), arch, }) } return cmake } export async function setupKcov({ version: versionGiven, setupDir, arch }: SetupOptions) { if (process.platform !== "linux") { info("Kcov is not supported on non-linux") return } // parse version const versionSplit = versionGiven.split("-") let version = addVPrefix(versionSplit[0]) const installMethod = versionSplit[1] as "binary" | undefined const version_number = removeVPrefix(version) // fix inconsistency in tagging if (version_number === 38) { version = "v38" } let installationInfo: InstallationInfo if (installMethod === "binary" && version_number >= 39) { installationInfo = await setupBin("kcov", version, getDownloadKcovPackageInfo, setupDir, arch) if (isArch()) { await setupPacmanPack("binutils") } else if (hasDnf()) { await setupDnfPack([{ name: "binutils" }]) } else if (hasAptGet()) { await installAptPack([{ name: "libbinutils" }]) } return installationInfo } else { installationInfo = await setupBin("kcov", version, getBuildKcovPackageInfo, setupDir, arch) } return installationInfo }