Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,6 @@
"eslint.useESLintClass": true,
"yaml.schemas": {
"https://json.schemastore.org/container-structure-test.json": "/dev/docker/ci/tests/*.yml"
}
},
"js/ts.tsdk.path": "node_modules/typescript/lib"
}
1 change: 1 addition & 0 deletions dev/docker/ci/ubuntu-mingw.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ FROM aminya/setup-cpp-ubuntu:latest AS setup-cpp-ubuntu-mingw
# install mingw/powershell
RUN setup-cpp \
--compiler mingw \
--gcc true \
--powershell true && \
# cleanup
apt-get clean autoclean && \
Expand Down
1 change: 1 addition & 0 deletions dev/docker/setup-cpp/setup-cpp-ubuntu-mingw.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ RUN apt-get update -qq && \
--autoreconf true \
--nala true \
--compiler mingw \
--gcc true \
--cmake true \
--ninja true \
--task true \
Expand Down
26 changes: 13 additions & 13 deletions dist/legacy/setup-cpp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/legacy/setup-cpp.js.map

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions dist/modern/setup-cpp.mjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/modern/setup-cpp.mjs.map

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions packages/setup-apt/__tests__/qualify-install.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { execaSync } from "execa"

import { getAptEnv } from "../src/apt-env.js"
import { hasAptGet } from "../src/get-apt.js"
import { filterAndQualifyAptPackages } from "../src/qualify-install.js"

function indexedGccVariants() {
try {
const { stdout } = execaSync("apt-cache", ["search", "--names-only", "^gcc-[0-9]+$"], {
env: getAptEnv("apt-get"),
stdio: "pipe",
})
return stdout.split("\n")
.map((line) => line.trim().split(/\s+/u)[0])
.filter((name): name is string => name !== undefined && /^gcc-\d+$/u.test(name))
.sort((first, second) => {
const firstVersion = Number.parseInt(first.slice("gcc-".length), 10)
const secondVersion = Number.parseInt(second.slice("gcc-".length), 10)
return secondVersion - firstVersion
})
} catch {
return []
}
}

