Merge pull request #182 from aminya/llvm-system [skip ci]

This commit is contained in:
Amin Yahyaabadi 2023-07-17 21:33:29 -07:00 committed by GitHub
commit 0c3b851567
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 345 additions and 214 deletions

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["orta.vscode-jest", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
}

15
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Jest Current File",
"runtimeExecutable": "sh",
"program": "node_modules/.bin/jest",
"args": ["${relativeFile}"],
"console": "integratedTerminal",
"internalConsoleOptions": "openOnFirstSessionStart"
}
]
}

View File

@ -209,7 +209,7 @@ If you want to build the ones included, then run:
```shell
git clone --recurse-submodules https://github.com/aminya/setup-cpp
cd ./setup-cpp
docker build -f ./dev/docker/setup-cpp-ubuntu.dockerfile -t setup-cpp .
docker build -f ./dev/docker/setup-cpp-ubuntu.dockerfile -t setup-cpp-ubuntu .
```
Where you should use the path to the dockerfile after `-f`.

View File

@ -9,6 +9,7 @@ ignorePaths:
- dist/
- dev/cpp_vcpkg_project
- "**/node_modules/"
- .vscode/extensions.json
words:
- aarch
- clangd

View File

@ -7,8 +7,7 @@ RUN pacman -Syuu --noconfirm && \
pacman-db-upgrade && \
# install nodejs
pacman -S --noconfirm --needed nodejs npm && \
# install setup-cpp
npm install -g setup-cpp@v0.31.1 && \
# install the compiler and tools
node /usr/lib/setup-cpp/setup-cpp.js \
--compiler llvm \

View File

@ -5,8 +5,7 @@ COPY "./dist/legacy" "/usr/lib/setup-cpp/"
# install nodejs
RUN dnf -y install nodejs npm && \
# install setup-cpp
npm install -g setup-cpp@v0.31.1 && \
# install the compiler and tools
node /usr/lib/setup-cpp/setup-cpp.js \
--compiler llvm \

View File

@ -6,8 +6,7 @@ COPY "./dist/legacy" "/usr/lib/setup-cpp/"
RUN apt-get update -qq && \
# install nodejs
apt-get install -y --no-install-recommends nodejs npm && \
# install setup-cpp
npm install -g setup-cpp@v0.31.1 && \
# install the compiler and tools
node /usr/lib/setup-cpp/setup-cpp.js \
--nala true \

View File

