Skip to content

Commit bcd2a42

Browse files
authored
Merge pull request #257 from aminya/vcpkg-version
2 parents 55af62e + 315189b commit bcd2a42

File tree

13 files changed

+165
-120
lines changed

13 files changed

+165
-120
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ exe/
1717
*.log
1818
*.exe
1919
.cache/
20+
21+
coverage

biome.jsonc

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"**/dist/**",
88
"dev/cpp_vcpkg_project/**/*",
99
"**/.venv/",
10-
"**/.*cache/"
10+
"**/.*cache/",
11+
"**/coverage/"
1112
],
1213
"ignoreUnknown": true
1314
},

dist/actions/setup-cpp.js

+28-27
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

+28-27
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

+28-27
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

+5-3
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@ export async function setupLLVM(version: string, setupDir: string, arch: string)
2323
}
2424

2525
async function setupLLVMWithoutActivation_raw(version: string, setupDir: string, arch: string) {
26-
// install LLVM and its dependencies in parallel
27-
const [installationInfo, _1, _2] = await Promise.all([
26+
// install LLVM
27+
const [installationInfo, _1] = await Promise.all([
2828
setupLLVMOnly(version, setupDir, arch),
29-
setupLLVMDeps(arch),
3029
addLLVMLoggingMatcher(),
3130
])
3231

32+
// install LLVM dependencies
33+
await setupLLVMDeps(arch)
34+
3335
return installationInfo
3436
}
3537
const setupLLVMWithoutActivation = memoize(setupLLVMWithoutActivation_raw, { isPromise: true })

src/llvm/llvm_installer.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { execa } from "execa"
44
import { chmod, readFile, writeFile } from "fs/promises"
55
import { DEFAULT_TIMEOUT } from "../installTool"
66
import { addPath } from "../utils/env/addEnv"
7-
import { hasNala, isPackageRegexInstalled, setupAptPack } from "../utils/setup/setupAptPack"
7+
import { aptTimeout, hasNala, isPackageRegexInstalled, setupAptPack } from "../utils/setup/setupAptPack"
88
import type { InstallationInfo } from "../utils/setup/setupBin"
99

1010
export enum LLVMPackages {
@@ -70,16 +70,16 @@ function nonInteractiveScript(script: string) {
7070
// make the scirpt non-interactive and fix broken packages
7171
return script.replace(
7272
/add-apt-repository "\${REPO_NAME}"/g,
73-
// eslint-disable-next-line no-template-curly-in-string
74-
"add-apt-repository -y \"${REPO_NAME}\"",
73+
`add-apt-repository -y -n "\${REPO_NAME}"
74+
apt-get update -o ${aptTimeout} -y`,
7575
)
7676
}
7777

7878
async function removeConflictingPackages(givenScript: string) {
7979
// fix conflicts between libclang-rt and libclang
8080
let script = givenScript.replace(
8181
/apt-get install -y/g,
82-
"apt-get install -o Dpkg::Options::=\"--force-overwrite\" -y --fix-broken",
82+
`apt-get install -o Dpkg::Options::="--force-overwrite" -o ${aptTimeout} -y --fix-broken`,
8383
)
8484

8585
// check if these are installed and if so, remove them from the script as they conflict

src/utils/setup/setupAptPack.ts

+35-17
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import type { InstallationInfo } from "./setupBin"
1313
let didUpdate: boolean = false
1414
let didInit: boolean = false
1515

16+
// wait up to 300 seconds if the apt-get lock is held
17+
export const aptTimeout = "DPkg::Lock::Timeout=300"
18+
1619
export type AptPackage = {
1720
name: string
1821
version?: string
@@ -44,13 +47,9 @@ export async function setupAptPack(packages: AptPackage[], update = false): Prom
4447
// Add the repos if needed
4548
await addRepositories(apt, packages)
4649

47-
// Qualify the packages into full package name/version
48-
let qualifiedPacks = await Promise.all(packages.map((pack) => getAptArg(pack.name, pack.version)))
49-
50-
// find the packages that are not installed
51-
qualifiedPacks = await Promise.all(qualifiedPacks.filter(async (pack) => !(await isPackageInstalled(pack))))
50+
const needToInstall = await filterAndQualifyAptPackages(packages)
5251

53-
if (qualifiedPacks.length === 0) {
52+
if (needToInstall.length === 0) {
5453
info("All packages are already installed")
5554
return { binDir: "/usr/bin/" }
5655
}
@@ -63,13 +62,13 @@ export async function setupAptPack(packages: AptPackage[], update = false): Prom
6362

6463
// Install
6564
try {
66-
execRootSync(apt, ["install", "--fix-broken", "-y", ...qualifiedPacks])
65+
execRootSync(apt, ["install", "--fix-broken", "-y", ...needToInstall])
6766
} catch (err) {
6867
if ("stderr" in (err as ExecaError)) {
6968
const stderr = (err as ExecaError).stderr
7069
if (retryErrors.some((error) => stderr.includes(error))) {
71-
warning(`Failed to install packages ${qualifiedPacks}. Retrying...`)
72-
execRootSync(apt, ["install", "--fix-broken", "-y", ...qualifiedPacks])
70+
warning(`Failed to install packages ${needToInstall}. Retrying...`)
71+
execRootSync(apt, ["install", "--fix-broken", "-y", "-o", aptTimeout, ...needToInstall])
7372
}
7473
} else {
7574
throw err
@@ -86,17 +85,32 @@ export enum AptPackageType {
8685
None = 3,
8786
}
8887

88+
/**
89+
* Filter out the packages that are already installed and qualify the packages into a full package name/version
90+
*/
91+
async function filterAndQualifyAptPackages(packages: AptPackage[]) {
92+
return (await Promise.all(packages.map(qualifiedNeededAptPackage)))
93+
.filter((pack) => pack !== undefined)
94+
}
95+
96+
async function qualifiedNeededAptPackage(pack: AptPackage) {
97+
// Qualify the packages into full package name/version
98+
const qualified = await getAptArg(pack.name, pack.version)
99+
// filter out the packages that are already installed
100+
return (await isPackageInstalled(qualified)) ? undefined : qualified
101+
}
102+
89103
async function addRepositories(apt: string, packages: AptPackage[]) {
90104
const allRepositories = [...new Set(packages.flatMap((pack) => pack.repositories ?? []))]
91105
if (allRepositories.length !== 0) {
92106
if (!didInit) {
93107
await initApt(apt)
94108
didInit = true
95109
}
96-
await installAddAptRepo()
110+
await installAddAptRepo(apt)
97111
for (const repo of allRepositories) {
98112
// eslint-disable-next-line no-await-in-loop
99-
execRootSync("add-apt-repository", ["-y", repo])
113+
execRootSync("add-apt-repository", ["-y", "--no-update", repo])
100114
}
101115
updateRepos(apt)
102116
didUpdate = true
@@ -163,7 +177,7 @@ export function hasNala() {
163177
return which.sync("nala", { nothrow: true }) !== null
164178
}
165179

166-
function getApt() {
180+
export function getApt() {
167181
let apt: string
168182
if (hasNala()) {
169183
apt = "nala"
@@ -174,14 +188,14 @@ function getApt() {
174188
}
175189

176190
function updateRepos(apt: string) {
177-
execRootSync(apt, apt !== "nala" ? ["update", "-y"] : ["update"])
191+
execRootSync(apt, apt !== "nala" ? ["update", "-y", "-o", aptTimeout] : ["update", "-o", aptTimeout])
178192
}
179193

180-
async function installAddAptRepo() {
194+
async function installAddAptRepo(apt: string) {
181195
if (await isPackageInstalled("software-properties-common")) {
182196
return
183197
}
184-
execRootSync("apt-get", ["install", "-y", "--fix-broken", "software-properties-common"])
198+
execRootSync(apt, ["install", "-y", "--fix-broken", "-o", aptTimeout, "software-properties-common"])
185199
}
186200

187201
/** Install gnupg and certificates (usually missing from docker containers) */
@@ -192,10 +206,14 @@ async function initApt(apt: string) {
192206
didUpdate = true
193207
}
194208

195-
const toInstall = ["ca-certificates", "gnupg", "apt-utils"].filter(async (pack) => !(await isPackageInstalled(pack)))
209+
const toInstall = await filterAndQualifyAptPackages([
210+
{ name: "ca-certificates" },
211+
{ name: "gnupg" },
212+
{ name: "apt-utils" },
213+
])
196214

197215
if (toInstall.length !== 0) {
198-
execRootSync(apt, ["install", "-y", "--fix-broken", ...toInstall])
216+
execRootSync(apt, ["install", "-y", "--fix-broken", "-o", aptTimeout, ...toInstall])
199217
}
200218

201219
const promises: Promise<string | void>[] = [

src/vcpkg/__tests__/vcpkg.test.ts

+16-8
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
1-
import { setupTmpDir, testBin } from "../../utils/tests/test-helpers"
1+
import { cleanupTmpDir, setupTmpDir, testBin } from "../../utils/tests/test-helpers"
22
import { setupVcpkg } from "../vcpkg"
33

44
jest.setTimeout(300000)
5-
async function testVcpkg(directory: string) {
6-
const { binDir } = await setupVcpkg("", directory, "")
7-
await testBin("vcpkg", ["--version"], binDir)
8-
return binDir
9-
}
105

116
describe("setup-vcpkg", () => {
127
let directory: string
13-
beforeAll(async () => {
8+
beforeEach(async () => {
149
directory = await setupTmpDir("vcpkg")
1510
})
1611

1712
it("should setup vcpkg", async () => {
18-
await testVcpkg(directory)
13+
console.log(!("true" in ["", "true"]))
14+
const { binDir } = await setupVcpkg("", directory, "")
15+
await testBin("vcpkg", ["--version"], binDir)
16+
return binDir
17+
})
18+
19+
it("should setup vcpkg with specific version", async () => {
20+
const { binDir } = await setupVcpkg("e590c2b30c08caf1dd8d612ec602a003f9784b7d", directory, "")
21+
await testBin("vcpkg", ["--version"], binDir)
22+
return binDir
23+
})
24+
25+
afterEach(async () => {
26+
await cleanupTmpDir(directory)
1927
})
2028
})

src/vcpkg/vcpkg.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { grantUserWriteAccess } from "admina"
2-
import { notice } from "ci-log"
2+
import { info, notice } from "ci-log"
33
import { execaSync } from "execa"
44
import { pathExists } from "path-exists"
55
import { addShExt, addShRelativePrefix, dirname, join } from "patha"
@@ -16,7 +16,7 @@ import { setupPacmanPack } from "../utils/setup/setupPacmanPack"
1616
let hasVCPKG = false
1717

1818
// eslint-disable-next-line @typescript-eslint/no-unused-vars
19-
export async function setupVcpkg(_version: string, setupDir: string, _arch: string): Promise<InstallationInfo> {
19+
export async function setupVcpkg(version: string, setupDir: string, _arch: string): Promise<InstallationInfo> {
2020
if (!hasVCPKG || which.sync("vcpkg", { nothrow: true }) === null) {
2121
if (process.platform === "linux") {
2222
// vcpkg download and extraction dependencies
@@ -50,12 +50,23 @@ export async function setupVcpkg(_version: string, setupDir: string, _arch: stri
5050
}
5151
}
5252

53+
// clone if not already exists
5354
if (!(await pathExists(join(setupDir, addShExt("bootstrap-vcpkg", ".bat"))))) {
5455
execaSync("git", ["clone", "https://github.com/microsoft/vcpkg"], { cwd: dirname(setupDir), stdio: "inherit" })
5556
} else {
56-
notice(`Vcpkg folder already exists at ${setupDir}. This might mean that ~/vcpkg is restored from the cache.`)
57+
notice(`Vcpkg folder already exists at ${setupDir}. Skipping the clone`)
5758
}
5859

60+
// if version specified, checkout the version
61+
if (version !== "" && version !== "true") {
62+
info(`Checking out vcpkg version ${version}`)
63+
execaSync("git", ["checkout", version], {
64+
cwd: setupDir,
65+
stdio: "inherit",
66+
})
67+
}
68+
69+
// bootstrap vcpkg
5970
execaSync(addShExt(addShRelativePrefix("bootstrap-vcpkg"), ".bat"), {
6071
cwd: setupDir,
6172
shell: true,

0 commit comments

Comments
 (0)