Skip to content

Commit 1cc2853

Browse files
authored
Merge pull request #183 from aminya/llvm-conflicts [skip test]
2 parents eeed1d3 + 5f5040c commit 1cc2853

File tree

10 files changed

+159
-106
lines changed

10 files changed

+159
-106
lines changed

cspell.config.yaml

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ ignorePaths:
1212
- .vscode/extensions.json
1313
words:
1414
- aarch
15-
- clangd
16-
- Trofimovich
17-
- cobertura
18-
- whatwg
1915
- aminya
2016
- applellvm
2117
- bazel
@@ -24,7 +20,9 @@ words:
2420
- caxa
2521
- ccache
2622
- choco
23+
- clangd
2724
- cmake
25+
- cobertura
2826
- copr
2927
- CPATH
3028
- Cppcheck
@@ -50,6 +48,7 @@ words:
5048
- LDFLAGS
5149
- lefticus
5250
- libbinutils
51+
- libc
5352
- libdw
5453
- libstdc
5554
- libtinfo
@@ -77,6 +76,7 @@ words:
7776
- setx
7877
- Syuu
7978
- terserrc
79+
- Trofimovich
8080
- tsbuildinfo
8181
- ucrt
8282
- untildify
@@ -87,6 +87,7 @@ words:
8787
- visualc
8888
- visualcpp
8989
- vsversion
90+
- whatwg
9091
- xcrun
9192
- Yahyaabadi
9293
ignoreWords: []

dist/actions/setup-cpp.js

+16-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/actions/setup-cpp.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/legacy/setup-cpp.js

+16-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/legacy/setup-cpp.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/modern/setup-cpp.js

+16-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/modern/setup-cpp.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/llvm/llvm.ts

+3-50
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
1-
import { execRoot } from "admina"
21
import { GITHUB_ACTIONS } from "ci-info"
32
import { info, warning } from "ci-log"
4-
import { execa } from "execa"
5-
import { promises } from "fs"
6-
const { readFile, writeFile, chmod } = promises
73
import memoize from "micro-memoize"
84
import { delimiter } from "path"
95
import { pathExists } from "path-exists"
106
import { addExeExt, join } from "patha"
117
import { setupGcc } from "../gcc/gcc"
128
import { setupMacOSSDK } from "../macos-sdk/macos-sdk"
13-
import { addEnv, addPath } from "../utils/env/addEnv"
9+
import { addEnv } from "../utils/env/addEnv"
1410
import { isUbuntu } from "../utils/env/isUbuntu"
1511
import { ubuntuVersion } from "../utils/env/ubuntu_version"
16-
import { hasNala, setupAptPack, updateAptAlternatives } from "../utils/setup/setupAptPack"
12+
import { setupAptPack, updateAptAlternatives } from "../utils/setup/setupAptPack"
1713
import { InstallationInfo, setupBin } from "../utils/setup/setupBin"
1814
import { semverCoerceIfInvalid } from "../utils/setup/version"
1915
import { getVersion } from "../versions/versions"
16+
import { setupLLVMApt } from "./llvm_installer"
2017
import { getLLVMPackageInfo } from "./llvm_url"
2118

2219
export async function setupLLVM(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
@@ -55,50 +52,6 @@ async function setupLLVMOnly(version: string, setupDir: string, arch: string) {
5552
return installationInfo
5653
}
5754

58-
async function setupLLVMApt(majorVersion: number): Promise<InstallationInfo> {
59-
// TODO for older versions, this also includes the minor version
60-
const installationFolder = `/usr/lib/llvm-${majorVersion}`
61-
62-
await setupAptPack([{ name: "curl" }])
63-
await execa("curl", ["-LJO", "https://apt.llvm.org/llvm.sh"], { cwd: "/tmp" })
64-
const neededPackages = await patchAptLLVMScript("/tmp/llvm.sh", "/tmp/llvm-setup-cpp.sh")
65-
await setupAptPack(neededPackages)
66-
await chmod("/tmp/llvm-setup-cpp.sh", "755")
67-
await execRoot("bash", ["/tmp/llvm-setup-cpp.sh", `${majorVersion}`, "all"], {
68-
stdio: "inherit",
69-
shell: true,
70-
})
71-
72-
await addPath(`${installationFolder}/bin`)
73-
74-
return {
75-
installDir: `${installationFolder}`,
76-
binDir: `${installationFolder}/bin`,
77-
bin: `${installationFolder}/bin/clang++`,
78-
}
79-
}
80-
81-
async function patchAptLLVMScript(path: string, target_path: string) {
82-
let script = await readFile(path, "utf-8")
83-
// make the scirpt non-interactive and fix broken packages
84-
script = script
85-
.replace(
86-
/add-apt-repository "\${REPO_NAME}"/g,
87-
// eslint-disable-next-line no-template-curly-in-string
88-
'add-apt-repository -y "${REPO_NAME}"'
89-
)
90-
// fix conflicts between libclang-rt and libclang
91-
.replace(/apt-get install -y/g, 'apt-get install -o Dpkg::Options::="--force-overwrite" -y --fix-broken')
92-
// use nala if it is available
93-
if (hasNala()) {
94-
script = script.replace(/apt-get/g, "nala")
95-
}
96-
await writeFile(target_path, script)
97-
98-
// the packages needed by the script
99-
return [{ name: "lsb-release" }, { name: "wget" }, { name: "software-properties-common" }, { name: "gnupg" }]
100-
}
101-
10255
async function llvmBinaryDeps_raw(majorVersion: number) {
10356
if (isUbuntu()) {
10457
if (majorVersion <= 10) {

src/llvm/llvm_installer.ts

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { execRoot } from "admina"
2+
import { execa } from "execa"
3+
import { addPath } from "../utils/env/addEnv"
4+
import { hasNala, isPackageInstalled, setupAptPack } from "../utils/setup/setupAptPack"
5+
import { InstallationInfo } from "../utils/setup/setupBin"
6+
import { promises } from "fs"
7+
import { info } from "console"
8+
const { readFile, writeFile, chmod } = promises
9+
10+
export async function setupLLVMApt(majorVersion: number): Promise<InstallationInfo> {
11+
// TODO for older versions, this also includes the minor version
12+
const installationFolder = `/usr/lib/llvm-${majorVersion}`
13+
14+
await setupAptPack([{ name: "curl" }])
15+
await execa("curl", ["-LJO", "https://apt.llvm.org/llvm.sh"], { cwd: "/tmp" })
16+
const neededPackages = await patchAptLLVMScript("/tmp/llvm.sh", "/tmp/llvm-setup-cpp.sh")
17+
await setupAptPack(neededPackages)
18+
await chmod("/tmp/llvm-setup-cpp.sh", "755")
19+
await execRoot("bash", ["/tmp/llvm-setup-cpp.sh", `${majorVersion}`, "all"], {
20+
stdio: "inherit",
21+
shell: true,
22+
})
23+
24+
await addPath(`${installationFolder}/bin`)
25+
26+
return {
27+
installDir: `${installationFolder}`,
28+
binDir: `${installationFolder}/bin`,
29+
bin: `${installationFolder}/bin/clang++`,
30+
}
31+
}
32+
33+
async function patchAptLLVMScript(path: string, target_path: string) {
34+
let script = await readFile(path, "utf-8")
35+
36+
script = nonInteractiveScript(script)
37+
script = await removeConflictingPAckages(script)
38+
script = useNalaScript(script)
39+
40+
await writeFile(target_path, script)
41+
42+
// the packages needed by the script
43+
return [{ name: "lsb-release" }, { name: "wget" }, { name: "software-properties-common" }, { name: "gnupg" }]
44+
}
45+
function nonInteractiveScript(givenScript: string) {
46+
// make the scirpt non-interactive and fix broken packages
47+
return givenScript.replace(
48+
/add-apt-repository "\${REPO_NAME}"/g,
49+
// eslint-disable-next-line no-template-curly-in-string
50+
'add-apt-repository -y "${REPO_NAME}"'
51+
)
52+
}
53+
54+
async function removeConflictingPAckages(givenScript: string) {
55+
// fix conflicts between libclang-rt and libclang
56+
let script = givenScript.replace(
57+
/apt-get install -y/g,
58+
'apt-get install -o Dpkg::Options::="--force-overwrite" -y --fix-broken'
59+
)
60+
61+
// check if these are installed and if so, remove them from the script as they conflict
62+
const conflictingPackages = ["libc++-$LLVM_VERSION-dev", "libc++abi-$LLVM_VERSION-dev", "libunwind-$LLVM_VERSION-dev"]
63+
await Promise.all(
64+
conflictingPackages.map(async (pack) => {
65+
const installingPack = pack.replace("$LLVM_VERSION", "*")
66+
if (await isPackageInstalled(installingPack)) {
67+
info(`Removing conflicting package ${installingPack}`)
68+
script = script.replace(pack, "")
69+
}
70+
})
71+
)
72+
return script
73+
}
74+
75+
function useNalaScript(script: string) {
76+
// use nala if it is available
77+
if (hasNala()) {
78+
return script.replace(/apt-get/g, "nala")
79+
}
80+
return script
81+
}

src/utils/setup/setupAptPack.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ export type AptPackage = {
2020
repositories?: string[]
2121
}
2222

23+
const retryErrors = [
24+
"E: Could not get lock",
25+
"dpkg: error processing archive",
26+
"dpkg: error: dpkg status database is locked by another process",
27+
]
28+
2329
/** A function that installs a package using apt */
2430
export async function setupAptPack(packages: AptPackage[], update = false): Promise<InstallationInfo> {
2531
const apt: string = getApt()
@@ -57,7 +63,7 @@ export async function setupAptPack(packages: AptPackage[], update = false): Prom
5763
} catch (err) {
5864
if ("stderr" in (err as ExecaError)) {
5965
const stderr = (err as ExecaError).stderr
60-
if (stderr.includes("E: Could not get lock") || stderr.includes("dpkg: error processing archive")) {
66+
if (retryErrors.some((error) => stderr.includes(error))) {
6167
warning(`Failed to install packages ${aptArgs}. Retrying...`)
6268
execRootSync(apt, ["install", "--fix-broken", "-y", ...aptArgs])
6369
}
@@ -224,3 +230,15 @@ export async function updateAptAlternatives(name: string, path: string) {
224230
)
225231
}
226232
}
233+
234+
export async function isPackageInstalled(regexp: string) {
235+
try {
236+
// check if a package matching the regexp is installed
237+
const { stdout } = await execa("dpkg", ["-l", regexp])
238+
const lines = stdout.split("\n")
239+
// check if the output contains any lines that start with "ii"
240+
return lines.some((line) => line.startsWith("ii"))
241+
} catch {
242+
return false
243+
}
244+
}

0 commit comments

Comments
 (0)