mirror of https://github.com/aminya/setup-cpp
Merge pull request #182 from aminya/llvm-system [skip ci]
This commit is contained in:
commit
0c3b851567
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"recommendations": ["orta.vscode-jest", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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`.
|
||||
|
|
|
@ -9,6 +9,7 @@ ignorePaths:
|
|||
- dist/
|
||||
- dev/cpp_vcpkg_project
|
||||
- "**/node_modules/"
|
||||
- .vscode/extensions.json
|
||||
words:
|
||||
- aarch
|
||||
- clangd
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
@ -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": {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 }])
|
||||
}
|
||||
|
|
|
@ -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 }])
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"] },
|
||||
|
|
|
@ -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 }])
|
||||
}
|
||||
|
|
|
@ -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" }])
|
||||
}
|
||||
|
|
172
src/llvm/llvm.ts
172
src/llvm/llvm.ts
|
@ -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}`)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }])
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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())!
|
||||
|
|
|
@ -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" }])
|
||||
}
|
||||
|
|
|
@ -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 }])
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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" }])
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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}`)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue