Merge pull request #168 from aminya/notifier [skip ci]

This commit is contained in:
Amin Yahyaabadi 2023-05-25 00:40:11 -07:00 committed by GitHub
commit b706650c81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 835 additions and 735 deletions

View File

@ -7,4 +7,3 @@ stats.html
src/python/setup-python/ src/python/setup-python/
src/msvc/msvc-dev-cmd/ src/msvc/msvc-dev-cmd/
dev/cpp_vcpkg_project dev/cpp_vcpkg_project
package.json

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

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

View File

@ -1,12 +1,26 @@
module.exports = { /** @typedef {import("jest")} jestConfig */
const jestConfig = {
preset: "ts-jest/presets/js-with-ts-esm", preset: "ts-jest/presets/js-with-ts-esm",
extensionsToTreatAsEsm: [".ts"], extensionsToTreatAsEsm: [".ts"],
transformIgnorePatterns: [], // transform everything transformIgnorePatterns: [], // transform everything
testEnvironment: "node", testEnvironment: "node",
testMatch: ["**/*.test.ts"], testMatch: ["**/*.test.ts"],
testPathIgnorePatterns: ["<rootDir>/src/python/setup-python/"], testPathIgnorePatterns: ["<rootDir>/src/python/setup-python/"],
// tsconfig
transform: {
"^.+\\.tsx?$": [
"ts-jest",
/** @type {import("ts-jest")} */
{
importHelpers: true,
useESM: true,
},
],
},
// coverage // coverage
collectCoverageFrom: ["src/**/*.{ts,tsx}"], collectCoverageFrom: ["src/**/*.{ts,tsx}"],
coveragePathIgnorePatterns: ["assets", ".css.d.ts"], coveragePathIgnorePatterns: ["assets", ".css.d.ts"],
verbose: true, verbose: true,
} }
export default jestConfig

4
package-version.json Normal file
View File

@ -0,0 +1,4 @@
{
"name": "setup-cpp",
"version": "0.27.1"
}

View File