describe("filterAndQualifyAptPackages", () => {
if (!hasAptGet()) {
test.skip("filters installed packages", () => {})
return
}

it("filters an installed package when upgrade is disabled", async () => {
await expect(filterAndQualifyAptPackages([{ name: "apt", upgrade: false }])).resolves.toEqual([])
})

it("retains an installed package when upgrade is requested", async () => {
await expect(filterAndQualifyAptPackages([{ name: "apt", upgrade: true }])).resolves.toEqual(["apt"])
})

const gccVariants = indexedGccVariants()
if (gccVariants.length === 0) {
test.skip("resolves the highest indexed gcc-N package", () => {})
return
}

it("resolves an unversioned package to its highest indexed numeric variant", async () => {
await expect(filterAndQualifyAptPackages([{ name: "gcc" }])).resolves.toEqual([gccVariants[0]])
})
})
5 changes: 5 additions & 0 deletions packages/setup-apt/src/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ export type AptPackage = {
name: string
/** The version of the package (optional) */
version?: string
/**
* Whether to allow apt to upgrade the latest package available in the default repositories.
* This would could do a major upgrade for unversioned meta packages (e.g. gcc) or minor upgrade for versioned packages (e.g. gcc-9)
*/
upgrade?: boolean
/** The repository to add before installing the package (optional) */
repository?: string
/** The key to add before installing the package (optional) */
Expand Down
38 changes: 34 additions & 4 deletions packages/setup-apt/src/qualify-install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ export async function filterAndQualifyAptPackages(packages: AptPackage[], apt: s
/**
* Qualify the package into full package name/version.
* If the package is not installed, return the full package name/version.
* If the package is already installed, return undefined
* If the package is already installed and upgrade is not requested, return undefined
*/
export async function qualifiedNeededAptPackage(pack: AptPackage, apt: string = getApt()) {
// By default, leave the package in the install list so apt can select the candidate.
const upgrade = pack.upgrade ?? true
// Qualify the package into full package name/version
const qualified = await getAptArg(apt, pack)
// filter out the package that are already installed
return (await isAptPackInstalled(qualified)) ? undefined : qualified
// Filter out packages that are already installed unless they should be upgraded.
return (await isAptPackInstalled(qualified)) && !upgrade ? undefined : qualified
}

async function aptPackageType(
Expand Down Expand Up @@ -118,7 +120,14 @@ async function aptCacheShowHasPackage(apt: string, arg: string) {
}

async function getAptArg(apt: string, pack: AptPackage) {
const { name, version, fallBackToLatest = false } = pack
const { name, version, upgrade = true, fallBackToLatest = false } = pack

if ((version === undefined || version === "") && upgrade) {
const numericVariant = await findHighestNumericAptPackage(apt, name)
if (numericVariant !== undefined) {
return numericVariant
}
}

const package_type = await aptPackageType(apt, name, version, fallBackToLatest)
switch (package_type) {
Expand All @@ -133,3 +142,24 @@ async function getAptArg(apt: string, pack: AptPackage) {
throw new Error(`Could not find package '${name}' ${version ?? "with unspecified version"}`)
}
}

async function findHighestNumericAptPackage(apt: string, name: string) {
const packageNamePattern = new RegExp(`^${escapeRegex(name)}-([0-9]+)$`, "u")

try {
const { stdout } = await execa("apt-cache", [
"search",
"--names-only",
`^${escapeRegex(name)}-[0-9]+$`,
], { env: getAptEnv(apt), stdio: "pipe" })
const candidates = stdout.split("\n").flatMap((line) => {
const packageName: string | undefined = line.trim().split(/\s+/u)[0]
const match = packageName.match(packageNamePattern)
return match === null ? [] : [{ packageName, version: Number.parseInt(match[1], 10) }]
})

return candidates.sort((first, second) => second.version - first.version)[0]?.packageName
} catch {
return undefined
}
}
14 changes: 10 additions & 4 deletions patches/apply.mts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,16 @@ async function applyPatch(patch: string) {
}

console.log(`Applying patch ${patchFilePath} to ${patchedDir}`)
const result = applyPatchToDir({
patchedDir,
patchFilePath,
})
let result = false
try {
result = applyPatchToDir({
patchedDir,
patchFilePath,
})
} catch (err) {
console.error("pnpm patch failed. Maybe your node version is old", err)
result = false
}
// create .patched file in the patchedDir
await fs.writeFile(path.join(patchedDir, ".patched"), patch)
if (!result) {
Expand Down
17 changes: 16 additions & 1 deletion src/llvm/llvm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ciInfo from "ci-info"
const { GITHUB_ACTIONS } = ciInfo
import { info, warning } from "ci-log"
import { addEnv } from "envosman"
import { execa } from "execa"
import memoize from "memoizee"
import { pathExists } from "path-exists"
import { addExeExt } from "patha"
Expand All @@ -23,6 +24,7 @@ import { trySetupLLVMBrew } from "./llvm_brew_installer.js"
import { majorLLVMVersion } from "./utils.js"

const dirname = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url))
const APT_DEFAULT_GCC_DEPENDENCY = /^[\t ]+Depends:[\t ]+gcc-(\d+)[\t ]*$/mu

export async function setupLLVM({ version, setupDir, arch }: SetupOptions): Promise<InstallationInfo> {
const installationInfo = await setupLLVMOnly(version, setupDir, arch)
Expand Down Expand Up @@ -68,11 +70,24 @@ async function setupGccForLLVM_(arch: string) {
if (process.platform === "linux") {
// using llvm requires ld, an up to date libstdc++, etc. So, install gcc first,
// but with a lower priority than the one used by activateLLVM()
await setupGcc({ version: getVersion("gcc", undefined, await ubuntuVersion()), setupDir: "", arch, priority: 40 })
const distroVersion = await ubuntuVersion()
const defaultGccVersion = getVersion("gcc", undefined, distroVersion)
const gccVersion = hasAptGet() ? await getAptDefaultGccVersion(defaultGccVersion) : defaultGccVersion
await setupGcc({ version: gccVersion, setupDir: "", arch, priority: 40 })
}
}
const setupGccForLLVM = memoize(setupGccForLLVM_, { promise: true })

async function getAptDefaultGccVersion(fallback: string) {
try {
const { stdout } = await execa("apt-cache", ["depends", "gcc"], { stdio: "pipe" })
return stdout.match(APT_DEFAULT_GCC_DEPENDENCY)?.[1] ?? fallback
} catch {
// Preserve the existing default when APT metadata cannot be queried.
return fallback
}
}

export async function activateLLVM(directory: string, version: string) {
const ld = process.env.LD_LIBRARY_PATH ?? ""
const dyld = process.env.DYLD_LIBRARY_PATH ?? ""
Expand Down