@ -7,10 +7,12 @@ async function main() {
const dockerFileContent = await readFile(`./dev/docker/setup-cpp-${dockerFile}.dockerfile`, "utf-8")
const builderExample = await readFile(`./dev/docker/${dockerFile}.dockerfile`, "utf-8")
// after the first FROM, add COPY "./dist/legacy" "/"
const modifiedDockerFile = dockerFileContent
// load the externally built setup-cpp
.replace(/FROM (.*)/g, `FROM $1\n\nCOPY "./dist/legacy" "/usr/lib/setup-cpp/"`)
.replace("setup-cpp ", "node /usr/lib/setup-cpp/setup-cpp.js ")
// remove the npm install line
.replace(/# install setup-cpp\n\s*npm install -g setup-cpp.*/, "")
// concat the two files
const newDockerFileContent = `${modifiedDockerFile}\n${builderExample}`

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -151,7 +151,8 @@
],
"alias": {
"electron": false,
"patha": "patha/dist/index.node.mjs"
"patha": "patha/dist/index.node.mjs",
"admina": "admina/dist/index.mjs"
},
"pnpm": {
"overrides": {

View File

@ -23,9 +23,9 @@ export async function setupBazel(version: string, _setupDir: string, _arch: stri
throw new Error("installing bazel on Arch linux is not supported yet")
} else if (hasDnf()) {
// https://bazel.build/install/redhat
setupDnfPack("dnf-plugins-core", undefined)
await setupDnfPack([{ name: "dnf-plugins-core" }])
execRootSync("dnf", ["copr", "enable", "vbatts/bazel"])
return setupDnfPack("bazel4", undefined)
return setupDnfPack([{ name: "bazel4" }])
} else if (isUbuntu()) {
// https://bazel.build/install/ubuntu
const keyFileName = await addAptKeyViaDownload(

View File

@ -20,7 +20,7 @@ export function setupCcache(version: string, _setupDir: string, _arch: string) {
if (isArch()) {
return setupPacmanPack("ccache", version)
} else if (hasDnf()) {
return setupDnfPack("ccache", version)
return setupDnfPack([{ name: "ccache", version }])
} else if (isUbuntu()) {
return setupAptPack([{ name: "ccache", version }])
}

View File

@ -23,7 +23,7 @@ export async function setupCppcheck(version: string | undefined, _setupDir: stri
if (isArch()) {
return setupPacmanPack("cppcheck", version)
} else if (hasDnf()) {
return setupDnfPack("ccache", version)
return setupDnfPack([{ name: "ccache", version }])
} else if (isUbuntu()) {
return setupAptPack([{ name: "cppcheck", version }])
}

View File

@ -73,7 +73,7 @@ export async function setupDoxygen(version: string, setupDir: string, arch: stri
if (isArch()) {
installationInfo = await setupPacmanPack("doxygen", version)
} else if (hasDnf()) {
return setupDnfPack("doxygen", version)
return setupDnfPack([{ name: "doxygen", version }])
} else if (isUbuntu()) {
installationInfo = await setupAptPack([{ name: "doxygen", version }])
} else {

View File

@ -98,9 +98,11 @@ export async function setupGcc(version: string, setupDir: string, arch: string)
if (isArch()) {
installationInfo = await setupPacmanPack("gcc", version)
} else if (hasDnf()) {
installationInfo = setupDnfPack("gcc", version)
setupDnfPack("gcc-c++", version)
setupDnfPack("libstdc++-devel", undefined)
installationInfo = await setupDnfPack([
{ name: "gcc", version },
{ name: "gcc-c++", version },
{ name: "libstdc++-devel" },
])
} else if (isUbuntu()) {
installationInfo = await setupAptPack([
{ name: "gcc", version, repositories: ["ppa:ubuntu-toolchain-r/test"] },

View File

@ -23,7 +23,7 @@ export async function setupGraphviz(version: string, _setupDir: string, _arch: s
if (isArch()) {
return setupPacmanPack("graphviz", version)
} else if (hasDnf()) {
return setupDnfPack("graphviz", version)
return setupDnfPack([{ name: "graphviz", version }])
} else if (isUbuntu()) {
return setupAptPack([{ name: "graphviz", version }])
}

View File

@ -47,8 +47,7 @@ async function buildKcov(file: string, dest: string) {
if (isArch()) {
await Promise.all([setupPacmanPack("libdwarf"), setupPacmanPack("libcurl-openssl")])
} else if (hasDnf()) {
setupDnfPack("libdwarf-devel")
setupDnfPack("libcurl-devel")
await setupDnfPack([{ name: "libdwarf-devel" }, { name: "libcurl-devel" }])
} else if (isUbuntu()) {
await setupAptPack([{ name: "libdw-dev" }, { name: "libcurl4-openssl-dev" }])
}
@ -116,7 +115,7 @@ export async function setupKcov(versionGiven: string, setupDir: string, arch: st
if (isArch()) {
await setupPacmanPack("binutils")
} else if (hasDnf()) {
setupDnfPack("binutils")
await setupDnfPack([{ name: "binutils" }])
} else if (isUbuntu()) {
await setupAptPack([{ name: "libbinutils" }])
}

View File

@ -1,81 +1,134 @@
import { join, addExeExt } from "patha"
import { execRoot } from "admina"
import { GITHUB_ACTIONS } from "ci-info"
import { info, warning } from "ci-log"
import { execa } from "execa"
import { promises } from "fs"
const { readFile, writeFile, chmod } = promises
import memoize from "micro-memoize"
import { delimiter } from "path"
import { pathExists } from "path-exists"
import { addExeExt, join } from "patha"
import { setupGcc } from "../gcc/gcc"
import { setupMacOSSDK } from "../macos-sdk/macos-sdk"
import { addEnv, addPath } from "../utils/env/addEnv"
import { isUbuntu } from "../utils/env/isUbuntu"
import { ubuntuVersion } from "../utils/env/ubuntu_version"
import { hasNala, setupAptPack, updateAptAlternatives } from "../utils/setup/setupAptPack"
import { InstallationInfo, setupBin } from "../utils/setup/setupBin"
import { semverCoerceIfInvalid } from "../utils/setup/version"
import { setupMacOSSDK } from "../macos-sdk/macos-sdk"
import { addEnv } from "../utils/env/addEnv"
import { setupAptPack, updateAptAlternatives } from "../utils/setup/setupAptPack"
import { info, warning } from "ci-log"
import { GITHUB_ACTIONS } from "ci-info"
import { setupGcc } from "../gcc/gcc"
import { getVersion } from "../versions/versions"
import { isUbuntu } from "../utils/env/isUbuntu"
import { getLLVMPackageInfo } from "./llvm_url"
import { ubuntuVersion } from "../utils/env/ubuntu_version"
import { pathExists } from "path-exists"
import { ExecaReturnValue } from "execa"
export async function setupLLVM(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
const installationInfo = await setupLLVMWithoutActivation(version, setupDir, arch)
await activateLLVM(installationInfo.installDir ?? setupDir, version)
await activateLLVM(installationInfo.installDir ?? setupDir)
return installationInfo
}
let installedDeps = false
/** Setup llvm tools (clang tidy, clang format, etc) without activating llvm and using it as the compiler */
export const setupClangTools = setupLLVMWithoutActivation
async function setupLLVMWithoutActivation(version: string, setupDir: string, arch: string) {
const installationInfoPromise = setupBin("llvm", version, getLLVMPackageInfo, setupDir, arch)
let depsPromise: Promise<void>
if (!installedDeps) {
depsPromise = setupLLVMDeps(arch, version)
// eslint-disable-next-line require-atomic-updates
installedDeps = true
} else {
depsPromise = Promise.resolve()
}
// install LLVM and its dependencies in parallel
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [installationInfo, _] = await Promise.all([installationInfoPromise, depsPromise])
const [installationInfo, _1, _2] = await Promise.all([
setupLLVMOnly(version, setupDir, arch),
setupLLVMDeps(arch),
addLLVMLoggingMatcher(),
])
return installationInfo
}
async function setupLLVMDeps(arch: string, version: string) {
if (process.platform === "linux") {
// install llvm build dependencies
await setupGcc(getVersion("gcc", undefined, await ubuntuVersion()), "", arch) // using llvm requires ld, an up to date libstdc++, etc. So, install gcc first
async function setupLLVMOnly(version: string, setupDir: string, arch: string) {
const coeredVersion = semverCoerceIfInvalid(version)
const majorVersion = parseInt(coeredVersion.split(".")[0], 10)
try {
if (isUbuntu()) {
const majorVersion = parseInt(version.split(".")[0], 10)
if (majorVersion <= 10) {
await setupAptPack([{ name: "libtinfo5" }])
} else {
await setupAptPack([{ name: "libtinfo-dev" }])
}
return await setupLLVMApt(majorVersion)
}
// TODO: install libtinfo on other distros
// await setupPacmanPack("ncurses")
} catch (err) {
info(`Failed to install llvm via system package manager ${err}`)
}
const installationInfo = await setupBin("llvm", version, getLLVMPackageInfo, setupDir, arch)
await llvmBinaryDeps(majorVersion)
return installationInfo
}
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,
})
await addPath(`${installationFolder}/bin`)
return {
installDir: `${installationFolder}`,
binDir: `${installationFolder}/bin`,
bin: `${installationFolder}/bin/clang++`,
}
}
export async function activateLLVM(directory: string, versionGiven: string) {
const _version = semverCoerceIfInvalid(versionGiven)
async function patchAptLLVMScript(path: string, target_path: string) {
let script = await readFile(path, "utf-8")
// make the scirpt non-interactive and fix broken packages
script = script
.replace(
/add-apt-repository "\${REPO_NAME}"/g,
// eslint-disable-next-line no-template-curly-in-string
'add-apt-repository -y "${REPO_NAME}"'
)
// fix conflicts between libclang-rt and libclang
.replace(/apt-get install -y/g, 'apt-get install -o Dpkg::Options::="--force-overwrite" -y --fix-broken')
// use nala if it is available
if (hasNala()) {
script = script.replace(/apt-get/g, "nala")
}
await writeFile(target_path, script)
const lib = join(directory, "lib")
// the packages needed by the script
return [{ name: "lsb-release" }, { name: "wget" }, { name: "software-properties-common" }, { name: "gnupg" }]
}
async function llvmBinaryDeps_raw(majorVersion: number) {
if (isUbuntu()) {
if (majorVersion <= 10) {
await setupAptPack([{ name: "libtinfo5" }])
} else {
await setupAptPack([{ name: "libtinfo-dev" }])
}
}
}
const llvmBinaryDeps = memoize(llvmBinaryDeps_raw, { isPromise: true })
async function setupLLVMDeps_raw(arch: string) {
if (process.platform === "linux") {
// using llvm requires ld, an up to date libstdc++, etc. So, install gcc first
await setupGcc(getVersion("gcc", undefined, await ubuntuVersion()), "", arch)
}
}
const setupLLVMDeps = memoize(setupLLVMDeps_raw, { isPromise: true })
export async function activateLLVM(directory: string) {
const ld = process.env.LD_LIBRARY_PATH ?? ""
const dyld = process.env.DYLD_LIBRARY_PATH ?? ""
const promises: Promise<void | ExecaReturnValue<string>>[] = [
const actPromises: Promise<any>[] = [
// the output of this action
addEnv("LLVM_PATH", directory),
// Setup LLVM as the compiler
addEnv("LD_LIBRARY_PATH", `${lib}${delimiter}${ld}`),
addEnv("DYLD_LIBRARY_PATH", `${lib}${delimiter}${dyld}`),
addEnv("LD_LIBRARY_PATH", `${directory}/lib${delimiter}${ld}`),
addEnv("DYLD_LIBRARY_PATH", `${directory}/lib${delimiter}${dyld}`),
// compiler flags
addEnv("LDFLAGS", `-L"${directory}/lib"`),
@ -94,7 +147,6 @@ export async function activateLLVM(directory: string, versionGiven: string) {
// TODO Causes issues with clangd
// TODO Windows builds fail with llvm's CPATH
// if (process.platform !== "win32") {
// const llvmMajor = semverMajor(version)
// if (await pathExists(`${directory}/lib/clang/${version}/include`)) {
// promises.push(addEnv("CPATH", `${directory}/lib/clang/${version}/include`))
// } else if (await pathExists(`${directory}/lib/clang/${llvmMajor}/include`)) {
@ -103,7 +155,7 @@ export async function activateLLVM(directory: string, versionGiven: string) {
// }
if (isUbuntu()) {
promises.push(
actPromises.push(
updateAptAlternatives("cc", `${directory}/bin/clang`),
updateAptAlternatives("cxx", `${directory}/bin/clang++`),
updateAptAlternatives("clang", `${directory}/bin/clang`),
@ -114,25 +166,15 @@ export async function activateLLVM(directory: string, versionGiven: string) {
)
}
if (GITHUB_ACTIONS) {
await addLLVMLoggingMatcher()
}
await Promise.all(promises)
}
/** Setup llvm tools (clang tidy, clang format, etc) without activating llvm and using it as the compiler */
export async function setupClangTools(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
if (GITHUB_ACTIONS) {
await addLLVMLoggingMatcher()
}
return setupLLVMWithoutActivation(version, setupDir, arch)
await Promise.all(actPromises)
}
async function addLLVMLoggingMatcher() {
const matcherPath = join(__dirname, "llvm_matcher.json")
if (!(await pathExists(matcherPath))) {
return warning("the llvm_matcher.json file does not exist in the same folder as setup-cpp.js")
if (GITHUB_ACTIONS) {
const matcherPath = join(__dirname, "llvm_matcher.json")
if (!(await pathExists(matcherPath))) {
return warning("the llvm_matcher.json file does not exist in the same folder as setup-cpp.js")
}
info(`::add-matcher::${matcherPath}`)
}
info(`::add-matcher::${matcherPath}`)
}

View File

@ -67,6 +67,8 @@ export const VERSIONS: Set<string> = getVersions([
"16.0.2",
"16.0.3",
"16.0.4",
"16.0.5",
"16.0.6",
])
/** The LLVM versions that were never released for the Windows platform. */
@ -97,6 +99,8 @@ const DARWIN_MISSING = new Set([
"16.0.2",
"16.0.3",
"16.0.4",
"16.0.5",
"16.0.6",
])
/**
@ -161,7 +165,7 @@ const UBUNTU_SUFFIX_MAP: { [key: string]: string } = {
}
/** The latest supported LLVM version for the Linux (Ubuntu) platform. */
const MAX_UBUNTU: string = "15.0.6"
const MAX_UBUNTU: string = "16.0.4"
//================================================
// URL

View File

@ -23,7 +23,7 @@ export async function setupMake(version: string, _setupDir: string, _arch: strin
if (isArch()) {
return setupPacmanPack("make", version)
} else if (hasDnf()) {
return setupDnfPack("make", version)
return setupDnfPack([{ name: "make", version }])
} else if (isUbuntu()) {
return setupAptPack([{ name: "make", version }])
}

View File

@ -2,7 +2,7 @@ import { dirname } from "patha"
import which from "which"
import { isUbuntu } from "../utils/env/isUbuntu"
import { execRootSync } from "admina"
import { addAptKeyViaDownload, setupAptPack } from "../utils/setup/setupAptPack"
import { addAptKeyViaDownload, hasNala, setupAptPack } from "../utils/setup/setupAptPack"
let binDir: string | undefined
@ -45,3 +45,10 @@ export async function setupNala(version: string, _setupDir: string, _arch: strin
return { binDir }
}
export function bashWithNala(script: string) {
if (hasNala()) {
return `apt-get() { nala $@; }; export -f apt-get; ${script}; unset -f apt-get`
}
return script
}

View File

@ -26,12 +26,12 @@ export async function setupPowershell(version: string | undefined, _setupDir: st
if (isArch()) {
return setupPacmanPack("powershell-bin", version, "yay")
} else if (hasDnf()) {
setupDnfPack("curl")
setupDnfPack([{ name: "curl" }])
execRootSync("/bin/bash", [
"-c",
`curl https://packages.microsoft.com/config/rhel/8/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo`,
])
return setupDnfPack("powershell", version)
return setupDnfPack([{ name: "powershell", version }])
} else if (isUbuntu()) {
await setupAptPack([{ name: "curl" }])
const ubuntuVerSplitted = (await ubuntuVersion())!

View File

@ -112,7 +112,7 @@ async function setupPythonSystem(setupDir: string, version: string) {
if (isArch()) {
installInfo = await setupPacmanPack("python", version)
} else if (hasDnf()) {
installInfo = setupDnfPack("python3", version)
installInfo = await setupDnfPack([{ name: "python3", version }])
} else if (isUbuntu()) {
installInfo = await setupAptPack([{ name: "python3", version }, { name: "python-is-python3" }])
} else {
@ -234,7 +234,7 @@ function setupPipSystem() {
if (isArch()) {
return setupPacmanPack("python-pip")
} else if (hasDnf()) {
return setupDnfPack("python3-pip")
return setupDnfPack([{ name: "python3-pip" }])
} else if (isUbuntu()) {
return setupAptPack([{ name: "python3-pip" }])
}

View File

@ -20,8 +20,10 @@ export function setupSevenZip(version: string, _setupDir: string, _arch: string)
if (isArch()) {
return setupPacmanPack("p7zip", version)
} else if (hasDnf()) {
setupDnfPack("p7zip", version)
return setupDnfPack("p7zip-plugins", version)
return setupDnfPack([
{ name: "p7zip", version },
{ name: "p7zip-plugins", version },
])
} else if (isUbuntu()) {
return setupAptPack([{ name: "p7zip-full", version }])
}

View File

@ -2,13 +2,13 @@ import { InstallationInfo } from "./setupBin"
import { execRoot, execRootSync } from "admina"
import { GITHUB_ACTIONS } from "ci-info"
import { addEnv, cpprc_path, setupCppInProfile } from "../env/addEnv"
import which from "which"
import { pathExists } from "path-exists"
import { promises as fsPromises } from "fs"
const { appendFile } = fsPromises
import { execa } from "execa"
import { execa, ExecaError } from "execa"
import escapeRegex from "escape-string-regexp"
import { warning, info } from "ci-log"
import which from "which"
/* eslint-disable require-atomic-updates */
let didUpdate: boolean = false
@ -52,12 +52,31 @@ export async function setupAptPack(packages: AptPackage[], update = false): Prom
}
const aptArgs = await Promise.all(packages.map((pack) => getAptArg(pack.name, pack.version)))
execRootSync(apt, ["install", "--fix-broken", "-y", ...aptArgs])
try {
execRootSync(apt, ["install", "--fix-broken", "-y", ...aptArgs])
} catch (err) {
if ("stderr" in (err as ExecaError)) {
const stderr = (err as ExecaError).stderr
if (stderr.includes("E: Could not get lock") || stderr.includes("dpkg: error processing archive")) {
warning(`Failed to install packages ${aptArgs}. Retrying...`)
execRootSync(apt, ["install", "--fix-broken", "-y", ...aptArgs])
}
} else {
throw err
}
}
return { binDir: "/usr/bin/" }
}
async function getAptArg(name: string, version: string | undefined) {
export enum AptPackageType {
NameDashVersion,
NameEqualsVersion,
Name,
None,
}
export async function aptPackageType(name: string, version: string | undefined): Promise<AptPackageType> {
if (version !== undefined && version !== "") {
const { stdout } = await execa("apt-cache", [
"search",
@ -65,26 +84,55 @@ async function getAptArg(name: string, version: string | undefined) {
`^${escapeRegex(name)}-${escapeRegex(version)}$`,
])
if (stdout.trim() !== "") {
return `${name}-${version}`
} else {
try {
// check if apt-get show can find the version
const { stdout: showStdout } = await execa("apt-cache", ["show", `${name}=${version}`])
if (showStdout.trim() === "") {
return `${name}=${version}`
}
} catch {
// ignore
return AptPackageType.NameDashVersion
}
try {
// check if apt-get show can find the version
// eslint-disable-next-line @typescript-eslint/no-shadow
const { stdout } = await execa("apt-cache", ["show", `${name}=${version}`])
if (stdout.trim() === "") {
return AptPackageType.NameEqualsVersion
}
warning(`Failed to install ${name} ${version} via apt, trying without version`)
} catch {
// ignore
}
}
return name
try {
const { stdout: showStdout } = await execa("apt-cache", ["show", name])
if (showStdout.trim() !== "") {
return AptPackageType.Name
}
} catch {
// ignore
}
return AptPackageType.None
}
async function getAptArg(name: string, version: string | undefined) {
const package_type = await aptPackageType(name, version)
switch (package_type) {
case AptPackageType.NameDashVersion:
return `${name}-${version}`
case AptPackageType.NameEqualsVersion:
return `${name}=${version}`
case AptPackageType.Name:
return name
case AptPackageType.None:
default:
throw new Error(`Could not find package ${name} ${version ?? ""}`)
}
}
export function hasNala() {
return which.sync("nala", { nothrow: true }) !== null
}
function getApt() {
let apt: string
if (which.sync("nala", { nothrow: true }) !== null) {
if (hasNala()) {
apt = "nala"
} else {
apt = "apt-get"

View File

@ -107,9 +107,7 @@ export async function setupBin(
if (isArch()) {
await Promise.all([setupPacmanPack("unzip"), setupPacmanPack("tar"), setupPacmanPack("xz")])
} else if (hasDnf()) {
setupDnfPack("unzip")
setupDnfPack("tar")
setupDnfPack("xz")
await setupDnfPack([{ name: "unzip" }, { name: "tar" }, { name: "xz" }])
} else if (isUbuntu()) {
await setupAptPack([{ name: "unzip" }, { name: "tar" }, { name: "xz-utils" }])
}

View File

@ -1,31 +1,42 @@
/* eslint-disable require-atomic-updates */
import { InstallationInfo } from "./setupBin"
import { execRootSync } from "admina"
import { info, warning } from "ci-log"
import { execa } from "execa"
// let didUpdate: boolean = false
type DnfPackage = {
name: string
version?: string
}
/** A function that installs a package using dnf */
export function setupDnfPack(name: string, version?: string): InstallationInfo {
info(`Installing ${name} ${version ?? ""} via dnf`)
const dnf = "dnf"
// if (!didUpdate) {
// execRootSync(dnf, ["-y", "check-update"])
// didUpdate = true
// }
if (version !== undefined && version !== "") {
try {
execRootSync(dnf, ["-y", "install", `${name}-${version}`])
} catch (err) {
warning(`${(err as Error).toString()}\nInstalling the default version available via dnf`)
execRootSync(dnf, ["-y", "install", name])
}
} else {
execRootSync(dnf, ["-y", "install", name])
export async function setupDnfPack(packages: DnfPackage[]): Promise<InstallationInfo> {
for (const { name, version } of packages) {
info(`Installing ${name} ${version ?? ""} via dnf`)
}
const dnfArgs = await Promise.all(packages.map((pack) => getDnfArg(pack.name, pack.version)))
execRootSync("dnf", ["-y", "install", ...dnfArgs])
return { binDir: "/usr/bin/" }
}
async function getDnfArg(name: string, version: string | undefined) {
if (version !== undefined && version !== "") {
// check if name-version is available
const { stdout } = await execa("dnf", ["search", "-q", `${name}-${version}`])
if (stdout.trim() !== "") {
return `${name}-${version}`
} else {
// try with ${name}${version}
// eslint-disable-next-line @typescript-eslint/no-shadow
const { stdout } = await execa("dnf", ["search", "-q", `${name}${version}`])
if (stdout.trim() !== "") {
return `${name}${version}`
}
warning(`Failed to install ${name} ${version} via dnf, trying without version`)
}
}
return name
}

View File

@ -35,20 +35,24 @@ export async function testBin(
args: string[] | null = ["--version"],
binDir: string | undefined = undefined
) {
let bin = name
if (typeof binDir === "string") {
console.log(`Testing the existence of ${binDir}`)
expect(binDir).toBeDefined()
expect(binDir).not.toHaveLength(0)
expect(await pathExists(binDir)).toBeTruthy()
bin = join(binDir, addExeExt(name))
}
try {
let bin = name
if (typeof binDir === "string") {
console.log(`Testing the existence of ${binDir}`)
expect(binDir).toBeDefined()
expect(binDir).not.toHaveLength(0)
expect(await pathExists(binDir)).toBeTruthy()
bin = join(binDir, addExeExt(name))
}
if (args !== null) {
console.log(`Running ${bin} ${args.join(" ")}`)
const { status } = spawn.sync(bin, args, { stdio: "inherit" })
expect(status).toBe(0)
}
if (args !== null) {
console.log(`Running ${bin} ${args.join(" ")}`)
const { status } = spawn.sync(bin, args, { stdio: "inherit" })
expect(status).toBe(0)
}
expect((await io.which(name, true)).includes(bin))
expect((await io.which(name, true)).includes(bin))
} catch (err) {
throw new Error(`Failed to test bin ${name}: ${err}`)
}
}

View File

@ -30,12 +30,14 @@ export async function setupVcpkg(_version: string, setupDir: string, _arch: stri
setupPacmanPack("pkg-config"),
])
} else if (hasDnf()) {
setupDnfPack("curl")
setupDnfPack("zip")
setupDnfPack("unzip")
setupDnfPack("tar")
setupDnfPack("git")
setupDnfPack("pkg-config")
await setupDnfPack([
{ name: "curl" },
{ name: "zip" },
{ name: "unzip" },
{ name: "tar" },
{ name: "git" },
{ name: "pkg-config" },
])
} else if (isUbuntu()) {
await setupAptPack([
{ name: "curl" },

View File

@ -4,7 +4,6 @@ import { DefaultLinuxVersion, DefaultVersions } from "./default_versions"
/** Get the default version if passed true or undefined, otherwise return the version itself */
export function getVersion(name: string, version: string | undefined, osVersion: number[] | null = null) {
console.log("isDefault", version, name, isVersionDefault(version))
if (isVersionDefault(version) && process.platform === "linux" && osVersion !== null && name in DefaultLinuxVersion) {
return getDefaultLinuxVersion(osVersion, DefaultLinuxVersion[name]!)
} else if (isVersionDefault(version) && name in DefaultVersions) {