@ -31,7 +31,7 @@
"build.docker.arch": "pnpm build && docker build -f ./dev/docker/arch_node.dockerfile -t setup-cpp:arch .", "build.docker.arch": "pnpm build && docker build -f ./dev/docker/arch_node.dockerfile -t setup-cpp:arch .",
"build.docker.fedora": "pnpm build && docker build -f ./dev/docker/fedora_node.dockerfile -t setup-cpp:fedora .", "build.docker.fedora": "pnpm build && docker build -f ./dev/docker/fedora_node.dockerfile -t setup-cpp:fedora .",
"build.docker.ubuntu": "pnpm build && docker build -f ./dev/docker/ubuntu_node.dockerfile -t setup-cpp:ubuntu .", "build.docker.ubuntu": "pnpm build && docker build -f ./dev/docker/ubuntu_node.dockerfile -t setup-cpp:ubuntu .",
"build.parcel": "cross-env NODE_ENV=production parcel build && babel ./dist --out-dir dist --plugins @upleveled/babel-plugin-remove-node-prefix --compact --no-babelrc --source-maps true", "build.parcel": "cross-env NODE_ENV=production parcel build --detailed-report 10 && babel ./dist --out-dir dist --plugins @upleveled/babel-plugin-remove-node-prefix --compact --no-babelrc --source-maps true",
"bump": "ncu -u -x numerous && pnpm update", "bump": "ncu -u -x numerous && pnpm update",
"clean": "shx rm -rf .parcel-cache dist exe", "clean": "shx rm -rf .parcel-cache dist exe",
"copy.matchers": "shx cp ./src/gcc/gcc_matcher.json ./dist/node12/ && shx cp ./src/msvc/msvc_matcher.json ./dist/node12/ && shx cp ./src/python/python_matcher.json ./dist/node12/ && shx cp ./src/llvm/llvm_matcher.json ./dist/node12/ && shx cp ./dist/node12/*.json ./dist/node16/", "copy.matchers": "shx cp ./src/gcc/gcc_matcher.json ./dist/node12/ && shx cp ./src/msvc/msvc_matcher.json ./dist/node12/ && shx cp ./src/python/python_matcher.json ./dist/node12/ && shx cp ./src/llvm/llvm_matcher.json ./dist/node12/ && shx cp ./dist/node12/*.json ./dist/node16/",
@ -43,7 +43,7 @@
"lint.eslint": "eslint **/*.{ts,tsx,js,jsx,cjs,mjs,json,yaml} --no-error-on-unmatched-pattern --cache --cache-location ./.cache/eslint/ --fix", "lint.eslint": "eslint **/*.{ts,tsx,js,jsx,cjs,mjs,json,yaml} --no-error-on-unmatched-pattern --cache --cache-location ./.cache/eslint/ --fix",
"lint.prettier": "prettier --list-different --write .", "lint.prettier": "prettier --list-different --write .",
"lint.tsc": "tsc --noEmit", "lint.tsc": "tsc --noEmit",
"pack.exe": "shx rm -rf ./dist/tsconfig.tsbuildinfo && ts-node --esm ./dev/scripts/pack-exe.ts", "pack.exe": "shx rm -rf ./dist/tsconfig.tsbuildinfo && node ./dev/scripts/pack-exe.mjs",
"prepare": "pnpm run -r build && pnpm run -w build", "prepare": "pnpm run -r build && pnpm run -w build",
"start.docker": "docker run -t setup-cpp .", "start.docker": "docker run -t setup-cpp .",
"start.docker.arch": "docker run -t setup-cpp:arch .", "start.docker.arch": "docker run -t setup-cpp:arch .",
@ -59,6 +59,9 @@
"test.unit": "jest --runInBand" "test.unit": "jest --runInBand"
}, },
"prettier": "prettier-config-atomic", "prettier": "prettier-config-atomic",
"dependencies": {
"update-notifier": "^5.1.0"
},
"devDependencies": { "devDependencies": {
"@actions/core": "^1.10.0", "@actions/core": "^1.10.0",
"@actions/exec": "^1.1.1", "@actions/exec": "^1.1.1",
@ -90,6 +93,7 @@
"exec-powershell": "workspace:*", "exec-powershell": "workspace:*",
"execa": "^7.1.1", "execa": "^7.1.1",
"fast-glob": "^3.2.12", "fast-glob": "^3.2.12",
"find-up": "^6.3.0",
"gen-readme": "^1.6.0", "gen-readme": "^1.6.0",
"is-url-online": "^1.5.0", "is-url-online": "^1.5.0",
"jest": "^29.5.0", "jest": "^29.5.0",
@ -109,6 +113,7 @@
"semver": "7.5.1", "semver": "7.5.1",
"setup-python": "github:actions/setup-python#v4.6.1", "setup-python": "github:actions/setup-python#v4.6.1",
"shx": "0.3.4", "shx": "0.3.4",
"simple-update-notifier": "^1.1.0",
"terser-config-atomic": "^0.1.1", "terser-config-atomic": "^0.1.1",
"time-delta": "github:aminya/time-delta#69d91a41cef28e569be9a2991129f5f7d1f0d00e", "time-delta": "github:aminya/time-delta#69d91a41cef28e569be9a2991129f5f7d1f0d00e",
"ts-jest": "^29.1.0", "ts-jest": "^29.1.0",
@ -153,7 +158,9 @@
"engines": { "engines": {
"node": ">=12.x" "node": ">=12.x"
}, },
"includeNodeModules": true, "includeNodeModules": {
"update-notifier": false
},
"optimize": true, "optimize": true,
"outputFormat": "commonjs" "outputFormat": "commonjs"
}, },
@ -162,7 +169,9 @@
"engines": { "engines": {
"node": ">=16.x" "node": ">=16.x"
}, },
"includeNodeModules": true, "includeNodeModules": {
"update-notifier": false
},
"optimize": true, "optimize": true,
"outputFormat": "commonjs" "outputFormat": "commonjs"
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
import { syncVersions, getVersion } from "../versions/versions" import { syncVersions, getVersion } from "../versions/versions"
import { getCompilerInfo, Inputs, parseArgs } from "../main" import { parseArgs } from "../cli-options"
import { Inputs } from "../tool"
import { getCompilerInfo } from "../compilers"
jest.setTimeout(300000) jest.setTimeout(300000)
describe("getCompilerInfo", () => { describe("getCompilerInfo", () => {

12
src/check-updates.ts Normal file
View File

@ -0,0 +1,12 @@
import { warning } from "ci-log"
import updateNotifier from "simple-update-notifier"
import packageJson from "../package-version.json"
// auto self update notifier
export async function checkUpdates() {
try {
await updateNotifier({ pkg: packageJson })
} catch (err) {
warning(`Failed to check for updates: ${err instanceof Error ? err.message + err.stack : err}`)
}
}

86
src/cli-options.ts Normal file
View File

@ -0,0 +1,86 @@
import { getInput } from "@actions/core"
import { info } from "ci-log"
import mri from "mri"
import { InstallationInfo } from "./utils/setup/setupBin"
import { Inputs, inputs } from "./tool"
export function parseArgs(args: string[]): Opts {
return mri<Record<Inputs, string | undefined> & { help: boolean }>(args, {
string: inputs,
default: Object.fromEntries(inputs.map((inp) => [inp, maybeGetInput(inp)])),
alias: { h: "help" },
boolean: "help",
})
}
export function printHelp() {
info(`
setup-cpp [options]
setup-cpp --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
Install all the tools required for building and testing C++/C projects.
--architecture\t the cpu architecture to install the tools for. By default it uses the current CPU architecture.
--compiler\t the <compiler> to install.
\t You can specify the version instead of specifying just the name e.g: --compiler 'llvm-13.0.0'
--tool_name\t pass "true" or pass the <version> you would like to install for this tool. e.g. --conan true or --conan "1.42.1"
All the available tools:
--llvm
--gcc
--vcvarsall
--cmake
--ninja
--vcpkg
--bazel
--meson
--conan
--make
--task
--ccache
--sccache
--cppcheck
--clangformat
--clangtidy
--doxygen
--gcovr
--opencppcoverage
--kcov
--python
--choco
--brew
--nala
--sevenzip
--graphviz
--powershell
`)
}
/** Get an object from github actions */
export function maybeGetInput(key: string) {
const value = getInput(key.toLowerCase())
if (value !== "false" && value !== "") {
return value
}
return undefined // skip installation
}
export type Opts = mri.Argv<
Record<Inputs, string | undefined> & {
help: boolean
}
>
export function getSuccessMessage(tool: string, installationInfo: InstallationInfo | undefined | void) {
let msg = `${tool} was installed successfully:`
if (installationInfo === undefined) {
return msg
}
if ("installDir" in installationInfo) {
msg += `\n- The installation directory is ${installationInfo.installDir}`
}
if (installationInfo.binDir !== "") {
msg += `\n- The binary directory is ${installationInfo.binDir}`
}
return msg
}

114
src/compilers.ts Normal file
View File

@ -0,0 +1,114 @@
import { endGroup, notice, startGroup } from "@actions/core"
import { error, info } from "ci-log"
import { join } from "path"
import semverValid from "semver/functions/valid"
import { getSuccessMessage } from "./cli-options"
import { setupGcc } from "./gcc/gcc"
import { activateGcovGCC, activateGcovLLVM } from "./gcovr/gcovr"
import { setupLLVM } from "./llvm/llvm"
import { setupMSVC } from "./msvc/msvc"
import { addEnv } from "./utils/env/addEnv"
import { getVersion } from "./versions/versions"
/** Detecting the compiler version. Divide the given string by `-` and use the second element as the version */
export function getCompilerInfo(compilerAndVersion: string) {
const compilerAndMaybeVersion = compilerAndVersion.split("-")
const compiler = compilerAndMaybeVersion[0]
if (1 in compilerAndMaybeVersion) {
const maybeVersion = compilerAndMaybeVersion[1]
if (semverValid(maybeVersion) !== null) {
return { compiler, version: maybeVersion }
} else {
info(`Invalid semver version ${maybeVersion} used for the compiler.`)
return { compiler, version: maybeVersion }
}
}
return { compiler, version: undefined }
}
/** Installing the specified compiler */
export async function installCompiler(
compilerAndVersion: string,
osVersion: number[] | null,
setupCppDir: string,
arch: string,
successMessages: string[],
hasLLVM: boolean,
errorMessages: string[]
) {
try {
const { compiler, version } = getCompilerInfo(compilerAndVersion)
// install the compiler. We allow some aliases for the compiler name
startGroup(`Installing ${compiler} ${version ?? ""}`)
switch (compiler) {
case "llvm":
case "clang":
case "clang++": {
const installationInfo = await setupLLVM(
getVersion("llvm", version, osVersion),
join(setupCppDir, "llvm"),
arch
)
await activateGcovLLVM()
successMessages.push(getSuccessMessage("llvm", installationInfo))
break
}
case "gcc":
case "mingw":
case "cygwin":
case "msys": {
const gccVersion = getVersion("gcc", version, osVersion)
const installationInfo = await setupGcc(gccVersion, join(setupCppDir, "gcc"), arch)
if (hasLLVM) {
// remove back the added CPPFLAGS of LLVM that include the LLVM headers
await addEnv("CPPFLAGS", "")
}
await activateGcovGCC(gccVersion)
successMessages.push(getSuccessMessage("gcc", installationInfo))
break
}
case "cl":
case "msvc":
case "msbuild":
case "vs":
case "visualstudio":
case "visualcpp":
case "visualc++": {
const installationInfo = await setupMSVC(
getVersion("msvc", version, osVersion),
join(setupCppDir, "msvc"),
arch
)
if (hasLLVM) {
// remove the CPPFLAGS of LLVM that include the LLVM headers
await addEnv("CPPFLAGS", "")
}
successMessages.push(getSuccessMessage("msvc", installationInfo))
break
}
case "appleclang":
case "applellvm": {
notice("Assuming apple-clang is already installed")
await Promise.all([addEnv("CC", "clang"), addEnv("CXX", "clang++")])
successMessages.push(getSuccessMessage("apple-clang", undefined))
break
}
default: {
errorMessages.push(`Unsupported compiler ${compiler}`)
}
}
} catch (err) {
error(err as string | Error)
errorMessages.push(`Failed to install the ${compilerAndVersion}`)
}
endGroup()
}

View File

@ -1,95 +1,28 @@
#!/usr/bin/env node #!/usr/bin/env node
/* eslint-disable node/shebang */ /* eslint-disable node/shebang */
import { endGroup, getInput, notice, startGroup } from "@actions/core"
import { GITHUB_ACTIONS } from "ci-info" import { GITHUB_ACTIONS } from "ci-info"
import { error, info, success, warning } from "ci-log" import { error, info, success, warning } from "ci-log"
import mri from "mri"
import * as numerous from "numerous" import * as numerous from "numerous"
import numerousLocale from "numerous/locales/en.js" import numerousLocale from "numerous/locales/en.js"
import { join } from "patha"
import semverValid from "semver/functions/valid"
import * as timeDelta from "time-delta" import * as timeDelta from "time-delta"
import timeDeltaLocale from "time-delta/locales/en.js" import timeDeltaLocale from "time-delta/locales/en.js"
import { untildifyUser } from "untildify-user" import { untildifyUser } from "untildify-user"
import { checkUpdates } from "./check-updates"
import { setupBazel } from "./bazel/bazel" import { parseArgs, printHelp } from "./cli-options"
import { setupBrew } from "./brew/brew" import { installCompiler } from "./compilers"
import { setupCcache } from "./ccache/ccache" import { installTool, tools } from "./tool"
import { setupChocolatey } from "./chocolatey/chocolatey" import { finalizeCpprc } from "./utils/env/addEnv"
import { setupCmake } from "./cmake/cmake"
import { setupConan } from "./conan/conan"
import { setupCppcheck } from "./cppcheck/cppcheck"
import { setupDoxygen } from "./doxygen/doxygen"
import { setupGcc } from "./gcc/gcc"
import { activateGcovGCC, activateGcovLLVM, setupGcovr } from "./gcovr/gcovr"
import { setupGraphviz } from "./graphviz/graphviz"
import { setupKcov } from "./kcov/kcov"
import { setupClangTools, setupLLVM } from "./llvm/llvm"
import { setupMake } from "./make/make"
import { setupMeson } from "./meson/meson"
import { setupMSVC } from "./msvc/msvc"
import { setupNala } from "./nala/nala"
import { setupNinja } from "./ninja/ninja"
import { setupOpencppcoverage } from "./opencppcoverage/opencppcoverage"
import { setupPowershell } from "./powershell/powershell"
import { setupPython } from "./python/python"
import { setupSccache } from "./sccache/sccache"
import { setupSevenZip } from "./sevenzip/sevenzip"
import { setupTask } from "./task/task"
import { addEnv, finalizeCpprc } from "./utils/env/addEnv"
import { isArch } from "./utils/env/isArch" import { isArch } from "./utils/env/isArch"
import { ubuntuVersion } from "./utils/env/ubuntu_version" import { ubuntuVersion } from "./utils/env/ubuntu_version"
import { InstallationInfo } from "./utils/setup/setupBin"
import { setupPacmanPack } from "./utils/setup/setupPacmanPack" import { setupPacmanPack } from "./utils/setup/setupPacmanPack"
import { setupVcpkg } from "./vcpkg/vcpkg" import { syncVersions } from "./versions/versions"
import { setupVCVarsall } from "./vcvarsall/vcvarsall"
import { getVersion, syncVersions } from "./versions/versions"
/** The setup functions */
const setups = {
nala: setupNala,
cmake: setupCmake,
ninja: setupNinja,
python: setupPython,
vcpkg: setupVcpkg,
bazel: setupBazel,
conan: setupConan,
meson: setupMeson,
gcovr: setupGcovr,
opencppcoverage: setupOpencppcoverage,
llvm: setupLLVM,
gcc: setupGcc,
choco: setupChocolatey,
brew: setupBrew,
powershell: setupPowershell,
ccache: setupCcache,
sccache: setupSccache,
doxygen: setupDoxygen,
graphviz: setupGraphviz,
cppcheck: setupCppcheck,
clangtidy: setupClangTools,
clangformat: setupClangTools,
msvc: setupMSVC,
vcvarsall: setupVCVarsall,
kcov: setupKcov,
make: setupMake,
task: setupTask,
sevenzip: setupSevenZip,
}
/** The tools that can be installed */
const tools = Object.keys(setups) as Array<keyof typeof setups>
/** The possible inputs to the program */
export type Inputs = keyof typeof setups | "compiler" | "architecture"
// an array of possible inputs
const inputs: Array<Inputs> = ["compiler", "architecture", ...tools]
/** The main entry function */ /** The main entry function */
export async function main(args: string[]): Promise<number> { async function main(args: string[]): Promise<number> {
let checkUpdatePromise = Promise.resolve()
if (!GITHUB_ACTIONS) { if (!GITHUB_ACTIONS) {
checkUpdatePromise = checkUpdates()
process.env.ACTIONS_ALLOW_UNSECURE_COMMANDS = "true" process.env.ACTIONS_ALLOW_UNSECURE_COMMANDS = "true"
} }
@ -127,13 +60,14 @@ export async function main(args: string[]): Promise<number> {
return 1 return 1
} }
let hasLLVM = false // used to unset CPPFLAGS of LLVM when other compilers are used as the main compiler
if (isArch() && typeof opts.cppcheck === "string" && typeof opts.gcovr === "string") { if (isArch() && typeof opts.cppcheck === "string" && typeof opts.gcovr === "string") {
info("installing python-pygments to avoid conflicts with cppcheck and gcovr on Arch linux") info("installing python-pygments to avoid conflicts with cppcheck and gcovr on Arch linux")
await setupPacmanPack("python-pygments") await setupPacmanPack("python-pygments")
} }
/** Used to unset CPPFLAGS of LLVM when other compilers are used as the main compiler */
let hasLLVM = false
// loop over the tools and run their setup function // loop over the tools and run their setup function
for (const tool of tools) { for (const tool of tools) {
// get the version or "true" or undefined for this tool from the options // get the version or "true" or undefined for this tool from the options
@ -143,40 +77,8 @@ export async function main(args: string[]): Promise<number> {
if (version !== undefined) { if (version !== undefined) {
// running the setup function for this tool // running the setup function for this tool
time1 = Date.now() time1 = Date.now()
startGroup(`Installing ${tool} ${version}`) // eslint-disable-next-line no-await-in-loop
try { hasLLVM = await installTool(tool, version, osVersion, arch, setupCppDir, successMessages, errorMessages)
let installationInfo: InstallationInfo | undefined | void
if (tool === "vcvarsall") {
// eslint-disable-next-line no-await-in-loop
await setupVCVarsall(
getVersion(tool, version, osVersion),
undefined,
arch,
undefined,
undefined,
false,
false
)
} else {
// get the setup function
const setupFunction = setups[tool]
hasLLVM = ["llvm", "clangformat", "clangtidy"].includes(tool)
// the tool installation directory (for the functions that ue it)
const setupDir = join(setupCppDir, hasLLVM ? "llvm" : tool)
// eslint-disable-next-line no-await-in-loop
installationInfo = await setupFunction(getVersion(tool, version, osVersion), setupDir, arch)
}
// preparing a report string
successMessages.push(getSuccessMessage(tool, installationInfo))
} catch (e) {
// push error message to the logger
error(e as string | Error)
errorMessages.push(`${tool} failed to install`)
}
endGroup()
time2 = Date.now() time2 = Date.now()
info(`took ${timeFormatter.format(time1, time2) || "0 seconds"}`) info(`took ${timeFormatter.format(time1, time2) || "0 seconds"}`)
} }
@ -184,87 +86,11 @@ export async function main(args: string[]): Promise<number> {
// installing the specified compiler // installing the specified compiler
const maybeCompiler = opts.compiler const maybeCompiler = opts.compiler
time1 = Date.now() if (maybeCompiler !== undefined) {
try { const time1Compiler = Date.now()
if (maybeCompiler !== undefined) { await installCompiler(maybeCompiler, osVersion, setupCppDir, arch, successMessages, hasLLVM, errorMessages)
const { compiler, version } = getCompilerInfo(maybeCompiler) const time2Compiler = Date.now()
info(`took ${timeFormatter.format(time1Compiler, time2Compiler) || "0 seconds"}`)
// install the compiler. We allow some aliases for the compiler name
startGroup(`Installing ${compiler} ${version ?? ""}`)
switch (compiler) {
case "llvm":
case "clang":
case "clang++": {
const installationInfo = await setupLLVM(
getVersion("llvm", version, osVersion),
join(setupCppDir, "llvm"),
arch
)
await activateGcovLLVM()
successMessages.push(getSuccessMessage("llvm", installationInfo))
break
}
case "gcc":
case "mingw":
case "cygwin":
case "msys": {
const gccVersion = getVersion("gcc", version, osVersion)
const installationInfo = await setupGcc(gccVersion, join(setupCppDir, "gcc"), arch)
if (hasLLVM) {
// remove back the added CPPFLAGS of LLVM that include the LLVM headers
await addEnv("CPPFLAGS", "")
}
await activateGcovGCC(gccVersion)
successMessages.push(getSuccessMessage("gcc", installationInfo))
break
}
case "cl":
case "msvc":
case "msbuild":
case "vs":
case "visualstudio":
case "visualcpp":
case "visualc++": {
const installationInfo = await setupMSVC(
getVersion("msvc", version, osVersion),
join(setupCppDir, "msvc"),
arch
)
if (hasLLVM) {
// remove the CPPFLAGS of LLVM that include the LLVM headers
await addEnv("CPPFLAGS", "")
}
successMessages.push(getSuccessMessage("msvc", installationInfo))
break
}
case "appleclang":
case "applellvm": {
notice("Assuming apple-clang is already installed")
await Promise.all([addEnv("CC", "clang"), addEnv("CXX", "clang++")])
successMessages.push(getSuccessMessage("apple-clang", undefined))
break
}
default: {
errorMessages.push(`Unsupported compiler ${compiler}`)
}
}
endGroup()
time2 = Date.now()
info(`took ${timeFormatter.format(time1, time2) || "0 seconds"}`)
}
} catch (e) {
error(e as string | Error)
errorMessages.push(`Failed to install the ${maybeCompiler}`)
endGroup()
time2 = Date.now()
info(`took ${timeFormatter.format(time1, time2) || "0 seconds"}`)
} }
await finalizeCpprc() await finalizeCpprc()
@ -297,8 +123,11 @@ export async function main(args: string[]): Promise<number> {
} }
} }
await checkUpdatePromise
return errorMessages.length === 0 ? 0 : 1 // exit with non-zero if any error message return errorMessages.length === 0 ? 0 : 1 // exit with non-zero if any error message
} }
// Run main // Run main
main(process.argv) main(process.argv)
.then((ret) => { .then((ret) => {
@ -309,101 +138,3 @@ main(process.argv)
error(err as string | Error) error(err as string | Error)
process.exitCode = 1 process.exitCode = 1
}) })
export type Opts = mri.Argv<
Record<Inputs, string | undefined> & {
help: boolean
}
>
export function parseArgs(args: string[]): Opts {
return mri<Record<Inputs, string | undefined> & { help: boolean }>(args, {
string: inputs,
default: Object.fromEntries(inputs.map((inp) => [inp, maybeGetInput(inp)])),
alias: { h: "help" },
boolean: "help",
})
}
/** Detecting the compiler version. Divide the given string by `-` and use the second element as the version */
export function getCompilerInfo(maybeCompiler: string) {
const compilerAndMaybeVersion = maybeCompiler.split("-")
const compiler = compilerAndMaybeVersion[0]
if (1 in compilerAndMaybeVersion) {
const maybeVersion = compilerAndMaybeVersion[1]
if (semverValid(maybeVersion) !== null) {
return { compiler, version: maybeVersion }
} else {
info(`Invalid semver version ${maybeVersion} used for the compiler.`)
return { compiler, version: maybeVersion }
}
}
return { compiler, version: undefined }
}
function printHelp() {
info(`
setup-cpp [options]
setup-cpp --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
Install all the tools required for building and testing C++/C projects.
--architecture\t the cpu architecture to install the tools for. By default it uses the current CPU architecture.
--compiler\t the <compiler> to install.
\t You can specify the version instead of specifying just the name e.g: --compiler 'llvm-13.0.0'
--tool_name\t pass "true" or pass the <version> you would like to install for this tool. e.g. --conan true or --conan "1.42.1"
All the available tools:
--llvm
--gcc
--vcvarsall
--cmake
--ninja
--vcpkg
--bazel
--meson
--conan
--make
--task
--ccache
--sccache
--cppcheck
--clangformat
--clangtidy
--doxygen
--gcovr
--opencppcoverage
--kcov
--python
--choco
--brew
--nala
--sevenzip
--graphviz
--powershell
`)
}
/** Get an object from github actions */
function maybeGetInput(key: string) {
const value = getInput(key.toLowerCase())
if (value !== "false" && value !== "") {
return value
}
return undefined // skip installation
}
function getSuccessMessage(tool: string, installationInfo: InstallationInfo | undefined | void) {
let msg = `${tool} was installed successfully:`
if (installationInfo === undefined) {
return msg
}
if ("installDir" in installationInfo) {
msg += `\n- The installation directory is ${installationInfo.installDir}`
}
if (installationInfo.binDir !== "") {
msg += `\n- The binary directory is ${installationInfo.binDir}`
}
return msg
}

113
src/tool.ts Normal file
View File

@ -0,0 +1,113 @@
import { endGroup, startGroup } from "@actions/core"
import { error } from "ci-log"
import { join } from "patha"
import { setupBazel } from "./bazel/bazel"
import { setupBrew } from "./brew/brew"
import { setupCcache } from "./ccache/ccache"
import { setupChocolatey } from "./chocolatey/chocolatey"
import { getSuccessMessage } from "./cli-options"
import { setupCmake } from "./cmake/cmake"
import { setupConan } from "./conan/conan"
import { setupCppcheck } from "./cppcheck/cppcheck"
import { setupDoxygen } from "./doxygen/doxygen"
import { setupGcc } from "./gcc/gcc"
import { setupGcovr } from "./gcovr/gcovr"
import { setupGraphviz } from "./graphviz/graphviz"
import { setupKcov } from "./kcov/kcov"
import { setupClangTools, setupLLVM } from "./llvm/llvm"
import { setupMake } from "./make/make"
import { setupMeson } from "./meson/meson"
import { setupMSVC } from "./msvc/msvc"
import { setupNala } from "./nala/nala"
import { setupNinja } from "./ninja/ninja"
import { setupOpencppcoverage } from "./opencppcoverage/opencppcoverage"
import { setupPowershell } from "./powershell/powershell"
import { setupPython } from "./python/python"
import { setupSccache } from "./sccache/sccache"
import { setupSevenZip } from "./sevenzip/sevenzip"
import { setupTask } from "./task/task"
import { InstallationInfo } from "./utils/setup/setupBin"
import { setupVcpkg } from "./vcpkg/vcpkg"
import { setupVCVarsall } from "./vcvarsall/vcvarsall"
import { getVersion } from "./versions/versions"
export async function installTool(
tool: ToolName,
version: string,
osVersion: number[] | null,
arch: string,
setupCppDir: string,
successMessages: string[],
errorMessages: string[]
) {
startGroup(`Installing ${tool} ${version}`)
let hasLLVM = false
try {
let installationInfo: InstallationInfo | undefined | void
if (tool === "vcvarsall") {
// eslint-disable-next-line no-await-in-loop
await setupVCVarsall(getVersion(tool, version, osVersion), undefined, arch, undefined, undefined, false, false)
} else {
// get the setup function
const setupFunction = setups[tool]
hasLLVM = ["llvm", "clangformat", "clangtidy"].includes(tool)
// the tool installation directory (for the functions that ue it)
const setupDir = join(setupCppDir, hasLLVM ? "llvm" : tool)
// eslint-disable-next-line no-await-in-loop
installationInfo = await setupFunction(getVersion(tool, version, osVersion), setupDir, arch)
}
// preparing a report string
successMessages.push(getSuccessMessage(tool, installationInfo))
} catch (e) {
// push error message to the logger
error(e as string | Error)
errorMessages.push(`${tool} failed to install`)
}
endGroup()
return hasLLVM
} /** The setup functions */
export const setups = {
nala: setupNala,
cmake: setupCmake,
ninja: setupNinja,
python: setupPython,
vcpkg: setupVcpkg,
bazel: setupBazel,
conan: setupConan,
meson: setupMeson,
gcovr: setupGcovr,
opencppcoverage: setupOpencppcoverage,
llvm: setupLLVM,
gcc: setupGcc,
choco: setupChocolatey,
brew: setupBrew,
powershell: setupPowershell,
ccache: setupCcache,
sccache: setupSccache,
doxygen: setupDoxygen,
graphviz: setupGraphviz,
cppcheck: setupCppcheck,
clangtidy: setupClangTools,
clangformat: setupClangTools,
msvc: setupMSVC,
vcvarsall: setupVCVarsall,
kcov: setupKcov,
make: setupMake,
task: setupTask,
sevenzip: setupSevenZip,
}
export type ToolName = keyof typeof setups
/** The tools that can be installed */
export const tools = Object.keys(setups) as Array<ToolName>
/** The possible inputs to the program */
export type Inputs = keyof typeof setups | "compiler" | "architecture"
/** an array of possible inputs */
export const inputs: Array<Inputs> = ["compiler", "architecture", ...tools]

View File

@ -1,4 +1,5 @@
import { Inputs, Opts } from "../main" import { Opts } from "../cli-options"
import { Inputs } from "../tool"
import { DefaultLinuxVersion, DefaultVersions } from "./default_versions" import { DefaultLinuxVersion, DefaultVersions } from "./default_versions"
/** Get the default version if passed true or undefined, otherwise return the version itself */ /** Get the default version if passed true or undefined, otherwise return the version itself */

View File

@ -18,11 +18,11 @@
"removeComments": false, "removeComments": false,
"skipLibCheck": true, "skipLibCheck": true,
"lib": ["ES2020", "dom"], "lib": ["ES2020", "dom"],
"target": "ES2020", "target": "ESNext",
"allowJs": true, "allowJs": true,
"esModuleInterop": true, "esModuleInterop": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"module": "esnext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",
"importHelpers": false, "importHelpers": false,
"outDir": "./dist" "outDir": "./dist"