UNPKG

setup-cpp

Version:

Install all the tools required for building and testing C++/C projects.

196 lines (176 loc) 6.03 kB
import { getExecOutput } from "@actions/exec" import { info } from "ci-log" import { isUrlOnline } from "is-url-online" import semverCoerce from "semver/functions/coerce" import semverCompare from "semver/functions/compare" import semverSatisfies from "semver/functions/satisfies" import semverValid from "semver/functions/valid" /** * Gets the specific versions supported by this action compatible with the supplied (specific or minimum) version in * descending order of release (e.g., `5.0.2`, `5.0.1`, and `5.0.0` for `5`). */ export function getSpecificVersions(versions: Set<string>, semversion: string): string[] { return Array.from(versions) .filter((v) => /^\d+\.\d+\.\d+$/.test(v) && v.startsWith(semversion)) .sort((a, b) => { try { return semverCompare(a, b) } catch (err) { return a.localeCompare(b) } }) .reverse() } /** * Gets the specific and minimum versions that can be used to refer to the supplied specific versions (e.g., `3`, `3.5`, * `3.5.2` for `3.5.2`). */ export function getVersions(specific: string[]): Set<string> { const versions = new Set(specific) for (const version of specific) { versions.add(/^\d+/.exec(version)![0]) versions.add(/^\d+\.\d+/.exec(version)![0]) } return versions } /** Gets the most recent specific version for which there is a valid download URL. */ export async function getSpecificVersionAndUrl( versions: Set<string>, platform: string, version: string, getUrl: (platform: string, version: string) => string | null | Promise<string | null>, ): Promise<[string, string]> { // specific ubuntu version if (platform === "linux" && version.includes("ubuntu")) { const url = await getUrl(platform, version) // eslint-disable-next-line no-await-in-loop if (url !== null && (await isUrlOnline(url))) { return [version, url] } } // if the given set doesn't include the version, throw an error if (!versions.has(version)) { throw new Error( `Unsupported target! (platform='${platform}', version='${version}'). Try one of the following: ${ JSON.stringify( versions, ) }`, ) } const offlineUrls: string[] = [] // TODO use Promise.any for (const specificVersion of getSpecificVersions(versions, version)) { // eslint-disable-next-line no-await-in-loop const url = await getUrl(platform, specificVersion) if (url !== null) { // eslint-disable-next-line no-await-in-loop if (await isUrlOnline(url)) { return [specificVersion, url] } else { offlineUrls.push(url) } } } throw new Error( `Unsupported target! (platform='${platform}', version='${version}'). Try one of the following: ${ JSON.stringify( versions, ) }`, ) } export const defaultVersionRegex = /v?(\d\S*)/ /** Get the version of a binary */ export async function getBinVersion(file: string, versionRegex: RegExp = defaultVersionRegex) { try { const execout = await getExecOutput(file, ["--version"]) const version_output = execout.stdout || execout.stderr || "" const version = version_output.trim().match(versionRegex)?.[1] return semverCoerce(version) ?? undefined } catch (e) { console.error(e) return undefined } } /** Check if the given bin is up to date against the target version */ export async function isBinUptoDate( givenFile: string, targetVersion: string, versionRegex: RegExp = defaultVersionRegex, ) { const givenVersion = await getBinVersion(givenFile, versionRegex) if (givenVersion !== undefined && targetVersion !== "") { try { // if -1, it means the given version is newer than the target version // this requires the target version to be a valid semver range return semverCompare(givenVersion, targetVersion) !== -1 } catch { // check if the given version satisfies the target version // this works even if the target version is not a valid semver range (e.g. >=1.2.3) return semverSatisfies(givenVersion, targetVersion) } } else { // assume given version is old return false } } /** Coerce the given version if it is invalid */ export function semverCoerceIfInvalid(version: string) { if (semverValid(version) === null) { // version coercion try { // find the semver version of an integer const coercedVersion = semverCoerce(version) if (coercedVersion !== null) { info(`Coerced version '${version}' to '${coercedVersion}'`) return coercedVersion.version } } catch (err) { // handled below } } return version } /** * Coerce the given version to a semver range if it is invalid */ export function semverCoercedRangeIfInvalid(version: string) { if (semverValid(version) === null) { // version coercion try { // find the semver version of an integer const coercedVersion = semverCoerce(version) if (coercedVersion !== null) { // if the versions doesn't specify a range specifier (e.g. ^, ~, >, <, etc.), add a ^ to the version const versionRange = /^[<=>^~]/.test(coercedVersion.version) ? coercedVersion.version : `^${coercedVersion.version}` info(`Coerced version '${version}' to '${versionRange}'`) return versionRange } } catch (err) { // handled below } } return version } export function removeVPrefix(version: string) { return Number.parseInt(version.replace(/^v/, ""), 10) } export function addVPrefix(version: string) { if (!version.match(/^v/)) { return `v${version}` } return version } export function compareVersion(tag1: string, tag2: string) { const v1 = semverCoerce(tag1) const v2 = semverCoerce(tag2) if (v1 !== null && v2 !== null) { // put the latest version first return v2.compare(v1) } // if the tags are not semver, compare them as strings, putting the latest tag first return tag2.localeCompare(tag1) }