mirror of https://github.com/aminya/setup-cpp
Merge branch 'master' into pr/164
This commit is contained in:
commit
f7f2d14ebb
|
@ -1,4 +1,16 @@
|
||||||
{
|
{
|
||||||
"extends": "eslint-config-atomic",
|
"extends": "eslint-config-atomic",
|
||||||
"ignorePatterns": ["dist/", "node_modules/", "dev/cpp_vcpkg_project"]
|
"ignorePatterns": ["dist/", "node_modules/", "dev/cpp_vcpkg_project"],
|
||||||
|
"rules": {
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
"argsIgnorePattern": "^_",
|
||||||
|
"varsIgnorePattern": "^_",
|
||||||
|
"caughtErrorsIgnorePattern": "^_",
|
||||||
|
"destructuredArrayIgnorePattern": "^_"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
22
.terserrc.js
22
.terserrc.js
|
@ -1,22 +0,0 @@
|
||||||
const terserConfig = require("terser-config-atomic")
|
|
||||||
|
|
||||||
const compress =
|
|
||||||
typeof terserConfig.compress !== "boolean"
|
|
||||||
? {
|
|
||||||
...terserConfig.compress,
|
|
||||||
global_defs: {
|
|
||||||
...terserConfig.compress.global_defs,
|
|
||||||
"process.env.NODE_DEBUG": false,
|
|
||||||
"process.env.RUNNER_DEBUG": "0",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: terserConfig.compress
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
...terserConfig,
|
|
||||||
compress,
|
|
||||||
format: {
|
|
||||||
...terserConfig.format,
|
|
||||||
comments: false,
|
|
||||||
},
|
|
||||||
}
|
|
28
README.md
28
README.md
|
@ -24,7 +24,7 @@ Setting up a **cross-platform** environment for building and testing C++/C proje
|
||||||
| coverage | gcovr, opencppcoverage, kcov |
|
| coverage | gcovr, opencppcoverage, kcov |
|
||||||
| other | python, powershell, sevenzip |
|
| other | python, powershell, sevenzip |
|
||||||
|
|
||||||
`setup-cpp` automatically installs the dependencies above tools if needed for the selected tool (e.g., `python` is required for `conan`).
|
`setup-cpp` automatically handles the dependencies of the selected tool (e.g., `python` is required for `conan`).
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
@ -32,24 +32,18 @@ Setting up a **cross-platform** environment for building and testing C++/C proje
|
||||||
|
|
||||||
#### With npm and Nodejs
|
#### With npm and Nodejs
|
||||||
|
|
||||||
Install setup-cpp with npm:
|
Run `setup-cpp` with the available options.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
npm install -g setup-cpp
|
# Windows example (open PowerShell as admin)
|
||||||
```
|
npx setup-cpp --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
|
||||||
|
|
||||||
Then run `setup-cpp` with the available options.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# windows example (open PowerShell as admin)
|
|
||||||
setup-cpp --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
|
|
||||||
|
|
||||||
RefreshEnv.cmd # activate the environment
|
RefreshEnv.cmd # activate the environment
|
||||||
```
|
```
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# linux/macos example
|
# Linux/Macos example
|
||||||
sudo setup-cpp --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
|
sudo npx setup-cpp --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
|
||||||
|
|
||||||
source ~/.cpprc
|
source ~/.cpprc
|
||||||
```
|
```
|
||||||
|
@ -62,13 +56,13 @@ NOTE: On Unix systems, if you are already a root user (e.g., in a GitLab runner
|
||||||
|
|
||||||
#### With executable
|
#### With executable
|
||||||
|
|
||||||
Download the executable for your platform from [here](https://github.com/aminya/setup-cpp/releases/tag/v0.26.2), and run it with the available options. You can also automate downloading using `wget`, `curl`, or other similar tools.
|
Download the executable for your platform from [here](https://github.com/aminya/setup-cpp/releases/tag/v0.30.1), and run it with the available options. You can also automate downloading using `wget`, `curl`, or other similar tools.
|
||||||
|
|
||||||
An example that installs llvm, cmake, ninja, ccache, and vcpkg:
|
An example that installs llvm, cmake, ninja, ccache, and vcpkg:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# windows example (open PowerShell as admin)
|
# windows example (open PowerShell as admin)
|
||||||
curl -LJO "https://github.com/aminya/setup-cpp/releases/download/v0.26.2/setup-cpp-x64-windows.exe"
|
curl -LJO "https://github.com/aminya/setup-cpp/releases/download/v0.30.1/setup-cpp-x64-windows.exe"
|
||||||
./setup-cpp-x64-windows --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
|
./setup-cpp-x64-windows --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
|
||||||
|
|
||||||
RefreshEnv.cmd # activate cpp environment variables
|
RefreshEnv.cmd # activate cpp environment variables
|
||||||
|
@ -76,7 +70,7 @@ RefreshEnv.cmd # activate cpp environment variables
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# linux example
|
# linux example
|
||||||
wget "https://github.com/aminya/setup-cpp/releases/download/v0.26.2/setup-cpp-x64-linux"
|
wget "https://github.com/aminya/setup-cpp/releases/download/v0.30.1/setup-cpp-x64-linux"
|
||||||
chmod +x ./setup-cpp-x64-linux
|
chmod +x ./setup-cpp-x64-linux
|
||||||
sudo ./setup-cpp-x64-linux --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
|
sudo ./setup-cpp-x64-linux --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
|
||||||
|
|
||||||
|
@ -85,7 +79,7 @@ source ~/.cpprc # activate cpp environment variables
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# macos example
|
# macos example
|
||||||
wget "https://github.com/aminya/setup-cpp/releases/download/v0.26.2/setup-cpp-x64-macos"
|
wget "https://github.com/aminya/setup-cpp/releases/download/v0.30.1/setup-cpp-x64-macos"
|
||||||
chmod +x ./setup-cpp-x64-macos
|
chmod +x ./setup-cpp-x64-macos
|
||||||
sudo ./setup-cpp-x64-macos --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
|
sudo ./setup-cpp-x64-macos --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
|
||||||
|
|
||||||
|
@ -255,7 +249,7 @@ stages:
|
||||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1E9377A2BA9EF27F
|
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1E9377A2BA9EF27F
|
||||||
|
|
||||||
.setup-cpp: &setup-cpp |
|
.setup-cpp: &setup-cpp |
|
||||||
curl -LJO "https://github.com/aminya/setup-cpp/releases/download/v0.26.2/setup-cpp-x64-linux"
|
curl -LJO "https://github.com/aminya/setup-cpp/releases/download/v0.30.1/setup-cpp-x64-linux"
|
||||||
chmod +x setup-cpp-x64-linux
|
chmod +x setup-cpp-x64-linux
|
||||||
./setup-cpp-x64-linux --compiler $compiler --cmake true --ninja true --ccache true --vcpkg true
|
./setup-cpp-x64-linux --compiler $compiler --cmake true --ninja true --ccache true --vcpkg true
|
||||||
source ~/.cpprc
|
source ~/.cpprc
|
||||||
|
|
|
@ -11,6 +11,10 @@ ignorePaths:
|
||||||
- "**/node_modules/"
|
- "**/node_modules/"
|
||||||
words:
|
words:
|
||||||
- aarch
|
- aarch
|
||||||
|
- clangd
|
||||||
|
- Trofimovich
|
||||||
|
- cobertura
|
||||||
|
- whatwg
|
||||||
- aminya
|
- aminya
|
||||||
- applellvm
|
- applellvm
|
||||||
- bazel
|
- bazel
|
||||||
|
|
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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "setup-cpp",
|
||||||
|
"version": "0.30.1"
|
||||||
|
}
|
65
package.json
65
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "setup-cpp",
|
"name": "setup-cpp",
|
||||||
"version": "0.26.2",
|
"version": "0.30.1",
|
||||||
"description": "Install all the tools required for building and testing C++/C projects.",
|
"description": "Install all the tools required for building and testing C++/C projects.",
|
||||||
"repository": "https://github.com/aminya/setup-cpp",
|
"repository": "https://github.com/aminya/setup-cpp",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
@ -9,19 +9,26 @@
|
||||||
"import": "./dist/node16/setup-cpp.mjs",
|
"import": "./dist/node16/setup-cpp.mjs",
|
||||||
"require": "./dist/node16/setup-cpp.js"
|
"require": "./dist/node16/setup-cpp.js"
|
||||||
},
|
},
|
||||||
|
"main": "dist/node16/setup-cpp.js",
|
||||||
|
"main.legacy": "./dist/node12/setup-cpp.js",
|
||||||
|
"main.actions": "./dist/node18/setup-cpp.js",
|
||||||
"source": "./src/main.ts",
|
"source": "./src/main.ts",
|
||||||
"bin": {
|
"bin": {
|
||||||
"setup-cpp": "./dist/node16/setup-cpp.js"
|
"setup-cpp": "dist/node16/setup-cpp.js"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"action.yml",
|
||||||
|
".dockerignore",
|
||||||
"dist",
|
"dist",
|
||||||
"src",
|
"src",
|
||||||
"packages",
|
"packages",
|
||||||
"dev",
|
"dev/docker",
|
||||||
|
"dev/container-tests",
|
||||||
"README.md",
|
"README.md",
|
||||||
"LICENSE.txt",
|
"LICENSE.txt",
|
||||||
"LICENSE.dependencies.txt",
|
"LICENSE.dependencies.txt",
|
||||||
"package.json",
|
"package.json",
|
||||||
|
"package-version.json",
|
||||||
"tsconfig.json"
|
"tsconfig.json"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -45,8 +52,8 @@
|
||||||
"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 && rm ./dist/tsconfig.tsbuildinfo",
|
||||||
"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 .",
|
||||||
"start.docker.fedora": "docker run -t setup-cpp:fedora .",
|
"start.docker.fedora": "docker run -t setup-cpp:fedora .",
|
||||||
|
@ -66,15 +73,15 @@
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/io": "^1.1.3",
|
"@actions/io": "^1.1.3",
|
||||||
"@actions/tool-cache": "^2.0.1",
|
"@actions/tool-cache": "^2.0.1",
|
||||||
"@babel/cli": "^7.21.0",
|
"@babel/cli": "^7.22.5",
|
||||||
"@types/cross-spawn": "^6.0.2",
|
"@types/cross-spawn": "^6.0.2",
|
||||||
"@types/eslint": "^8.37.0",
|
"@types/eslint": "^8.40.2",
|
||||||
"@types/jest": "^29.5.1",
|
"@types/jest": "^29.5.2",
|
||||||
"@types/mri": "^1.1.1",
|
"@types/mri": "^1.1.1",
|
||||||
"@types/node": "^18.16.0",
|
"@types/node": "^20.3.2",
|
||||||
"@types/npmcli__ci-detect": "^2.0.0",
|
"@types/npmcli__ci-detect": "^2.0.0",
|
||||||
"@types/prettier": "2.7.2",
|
"@types/prettier": "2.7.3",
|
||||||
"@types/semver": "^7.3.13",
|
"@types/semver": "^7.5.0",
|
||||||
"@types/which": "^3.0.0",
|
"@types/which": "^3.0.0",
|
||||||
"@upleveled/babel-plugin-remove-node-prefix": "github:aminya/babel-plugin-remove-node-prefix#95fcbd92405b99a6eece48c493548996f12e6519",
|
"@upleveled/babel-plugin-remove-node-prefix": "github:aminya/babel-plugin-remove-node-prefix#95fcbd92405b99a6eece48c493548996f12e6519",
|
||||||
"admina": "^0.1.3",
|
"admina": "^0.1.3",
|
||||||
|
@ -87,20 +94,22 @@
|
||||||
"escape-path-with-spaces": "^1.0.2",
|
"escape-path-with-spaces": "^1.0.2",
|
||||||
"escape-quotes": "^1.0.2",
|
"escape-quotes": "^1.0.2",
|
||||||
"escape-string-regexp": "^5.0.0",
|
"escape-string-regexp": "^5.0.0",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.43.0",
|
||||||
"eslint-config-atomic": "^1.18.3",
|
"eslint-config-atomic": "^1.19.3",
|
||||||
"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",
|
||||||
|
"micro-memoize": "^4.1.2",
|
||||||
"mri": "^1.2.0",
|
"mri": "^1.2.0",
|
||||||
"msvc-dev-cmd": "github:aminya/msvc-dev-cmd#9f672c1",
|
"msvc-dev-cmd": "github:aminya/msvc-dev-cmd#9f672c1",
|
||||||
"npm-check-updates": "^16.10.9",
|
"npm-check-updates": "^16.10.13",
|
||||||
"npm-run-all2": "^6.0.5",
|
"npm-run-all2": "^6.0.5",
|
||||||
"numerous": "1.0.3",
|
"numerous": "1.0.3",
|
||||||
"parcel": "2.8.3",
|
"parcel": "2.9.3",
|
||||||
"path-exists": "^5.0.0",
|
"path-exists": "^5.0.0",
|
||||||
"patha": "^0.4.1",
|
"patha": "^0.4.1",
|
||||||
"prettier": "2.8.8",
|
"prettier": "2.8.8",
|
||||||
|
@ -108,19 +117,19 @@
|
||||||
"quote-unquote": "^1.0.0",
|
"quote-unquote": "^1.0.0",
|
||||||
"readme-md-generator": "^1.0.0",
|
"readme-md-generator": "^1.0.0",
|
||||||
"retry-as-promised": "^7.0.4",
|
"retry-as-promised": "^7.0.4",
|
||||||
"semver": "7.5.0",
|
"semver": "7.5.3",
|
||||||
"setup-python": "github:actions/setup-python#v4.6.0",
|
"setup-python": "github:actions/setup-python#v4.6.1",
|
||||||
"shx": "0.3.4",
|
"shx": "0.3.4",
|
||||||
"terser-config-atomic": "^0.1.1",
|
"simple-update-notifier": "^2.0.0",
|
||||||
"time-delta": "github:aminya/time-delta#69d91a41cef28e569be9a2991129f5f7d1f0d00e",
|
"time-delta": "github:aminya/time-delta#69d91a41cef28e569be9a2991129f5f7d1f0d00e",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"ts-readme": "^1.1.3",
|
"ts-readme": "^1.1.3",
|
||||||
"typescript": "^5.0.4",
|
"typescript": "^5.1.5",
|
||||||
"ubuntu-version": "^2.0.0",
|
"ubuntu-version": "^2.0.0",
|
||||||
"untildify-user": "workspace:*",
|
"untildify-user": "workspace:*",
|
||||||
"user-access": "workspace:*",
|
"user-access": "workspace:*",
|
||||||
"which": "^3.0.0"
|
"which": "^3.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.x"
|
"node": ">=12.x"
|
||||||
|
@ -148,16 +157,20 @@
|
||||||
"electron": false,
|
"electron": false,
|
||||||
"patha": "patha/dist/index.node.mjs"
|
"patha": "patha/dist/index.node.mjs"
|
||||||
},
|
},
|
||||||
"main": "./dist/node16/setup-cpp.js",
|
"pnpm": {
|
||||||
"main.legacy": "./dist/node12/setup-cpp.js",
|
"overrides": {
|
||||||
"main.actions": "./dist/node18/setup-cpp.js",
|
"whatwg-url": "^12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"targets": {
|
"targets": {
|
||||||
"main.legacy": {
|
"main.legacy": {
|
||||||
"context": "node",
|
"context": "node",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.x"
|
"node": ">=12.x"
|
||||||
},
|
},
|
||||||
"includeNodeModules": true,
|
"includeNodeModules": {
|
||||||
|
"update-notifier": false
|
||||||
|
},
|
||||||
"optimize": true,
|
"optimize": true,
|
||||||
"outputFormat": "commonjs"
|
"outputFormat": "commonjs"
|
||||||
},
|
},
|
||||||
|
@ -166,7 +179,9 @@
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.x"
|
"node": ">=16.x"
|
||||||
},
|
},
|
||||||
"includeNodeModules": true,
|
"includeNodeModules": {
|
||||||
|
"update-notifier": false
|
||||||
|
},
|
||||||
"optimize": true,
|
"optimize": true,
|
||||||
"outputFormat": "commonjs"
|
"outputFormat": "commonjs"
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.9.1",
|
"@actions/core": "^1.9.1",
|
||||||
"@npmcli/ci-detect": "github:aminya/ci-detect#37fe40075bebec96794ba0a7c4a6d5c70cbea00d"
|
"ci-info": "^3.8.0"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"log",
|
"log",
|
||||||
|
|
3602
pnpm-lock.yaml
3602
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -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", () => {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { mkdirP } from "@actions/io"
|
||||||
import { readFileSync } from "fs"
|
import { readFileSync } from "fs"
|
||||||
import { addPath } from "../utils/env/addEnv"
|
import { addPath } from "../utils/env/addEnv"
|
||||||
|
|
||||||
|
/* eslint-disable require-atomic-updates */
|
||||||
let binDir: string | undefined
|
let binDir: string | undefined
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
|
|
@ -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}`)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
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:
|
||||||
|
`)
|
||||||
|
|
||||||
|
console.table(
|
||||||
|
{
|
||||||
|
"compiler and analyzer": { tools: `--llvm, --gcc, --msvc, --vcvarsall, --cppcheck, --clangtidy, --clangformat` },
|
||||||
|
"build system": { tools: `--cmake, --ninja, --meson, --make, --task, --bazel` },
|
||||||
|
"package manager": { tools: `--vcpkg, --conan, --choco, --brew, --nala` },
|
||||||
|
cache: { tools: `--cppcache, --sccache` },
|
||||||
|
documentation: { tools: `--doxygen, --graphviz` },
|
||||||
|
coverage: { tools: `--gcovr, --opencppcoverage, --kcov` },
|
||||||
|
other: { tools: `--python, --powershell, --sevenzip` },
|
||||||
|
},
|
||||||
|
["tools"]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/** 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
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import { setupDnfPack } from "../utils/setup/setupDnfPack"
|
||||||
import { isUbuntu } from "../utils/env/isUbuntu"
|
import { isUbuntu } from "../utils/env/isUbuntu"
|
||||||
import { pathExists } from "path-exists"
|
import { pathExists } from "path-exists"
|
||||||
import retry from "retry-as-promised"
|
import retry from "retry-as-promised"
|
||||||
|
import { ubuntuVersion } from "../utils/env/ubuntu_version"
|
||||||
|
|
||||||
/** Get the platform data for cmake */
|
/** Get the platform data for cmake */
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
@ -70,7 +71,7 @@ export async function setupDoxygen(version: string, setupDir: string, arch: stri
|
||||||
let installationInfo: InstallationInfo
|
let installationInfo: InstallationInfo
|
||||||
if (version === "" || isArch() || hasDnf()) {
|
if (version === "" || isArch() || hasDnf()) {
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
installationInfo = setupPacmanPack("doxygen", version)
|
installationInfo = await setupPacmanPack("doxygen", version)
|
||||||
} else if (hasDnf()) {
|
} else if (hasDnf()) {
|
||||||
return setupDnfPack("doxygen", version)
|
return setupDnfPack("doxygen", version)
|
||||||
} else if (isUbuntu()) {
|
} else if (isUbuntu()) {
|
||||||
|
@ -90,7 +91,7 @@ export async function setupDoxygen(version: string, setupDir: string, arch: stri
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Unsupported linux distributions`)
|
throw new Error(`Unsupported linux distributions`)
|
||||||
}
|
}
|
||||||
await setupGraphviz(getVersion("graphviz", undefined), "", arch)
|
await setupGraphviz(getVersion("graphviz", undefined, await ubuntuVersion()), "", arch)
|
||||||
return installationInfo
|
return installationInfo
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { isUbuntu } from "../utils/env/isUbuntu"
|
||||||
import { hasDnf } from "../utils/env/hasDnf"
|
import { hasDnf } from "../utils/env/hasDnf"
|
||||||
import { setupDnfPack } from "../utils/setup/setupDnfPack"
|
import { setupDnfPack } from "../utils/setup/setupDnfPack"
|
||||||
import { pathExists } from "path-exists"
|
import { pathExists } from "path-exists"
|
||||||
|
import { ExecaReturnValue } from "execa"
|
||||||
|
|
||||||
interface MingwInfo {
|
interface MingwInfo {
|
||||||
releaseName: string
|
releaseName: string
|
||||||
|
@ -25,7 +26,12 @@ interface MingwInfo {
|
||||||
|
|
||||||
// https://github.com/brechtsanders/winlibs_mingw/releases
|
// https://github.com/brechtsanders/winlibs_mingw/releases
|
||||||
const GccToMingwInfo = {
|
const GccToMingwInfo = {
|
||||||
"12": { releaseName: "12.2.0-14.0.6-10.0.0-ucrt-r2", fileSuffix: "12.2.0-mingw-w64ucrt-10.0.0-r2" },
|
"13": { releaseName: "13.1.0posix-16.0.3-11.0.0-ucrt-r1", fileSuffix: "13.1.0-mingw-w64ucrt-11.0.0-r1" },
|
||||||
|
"13.1-ucrt": { releaseName: "13.1.0posix-16.0.3-11.0.0-ucrt-r1", fileSuffix: "13.1.0-mingw-w64ucrt-11.0.0-r1" },
|
||||||
|
"13.1-msvcrt": { releaseName: "13.1.0posix-16.0.3-11.0.0-msvcrt-r1", fileSuffix: "13.1.0-mingw-w64msvcrt-11.0.0-r1" },
|
||||||
|
"12": { releaseName: "12.3.0-16.0.4-11.0.0-ucrt-r1", fileSuffix: "12.3.0-mingw-w64ucrt-11.0.0-r1" },
|
||||||
|
"12.3.0-ucrt": { releaseName: "12.3.0-16.0.4-11.0.0-ucrt-r1", fileSuffix: "12.3.0-mingw-w64ucrt-11.0.0-r1" },
|
||||||
|
"12.3.0-msvcrt": { releaseName: "12.3.0-16.0.4-11.0.0-msvcrt-r1", fileSuffix: "12.3.0-mingw-w64msvcrt-11.0.0-r1" },
|
||||||
"12.2.0-ucrt": { releaseName: "12.2.0-14.0.6-10.0.0-ucrt-r2", fileSuffix: "12.2.0-mingw-w64ucrt-10.0.0-r2" },
|
"12.2.0-ucrt": { releaseName: "12.2.0-14.0.6-10.0.0-ucrt-r2", fileSuffix: "12.2.0-mingw-w64ucrt-10.0.0-r2" },
|
||||||
"12.2.0-msvcrt": { releaseName: "12.2.0-14.0.6-10.0.0-msvcrt-r2", fileSuffix: "12.2.0-mingw-w64msvcrt-10.0.0-r2" },
|
"12.2.0-msvcrt": { releaseName: "12.2.0-14.0.6-10.0.0-msvcrt-r2", fileSuffix: "12.2.0-mingw-w64msvcrt-10.0.0-r2" },
|
||||||
"12.1.0-ucrt": { releaseName: "12.1.0-14.0.4-10.0.0-ucrt-r2", fileSuffix: "12.1.0-mingw-w64ucrt-10.0.0-r2" },
|
"12.1.0-ucrt": { releaseName: "12.1.0-14.0.4-10.0.0-ucrt-r2", fileSuffix: "12.1.0-mingw-w64ucrt-10.0.0-r2" },
|
||||||
|
@ -90,7 +96,7 @@ export async function setupGcc(version: string, setupDir: string, arch: string)
|
||||||
case "linux": {
|
case "linux": {
|
||||||
if (arch === "x64") {
|
if (arch === "x64") {
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
installationInfo = setupPacmanPack("gcc", version)
|
installationInfo = await setupPacmanPack("gcc", version)
|
||||||
} else if (hasDnf()) {
|
} else if (hasDnf()) {
|
||||||
installationInfo = setupDnfPack("gcc", version)
|
installationInfo = setupDnfPack("gcc", version)
|
||||||
setupDnfPack("gcc-c++", version)
|
setupDnfPack("gcc-c++", version)
|
||||||
|
@ -104,7 +110,7 @@ export async function setupGcc(version: string, setupDir: string, arch: string)
|
||||||
} else {
|
} else {
|
||||||
info(`Install g++-multilib because gcc for ${arch} was requested`)
|
info(`Install g++-multilib because gcc for ${arch} was requested`)
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
setupPacmanPack("gcc-multilib", version)
|
await setupPacmanPack("gcc-multilib", version)
|
||||||
} else if (isUbuntu()) {
|
} else if (isUbuntu()) {
|
||||||
await setupAptPack([{ name: "gcc-multilib", version, repositories: ["ppa:ubuntu-toolchain-r/test"] }])
|
await setupAptPack([{ name: "gcc-multilib", version, repositories: ["ppa:ubuntu-toolchain-r/test"] }])
|
||||||
}
|
}
|
||||||
|
@ -152,7 +158,7 @@ async function setupChocoMingw(version: string, arch: string): Promise<Installat
|
||||||
}
|
}
|
||||||
|
|
||||||
async function activateGcc(version: string, binDir: string) {
|
async function activateGcc(version: string, binDir: string) {
|
||||||
const promises: Promise<any>[] = []
|
const promises: Promise<void | ExecaReturnValue<string>>[] = []
|
||||||
// Setup gcc as the compiler
|
// Setup gcc as the compiler
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { setupGraphviz } from "../graphviz"
|
||||||
import { cleanupTmpDir, setupTmpDir, testBin } from "../../utils/tests/test-helpers"
|
import { cleanupTmpDir, setupTmpDir, testBin } from "../../utils/tests/test-helpers"
|
||||||
import { InstallationInfo } from "../../utils/setup/setupBin"
|
import { InstallationInfo } from "../../utils/setup/setupBin"
|
||||||
import { getVersion } from "../../versions/versions"
|
import { getVersion } from "../../versions/versions"
|
||||||
|
import { ubuntuVersion } from "../../utils/env/ubuntu_version"
|
||||||
|
|
||||||
jest.setTimeout(300000)
|
jest.setTimeout(300000)
|
||||||
describe("setup-graphviz", () => {
|
describe("setup-graphviz", () => {
|
||||||
|
@ -11,7 +12,11 @@ describe("setup-graphviz", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should setup graphviz", async () => {
|
it("should setup graphviz", async () => {
|
||||||
const installInfo = await setupGraphviz(getVersion("graphviz", undefined), directory, process.arch)
|
const installInfo = await setupGraphviz(
|
||||||
|
getVersion("graphviz", undefined, await ubuntuVersion()),
|
||||||
|
directory,
|
||||||
|
process.arch
|
||||||
|
)
|
||||||
|
|
||||||
await testBin("dot", ["-V"], (installInfo as InstallationInfo | undefined)?.binDir)
|
await testBin("dot", ["-V"], (installInfo as InstallationInfo | undefined)?.binDir)
|
||||||
})
|
})
|
||||||
|
|
|
@ -11,6 +11,18 @@ describe("setup-Kcov", () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it("should build and setup kcov-41", async () => {
|
||||||
|
const directory = await setupTmpDir("kcov-v41")
|
||||||
|
const { binDir } = (await setupKcov("41", directory, "")) as InstallationInfo
|
||||||
|
// the prebuild binary only works on ubuntu 20.04
|
||||||
|
try {
|
||||||
|
await testBin("kcov", ["--version"], binDir)
|
||||||
|
} catch (err) {
|
||||||
|
info((err as Error).message)
|
||||||
|
}
|
||||||
|
await cleanupTmpDir("kcov-v41")
|
||||||
|
})
|
||||||
|
|
||||||
it("should setup Kcov v40 via downloading the binaries", async () => {
|
it("should setup Kcov v40 via downloading the binaries", async () => {
|
||||||
const directory = await setupTmpDir("kcov-v40")
|
const directory = await setupTmpDir("kcov-v40")
|
||||||
const { binDir } = (await setupKcov("40-binary", directory, "")) as InstallationInfo
|
const { binDir } = (await setupKcov("40-binary", directory, "")) as InstallationInfo
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
From b63754b53b3a7cf43e13ec56bd0be76cb6175437 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergei Trofimovich <slyich@gmail.com>
|
||||||
|
Date: Thu, 15 Sep 2022 19:55:21 +0100
|
||||||
|
Subject: [PATCH] Fix build on gcc-13: add missing <stdint.h> include
|
||||||
|
|
||||||
|
[ 15%] Building CXX object src/CMakeFiles/kcov.dir/writers/cobertura-writer.cc.o
|
||||||
|
In file included from kcov/src/writers/cobertura-writer.cc:6:
|
||||||
|
kcov/src/include/reporter.hh:24:90: error: 'uint64_t' has not been declared
|
||||||
|
24 | LineExecutionCount(unsigned int hits, unsigned int possibleHits, uint64_t order) :
|
||||||
|
| ^~~~~~~~
|
||||||
|
---
|
||||||
|
src/include/collector.hh | 2 ++
|
||||||
|
src/include/reporter.hh | 1 +
|
||||||
|
src/include/source-file-cache.hh | 2 ++
|
||||||
|
3 files changed, 5 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/src/include/collector.hh b/src/include/collector.hh
|
||||||
|
index 79e5d5f2..1369a416 100644
|
||||||
|
--- a/src/include/collector.hh
|
||||||
|
+++ b/src/include/collector.hh
|
||||||
|
@@ -2,6 +2,8 @@
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
+#include <stdint.h>
|
||||||
|
+
|
||||||
|
namespace kcov
|
||||||
|
{
|
||||||
|
class IFileParser;
|
||||||
|
diff --git a/src/include/reporter.hh b/src/include/reporter.hh
|
||||||
|
index bc058e69..98d8e56b 100644
|
||||||
|
--- a/src/include/reporter.hh
|
||||||
|
+++ b/src/include/reporter.hh
|
||||||
|
@@ -3,6 +3,7 @@
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
+#include <stdint.h>
|
||||||
|
|
||||||
|
namespace kcov
|
||||||
|
{
|
||||||
|
diff --git a/src/include/source-file-cache.hh b/src/include/source-file-cache.hh
|
||||||
|
index c0cb00ee..cfc73b81 100644
|
||||||
|
--- a/src/include/source-file-cache.hh
|
||||||
|
+++ b/src/include/source-file-cache.hh
|
||||||
|
@@ -3,6 +3,8 @@
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
+#include <stdint.h>
|
||||||
|
+
|
||||||
|
namespace kcov
|
||||||
|
{
|
||||||
|
/**
|
|
@ -15,6 +15,7 @@ import { addVPrefix, removeVPrefix } from "../utils/setup/version"
|
||||||
import { info } from "ci-log"
|
import { info } from "ci-log"
|
||||||
import { untildifyUser } from "untildify-user"
|
import { untildifyUser } from "untildify-user"
|
||||||
import { setupNinja } from "../ninja/ninja"
|
import { setupNinja } from "../ninja/ninja"
|
||||||
|
import { ubuntuVersion } from "../utils/env/ubuntu_version"
|
||||||
|
|
||||||
function getDownloadKcovPackageInfo(version: string): PackageInfo {
|
function getDownloadKcovPackageInfo(version: string): PackageInfo {
|
||||||
return {
|
return {
|
||||||
|
@ -44,8 +45,7 @@ async function buildKcov(file: string, dest: string) {
|
||||||
|
|
||||||
if (process.platform === "linux") {
|
if (process.platform === "linux") {
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
setupPacmanPack("libdwarf")
|
await Promise.all([setupPacmanPack("libdwarf"), setupPacmanPack("libcurl-openssl")])
|
||||||
setupPacmanPack("libcurl-openssl")
|
|
||||||
} else if (hasDnf()) {
|
} else if (hasDnf()) {
|
||||||
setupDnfPack("libdwarf-devel")
|
setupDnfPack("libdwarf-devel")
|
||||||
setupDnfPack("libcurl-devel")
|
setupDnfPack("libcurl-devel")
|
||||||
|
@ -53,6 +53,19 @@ async function buildKcov(file: string, dest: string) {
|
||||||
await setupAptPack([{ name: "libdw-dev" }, { name: "libcurl4-openssl-dev" }])
|
await setupAptPack([{ name: "libdw-dev" }, { name: "libcurl4-openssl-dev" }])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply gcc13.patch
|
||||||
|
try {
|
||||||
|
if (which.sync("patch", { nothrow: true }) !== null) {
|
||||||
|
const patch = join(__dirname, "gcc13.patch")
|
||||||
|
await execa("patch", ["-N", "-p1", "-i", patch], { cwd: out, stdio: "inherit" })
|
||||||
|
} else {
|
||||||
|
info("`patch` not found, skipping gcc13.patch, kcov may not build on gcc 13")
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
const buildDir = join(out, "build")
|
const buildDir = join(out, "build")
|
||||||
await execa(cmake, ["-S", out, "-B", buildDir, "-DCMAKE_BUILD_TYPE=Release", "-G", "Ninja"], {
|
await execa(cmake, ["-S", out, "-B", buildDir, "-DCMAKE_BUILD_TYPE=Release", "-G", "Ninja"], {
|
||||||
cwd: out,
|
cwd: out,
|
||||||
|
@ -67,12 +80,16 @@ async function buildKcov(file: string, dest: string) {
|
||||||
async function getCmake() {
|
async function getCmake() {
|
||||||
let cmake = which.sync("cmake", { nothrow: true })
|
let cmake = which.sync("cmake", { nothrow: true })
|
||||||
if (cmake === null) {
|
if (cmake === null) {
|
||||||
const { binDir } = await setupCmake(getVersion("cmake", undefined), join(untildifyUser(""), "cmake"), "")
|
const { binDir } = await setupCmake(
|
||||||
|
getVersion("cmake", undefined, await ubuntuVersion()),
|
||||||
|
join(untildifyUser(""), "cmake"),
|
||||||
|
""
|
||||||
|
)
|
||||||
cmake = join(binDir, "cmake")
|
cmake = join(binDir, "cmake")
|
||||||
}
|
}
|
||||||
const ninja = which.sync("ninja", { nothrow: true })
|
const ninja = which.sync("ninja", { nothrow: true })
|
||||||
if (ninja === null) {
|
if (ninja === null) {
|
||||||
await setupNinja(getVersion("ninja", undefined), join(untildifyUser(""), "ninja"), "")
|
await setupNinja(getVersion("ninja", undefined, await ubuntuVersion()), join(untildifyUser(""), "ninja"), "")
|
||||||
}
|
}
|
||||||
return cmake
|
return cmake
|
||||||
}
|
}
|
||||||
|
@ -97,7 +114,7 @@ export async function setupKcov(versionGiven: string, setupDir: string, arch: st
|
||||||
if (installMethod === "binary" && version_number >= 39) {
|
if (installMethod === "binary" && version_number >= 39) {
|
||||||
installationInfo = await setupBin("kcov", version, getDownloadKcovPackageInfo, setupDir, arch)
|
installationInfo = await setupBin("kcov", version, getDownloadKcovPackageInfo, setupDir, arch)
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
setupPacmanPack("binutils")
|
await setupPacmanPack("binutils")
|
||||||
} else if (hasDnf()) {
|
} else if (hasDnf()) {
|
||||||
setupDnfPack("binutils")
|
setupDnfPack("binutils")
|
||||||
} else if (isUbuntu()) {
|
} else if (isUbuntu()) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { join, addExeExt } from "patha"
|
import { join, addExeExt } from "patha"
|
||||||
import { delimiter } from "path"
|
import { delimiter } from "path"
|
||||||
import semverMajor from "semver/functions/major"
|
|
||||||
import { InstallationInfo, setupBin } from "../utils/setup/setupBin"
|
import { InstallationInfo, setupBin } from "../utils/setup/setupBin"
|
||||||
import { semverCoerceIfInvalid } from "../utils/setup/version"
|
import { semverCoerceIfInvalid } from "../utils/setup/version"
|
||||||
import { setupMacOSSDK } from "../macos-sdk/macos-sdk"
|
import { setupMacOSSDK } from "../macos-sdk/macos-sdk"
|
||||||
|
@ -47,8 +46,7 @@ async function setupLLVMWithoutActivation(version: string, setupDir: string, arc
|
||||||
async function setupLLVMDeps(arch: string, version: string) {
|
async function setupLLVMDeps(arch: string, version: string) {
|
||||||
if (process.platform === "linux") {
|
if (process.platform === "linux") {
|
||||||
// install llvm build dependencies
|
// install llvm build dependencies
|
||||||
const osVersion = await ubuntuVersion()
|
await setupGcc(getVersion("gcc", undefined, await ubuntuVersion()), "", arch) // using llvm requires ld, an up to date libstdc++, etc. So, install gcc first
|
||||||
await setupGcc(getVersion("gcc", undefined, osVersion), "", arch) // using llvm requires ld, an up to date libstdc++, etc. So, install gcc first
|
|
||||||
|
|
||||||
if (isUbuntu()) {
|
if (isUbuntu()) {
|
||||||
const majorVersion = parseInt(version.split(".")[0], 10)
|
const majorVersion = parseInt(version.split(".")[0], 10)
|
||||||
|
@ -59,12 +57,12 @@ async function setupLLVMDeps(arch: string, version: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: install libtinfo on other distros
|
// TODO: install libtinfo on other distros
|
||||||
// setupPacmanPack("ncurses")
|
// await setupPacmanPack("ncurses")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function activateLLVM(directory: string, versionGiven: string) {
|
export async function activateLLVM(directory: string, versionGiven: string) {
|
||||||
const version = semverCoerceIfInvalid(versionGiven)
|
const _version = semverCoerceIfInvalid(versionGiven)
|
||||||
|
|
||||||
const lib = join(directory, "lib")
|
const lib = join(directory, "lib")
|
||||||
|
|
||||||
|
@ -93,15 +91,16 @@ export async function activateLLVM(directory: string, versionGiven: string) {
|
||||||
setupMacOSSDK(),
|
setupMacOSSDK(),
|
||||||
]
|
]
|
||||||
|
|
||||||
// windows builds fail with llvm's CPATH
|
// TODO Causes issues with clangd
|
||||||
if (process.platform !== "win32") {
|
// TODO Windows builds fail with llvm's CPATH
|
||||||
const llvmMajor = semverMajor(version)
|
// if (process.platform !== "win32") {
|
||||||
if (await pathExists(`${directory}/lib/clang/${version}/include`)) {
|
// const llvmMajor = semverMajor(version)
|
||||||
promises.push(addEnv("CPATH", `${directory}/lib/clang/${version}/include`))
|
// if (await pathExists(`${directory}/lib/clang/${version}/include`)) {
|
||||||
} else if (await pathExists(`${directory}/lib/clang/${llvmMajor}/include`)) {
|
// promises.push(addEnv("CPATH", `${directory}/lib/clang/${version}/include`))
|
||||||
promises.push(addEnv("CPATH", `${directory}/lib/clang/${llvmMajor}/include`))
|
// } else if (await pathExists(`${directory}/lib/clang/${llvmMajor}/include`)) {
|
||||||
}
|
// promises.push(addEnv("CPATH", `${directory}/lib/clang/${llvmMajor}/include`))
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if (isUbuntu()) {
|
if (isUbuntu()) {
|
||||||
promises.push(
|
promises.push(
|
||||||
|
|
|
@ -65,6 +65,8 @@ export const VERSIONS: Set<string> = getVersions([
|
||||||
"16.0.0",
|
"16.0.0",
|
||||||
"16.0.1",
|
"16.0.1",
|
||||||
"16.0.2",
|
"16.0.2",
|
||||||
|
"16.0.3",
|
||||||
|
"16.0.4",
|
||||||
])
|
])
|
||||||
|
|
||||||
/** The LLVM versions that were never released for the Windows platform. */
|
/** The LLVM versions that were never released for the Windows platform. */
|
||||||
|
@ -93,6 +95,8 @@ const DARWIN_MISSING = new Set([
|
||||||
"16.0.0",
|
"16.0.0",
|
||||||
"16.0.1",
|
"16.0.1",
|
||||||
"16.0.2",
|
"16.0.2",
|
||||||
|
"16.0.3",
|
||||||
|
"16.0.4",
|
||||||
])
|
])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -152,6 +156,8 @@ const UBUNTU_SUFFIX_MAP: { [key: string]: string } = {
|
||||||
"15.0.6": "-ubuntu-18.04",
|
"15.0.6": "-ubuntu-18.04",
|
||||||
"16.0.0": "-ubuntu-18.04",
|
"16.0.0": "-ubuntu-18.04",
|
||||||
"16.0.2": "-ubuntu-22.04",
|
"16.0.2": "-ubuntu-22.04",
|
||||||
|
"16.0.3": "-ubuntu-22.04",
|
||||||
|
"16.0.4": "-ubuntu-22.04",
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The latest supported LLVM version for the Linux (Ubuntu) platform. */
|
/** The latest supported LLVM version for the Linux (Ubuntu) platform. */
|
||||||
|
|
311
src/main.ts
311
src/main.ts
|
@ -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")
|
||||||
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}`)
|
|
||||||
try {
|
|
||||||
let installationInfo: InstallationInfo | undefined | void
|
|
||||||
if (tool === "vcvarsall") {
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
await setupVCVarsall(
|
hasLLVM = await installTool(tool, version, osVersion, arch, setupCppDir, successMessages, errorMessages)
|
||||||
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()
|
|
||||||
try {
|
|
||||||
if (maybeCompiler !== undefined) {
|
if (maybeCompiler !== undefined) {
|
||||||
const { compiler, version } = getCompilerInfo(maybeCompiler)
|
const time1Compiler = Date.now()
|
||||||
|
await installCompiler(maybeCompiler, osVersion, setupCppDir, arch, successMessages, hasLLVM, errorMessages)
|
||||||
// install the compiler. We allow some aliases for the compiler name
|
const time2Compiler = Date.now()
|
||||||
startGroup(`Installing ${compiler} ${version ?? ""}`)
|
info(`took ${timeFormatter.format(time1Compiler, time2Compiler) || "0 seconds"}`)
|
||||||
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 the 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
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ describe("setup-python", () => {
|
||||||
|
|
||||||
it("should setup python via system", async () => {
|
it("should setup python via system", async () => {
|
||||||
process.env.CI = "false"
|
process.env.CI = "false"
|
||||||
|
process.env.GITHUB_ACTIONS = "false"
|
||||||
|
|
||||||
const installInfo = await setupPython(getVersion("python", "true", await ubuntuVersion()), directory, process.arch)
|
const installInfo = await setupPython(getVersion("python", "true", await ubuntuVersion()), directory, process.arch)
|
||||||
|
|
||||||
|
|
|
@ -1,45 +1,89 @@
|
||||||
|
/* eslint-disable require-atomic-updates */
|
||||||
|
import { getExecOutput } from "@actions/exec"
|
||||||
|
import assert from "assert"
|
||||||
|
import { GITHUB_ACTIONS } from "ci-info"
|
||||||
|
import { info, warning } from "ci-log"
|
||||||
|
import { execa } from "execa"
|
||||||
|
import memoize from "micro-memoize"
|
||||||
|
import { addExeExt, dirname, join } from "patha"
|
||||||
|
import which from "which"
|
||||||
import { addPath } from "../utils/env/addEnv"
|
import { addPath } from "../utils/env/addEnv"
|
||||||
|
import { hasDnf } from "../utils/env/hasDnf"
|
||||||
|
import { isArch } from "../utils/env/isArch"
|
||||||
|
import { isUbuntu } from "../utils/env/isUbuntu"
|
||||||
import { setupAptPack } from "../utils/setup/setupAptPack"
|
import { setupAptPack } from "../utils/setup/setupAptPack"
|
||||||
import { setupPacmanPack } from "../utils/setup/setupPacmanPack"
|
import { InstallationInfo } from "../utils/setup/setupBin"
|
||||||
import { setupBrewPack } from "../utils/setup/setupBrewPack"
|
import { setupBrewPack } from "../utils/setup/setupBrewPack"
|
||||||
import { setupChocoPack } from "../utils/setup/setupChocoPack"
|
import { setupChocoPack } from "../utils/setup/setupChocoPack"
|
||||||
import { GITHUB_ACTIONS } from "ci-info"
|
|
||||||
import { warning, info } from "ci-log"
|
|
||||||
import { isArch } from "../utils/env/isArch"
|
|
||||||
import which from "which"
|
|
||||||
import { InstallationInfo } from "../utils/setup/setupBin"
|
|
||||||
import { dirname, join } from "patha"
|
|
||||||
import { hasDnf } from "../utils/env/hasDnf"
|
|
||||||
import { setupDnfPack } from "../utils/setup/setupDnfPack"
|
import { setupDnfPack } from "../utils/setup/setupDnfPack"
|
||||||
import { isUbuntu } from "../utils/env/isUbuntu"
|
import { setupPacmanPack } from "../utils/setup/setupPacmanPack"
|
||||||
import { getExecOutput } from "@actions/exec"
|
|
||||||
import { isBinUptoDate } from "../utils/setup/version"
|
import { isBinUptoDate } from "../utils/setup/version"
|
||||||
import { getVersion } from "../versions/versions"
|
|
||||||
import assert from "assert"
|
|
||||||
import { execaSync } from "execa"
|
|
||||||
import { unique } from "../utils/std"
|
import { unique } from "../utils/std"
|
||||||
|
import { MinVersions } from "../versions/default_versions"
|
||||||
|
import { pathExists } from "path-exists"
|
||||||
|
import { setupPipPackWithPython } from "../utils/setup/setupPipPack"
|
||||||
|
|
||||||
export async function setupPython(version: string, setupDir: string, arch: string) {
|
export async function setupPython(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
|
||||||
if (!GITHUB_ACTIONS) {
|
const installInfo = await findOrSetupPython(version, setupDir, arch)
|
||||||
// TODO parse version
|
assert(installInfo.bin !== undefined)
|
||||||
return setupPythonViaSystem(version, setupDir, arch)
|
const foundPython = installInfo.bin
|
||||||
|
|
||||||
|
// setup pip
|
||||||
|
const foundPip = await findOrSetupPip(foundPython)
|
||||||
|
if (foundPip === undefined) {
|
||||||
|
throw new Error("pip was not installed correctly")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setup wheel and setuptools
|
||||||
|
try {
|
||||||
|
await setupPipPackWithPython(foundPython, "setuptools", undefined, true)
|
||||||
|
await setupPipPackWithPython(foundPython, "wheel", undefined, true)
|
||||||
|
} catch (err) {
|
||||||
|
warning(`Failed to install setuptools or wheel: ${(err as Error).toString()}. Ignoring...`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return installInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findOrSetupPython(version: string, setupDir: string, arch: string) {
|
||||||
|
let installInfo: InstallationInfo | undefined
|
||||||
|
let foundPython = await findPython(setupDir)
|
||||||
|
|
||||||
|
if (foundPython !== undefined) {
|
||||||
|
const binDir = dirname(foundPython)
|
||||||
|
installInfo = { bin: foundPython, installDir: binDir, binDir }
|
||||||
|
} else {
|
||||||
|
// if python is not found, try to install it
|
||||||
|
if (GITHUB_ACTIONS) {
|
||||||
|
// install python in GitHub Actions
|
||||||
try {
|
try {
|
||||||
info("Installing python in GitHub Actions")
|
info("Installing python in GitHub Actions")
|
||||||
const { setupActionsPython } = await import("./actions_python")
|
const { setupActionsPython } = await import("./actions_python")
|
||||||
return setupActionsPython(version, setupDir, arch)
|
await setupActionsPython(version, setupDir, arch)
|
||||||
|
|
||||||
|
foundPython = (await findPython(setupDir))!
|
||||||
|
const binDir = dirname(foundPython)
|
||||||
|
installInfo = { bin: foundPython, installDir: binDir, binDir }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
warning((err as Error).toString())
|
warning((err as Error).toString())
|
||||||
return setupPythonViaSystem(version, setupDir, arch)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (installInfo === undefined) {
|
||||||
|
// install python via system package manager
|
||||||
|
installInfo = await setupPythonSystem(setupDir, version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundPython === undefined || installInfo.bin === undefined) {
|
||||||
|
foundPython = (await findPython(setupDir))!
|
||||||
|
installInfo.bin = foundPython
|
||||||
|
}
|
||||||
|
|
||||||
|
return installInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setupPythonViaSystem(
|
async function setupPythonSystem(setupDir: string, version: string) {
|
||||||
version: string,
|
let installInfo: InstallationInfo | undefined
|
||||||
setupDir: string,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
_arch: string
|
|
||||||
): Promise<InstallationInfo> {
|
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case "win32": {
|
case "win32": {
|
||||||
if (setupDir) {
|
if (setupDir) {
|
||||||
|
@ -48,86 +92,157 @@ export async function setupPythonViaSystem(
|
||||||
await setupChocoPack("python3", version)
|
await setupChocoPack("python3", version)
|
||||||
}
|
}
|
||||||
// Adding the bin dir to the path
|
// Adding the bin dir to the path
|
||||||
const pythonBinPath =
|
const bin = (await findPython(setupDir))!
|
||||||
which.sync("python3.exe", { nothrow: true }) ??
|
const binDir = dirname(bin)
|
||||||
which.sync("python.exe", { nothrow: true }) ??
|
|
||||||
join(setupDir, "python.exe")
|
|
||||||
const pythonSetupDir = dirname(pythonBinPath)
|
|
||||||
/** The directory which the tool is installed to */
|
/** The directory which the tool is installed to */
|
||||||
await addPath(pythonSetupDir)
|
await addPath(binDir)
|
||||||
return { installDir: pythonSetupDir, binDir: pythonSetupDir }
|
installInfo = { installDir: binDir, binDir, bin }
|
||||||
|
break
|
||||||
}
|
}
|
||||||
case "darwin": {
|
case "darwin": {
|
||||||
return setupBrewPack("python3", version)
|
installInfo = await setupBrewPack("python3", version)
|
||||||
|
// add the python and pip binaries to the path
|
||||||
|
const brewPythonPrefix = await execa("brew", ["--prefix", "python"], { stdio: "pipe" })
|
||||||
|
const brewPythonBin = join(brewPythonPrefix.stdout, "libexec", "bin")
|
||||||
|
await addPath(brewPythonBin)
|
||||||
|
|
||||||
|
break
|
||||||
}
|
}
|
||||||
case "linux": {
|
case "linux": {
|
||||||
let installInfo: InstallationInfo
|
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
installInfo = setupPacmanPack("python", version)
|
installInfo = await setupPacmanPack("python", version)
|
||||||
setupPacmanPack("python-pip")
|
|
||||||
} else if (hasDnf()) {
|
} else if (hasDnf()) {
|
||||||
installInfo = setupDnfPack("python3", version)
|
installInfo = setupDnfPack("python3", version)
|
||||||
setupDnfPack("python3-pip")
|
|
||||||
} else if (isUbuntu()) {
|
} else if (isUbuntu()) {
|
||||||
installInfo = await setupAptPack([{ name: "python3", version }, { name: "python3-pip" }])
|
installInfo = await setupAptPack([{ name: "python3", version }, { name: "python-is-python3" }])
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unsupported linux distributions")
|
throw new Error("Unsupported linux distributions")
|
||||||
}
|
}
|
||||||
return installInfo
|
break
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
throw new Error("Unsupported platform")
|
throw new Error("Unsupported platform")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return installInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
let setupPythonAndPipTried = false
|
async function findPython(binDir?: string) {
|
||||||
|
for (const pythonBin of ["python3", "python"]) {
|
||||||
/// setup python and pip if needed
|
// eslint-disable-next-line no-await-in-loop
|
||||||
export async function setupPythonAndPip(): Promise<string> {
|
const foundPython = await isPythonUpToDate(pythonBin, binDir)
|
||||||
let foundPython: string
|
if (foundPython !== undefined) {
|
||||||
|
return foundPython
|
||||||
// install python
|
|
||||||
if (which.sync("python3", { nothrow: true }) !== null) {
|
|
||||||
foundPython = "python3"
|
|
||||||
} else if (which.sync("python", { nothrow: true }) !== null && (await isBinUptoDate("python", "3.0.0"))) {
|
|
||||||
foundPython = "python"
|
|
||||||
} else {
|
|
||||||
info("python3 was not found. Installing python")
|
|
||||||
await setupPython(getVersion("python", undefined), "", process.arch)
|
|
||||||
// try again
|
|
||||||
if (setupPythonAndPipTried) {
|
|
||||||
throw new Error("Failed to install python")
|
|
||||||
}
|
}
|
||||||
setupPythonAndPipTried = true
|
}
|
||||||
return setupPythonAndPip() // recurse
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async function isPythonUpToDate(candidate: string, binDir?: string) {
|
||||||
|
try {
|
||||||
|
if (binDir !== undefined) {
|
||||||
|
const pythonBinPath = join(binDir, addExeExt(candidate))
|
||||||
|
if (await pathExists(pythonBinPath)) {
|
||||||
|
if (await isBinUptoDate(pythonBinPath, MinVersions.python!)) {
|
||||||
|
return pythonBinPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const pythonBinPaths = (await which(candidate, { nothrow: true, all: true })) ?? []
|
||||||
|
for (const pythonBinPath of pythonBinPaths) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
if (await isBinUptoDate(pythonBinPath, MinVersions.python!)) {
|
||||||
|
return pythonBinPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findOrSetupPip(foundPython: string) {
|
||||||
|
const maybePip = await findPip()
|
||||||
|
|
||||||
|
if (maybePip === undefined) {
|
||||||
|
// install pip if not installed
|
||||||
|
info("pip was not found. Installing pip")
|
||||||
|
await setupPip(foundPython)
|
||||||
|
return findPip() // recurse to check if pip is on PATH and up-to-date
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(typeof foundPython === "string")
|
return maybePip
|
||||||
|
}
|
||||||
|
|
||||||
// install pip
|
async function findPip() {
|
||||||
if (process.platform === "win32") {
|
for (const pipCandidate of ["pip3", "pip"]) {
|
||||||
// downgrade pip on Windows
|
// eslint-disable-next-line no-await-in-loop
|
||||||
// https://github.com/pypa/pip/issues/10875#issuecomment-1030293005
|
const maybePip = await isPipUptoDate(pipCandidate)
|
||||||
execaSync(foundPython, ["-m", "pip", "install", "-U", "pip==21.3.1"], { stdio: "inherit" })
|
if (maybePip !== undefined) {
|
||||||
} else if (process.platform === "linux") {
|
return maybePip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async function isPipUptoDate(pip: string) {
|
||||||
|
try {
|
||||||
|
const pipPaths = (await which(pip, { nothrow: true, all: true })) ?? []
|
||||||
|
for (const pipPath of pipPaths) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
if (pipPath !== null && (await isBinUptoDate(pipPath, MinVersions.pip!))) {
|
||||||
|
return pipPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupPip(foundPython: string) {
|
||||||
|
const upgraded = await ensurePipUpgrade(foundPython)
|
||||||
|
if (!upgraded) {
|
||||||
|
await setupPipSystem()
|
||||||
|
// upgrade pip
|
||||||
|
await ensurePipUpgrade(foundPython)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensurePipUpgrade(foundPython: string) {
|
||||||
|
try {
|
||||||
|
await execa(foundPython, ["-m", "ensurepip", "-U", "--upgrade"], { stdio: "inherit" })
|
||||||
|
return true
|
||||||
|
} catch (err1) {
|
||||||
|
info((err1 as Error)?.toString?.())
|
||||||
|
try {
|
||||||
|
// ensure pip is disabled on Ubuntu
|
||||||
|
await execa(foundPython, ["-m", "pip", "install", "--upgrade", "pip"], { stdio: "inherit" })
|
||||||
|
return true
|
||||||
|
} catch (err2) {
|
||||||
|
info((err2 as Error)?.toString?.())
|
||||||
|
// pip module not found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// all methods failed
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupPipSystem() {
|
||||||
|
if (process.platform === "linux") {
|
||||||
// ensure that pip is installed on Linux (happens when python is found but pip not installed)
|
// ensure that pip is installed on Linux (happens when python is found but pip not installed)
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
setupPacmanPack("python-pip")
|
return setupPacmanPack("python-pip")
|
||||||
} else if (hasDnf()) {
|
} else if (hasDnf()) {
|
||||||
setupDnfPack("python3-pip")
|
return setupDnfPack("python3-pip")
|
||||||
} else if (isUbuntu()) {
|
} else if (isUbuntu()) {
|
||||||
await setupAptPack([{ name: "python3-pip" }])
|
return setupAptPack([{ name: "python3-pip" }])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
throw new Error(`Could not install pip on ${process.platform}`)
|
||||||
// install wheel (required for Conan, Meson, etc.)
|
|
||||||
execaSync(foundPython, ["-m", "pip", "install", "-U", "wheel"], { stdio: "inherit" })
|
|
||||||
|
|
||||||
return foundPython
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addPythonBaseExecPrefix(python: string) {
|
async function addPythonBaseExecPrefix_raw(python: string) {
|
||||||
const dirs: string[] = []
|
const dirs: string[] = []
|
||||||
|
|
||||||
// detection based on the platform
|
// detection based on the platform
|
||||||
|
@ -145,3 +260,10 @@ export async function addPythonBaseExecPrefix(python: string) {
|
||||||
// remove duplicates
|
// remove duplicates
|
||||||
return unique(dirs)
|
return unique(dirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the base exec prefix to the PATH. This is required for Conan, Meson, etc. to work properly.
|
||||||
|
*
|
||||||
|
* The answer is cached for subsequent calls
|
||||||
|
*/
|
||||||
|
export const addPythonBaseExecPrefix = memoize(addPythonBaseExecPrefix_raw)
|
||||||
|
|
|
@ -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]
|
|
@ -10,23 +10,45 @@ import { giveUserAccess } from "user-access"
|
||||||
import escapeQuote from "escape-quotes"
|
import escapeQuote from "escape-quotes"
|
||||||
import { pathExists } from "path-exists"
|
import { pathExists } from "path-exists"
|
||||||
|
|
||||||
|
type AddEnvOptions = {
|
||||||
|
/** If true, the value will be escaped with quotes and spaces will be escaped with backslash */
|
||||||
|
shouldEscapeSpace?: boolean
|
||||||
|
/** If true, the variable will be only added if it is not defined */
|
||||||
|
shouldAddOnlyIfNotDefined?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultAddEnvOptions: AddEnvOptions = {
|
||||||
|
shouldEscapeSpace: false,
|
||||||
|
shouldAddOnlyIfNotDefined: false,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an environment variable.
|
* Add an environment variable.
|
||||||
*
|
*
|
||||||
* This function is cross-platforms and works in all the local or CI systems.
|
* This function is cross-platforms and works in all the local or CI systems.
|
||||||
*/
|
*/
|
||||||
export async function addEnv(name: string, valGiven: string | undefined, shouldEscapeSpace: boolean = false) {
|
export async function addEnv(
|
||||||
const val = escapeString(valGiven ?? "", shouldEscapeSpace)
|
name: string,
|
||||||
|
valGiven: string | undefined,
|
||||||
|
options: AddEnvOptions = defaultAddEnvOptions
|
||||||
|
) {
|
||||||
|
const val = escapeString(valGiven ?? "", options.shouldEscapeSpace)
|
||||||
try {
|
try {
|
||||||
if (GITHUB_ACTIONS) {
|
if (GITHUB_ACTIONS) {
|
||||||
try {
|
try {
|
||||||
|
if (options.shouldAddOnlyIfNotDefined) {
|
||||||
|
if (process.env[name] !== undefined) {
|
||||||
|
info(`Environment variable ${name} is already defined. Skipping.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
exportVariable(name, val)
|
exportVariable(name, val)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error(err as Error)
|
error(err as Error)
|
||||||
await addEnvSystem(name, val)
|
await addEnvSystem(name, val, options)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await addEnvSystem(name, val)
|
await addEnvSystem(name, val, options)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error(err as Error)
|
error(err as Error)
|
||||||
|
@ -65,10 +87,16 @@ export async function addPath(path: string) {
|
||||||
|
|
||||||
export const cpprc_path = untildifyUser(".cpprc")
|
export const cpprc_path = untildifyUser(".cpprc")
|
||||||
|
|
||||||
async function addEnvSystem(name: string, valGiven: string | undefined) {
|
async function addEnvSystem(name: string, valGiven: string | undefined, options: AddEnvOptions) {
|
||||||
const val = valGiven ?? ""
|
const val = valGiven ?? ""
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case "win32": {
|
case "win32": {
|
||||||
|
if (options.shouldAddOnlyIfNotDefined) {
|
||||||
|
if (process.env[name] !== undefined) {
|
||||||
|
info(`Environment variable ${name} is already defined. Skipping.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
// We do not use `execaSync(`setx PATH "${path};%PATH%"`)` because of its character limit
|
// We do not use `execaSync(`setx PATH "${path};%PATH%"`)` because of its character limit
|
||||||
await execPowershell(`[Environment]::SetEnvironmentVariable('${name}', '${val}', "User")`)
|
await execPowershell(`[Environment]::SetEnvironmentVariable('${name}', '${val}', "User")`)
|
||||||
info(`${name}='${val}' was set in the environment.`)
|
info(`${name}='${val}' was set in the environment.`)
|
||||||
|
@ -77,8 +105,13 @@ async function addEnvSystem(name: string, valGiven: string | undefined) {
|
||||||
case "linux":
|
case "linux":
|
||||||
case "darwin": {
|
case "darwin": {
|
||||||
await setupCppInProfile()
|
await setupCppInProfile()
|
||||||
|
if (options.shouldAddOnlyIfNotDefined) {
|
||||||
|
appendFileSync(cpprc_path, `\nif [ -z "\${${name}}" ]; then export ${name}="${val}"; fi\n`)
|
||||||
|
info(`if not defined ${name} then ${name}="${val}" was added to "${cpprc_path}`)
|
||||||
|
} else {
|
||||||
appendFileSync(cpprc_path, `\nexport ${name}="${val}"\n`)
|
appendFileSync(cpprc_path, `\nexport ${name}="${val}"\n`)
|
||||||
info(`${name}="${val}" was added to "${cpprc_path}`)
|
info(`${name}="${val}" was added to "${cpprc_path}`)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -111,6 +144,7 @@ async function addPathSystem(path: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-disable require-atomic-updates */
|
||||||
let setupCppInProfile_called = false
|
let setupCppInProfile_called = false
|
||||||
|
|
||||||
/// handles adding conditions to source .cpprc file from .bashrc and .profile
|
/// handles adding conditions to source .cpprc file from .bashrc and .profile
|
||||||
|
|
|
@ -3,18 +3,24 @@ import { getUbuntuVersion } from "ubuntu-version"
|
||||||
import which from "which"
|
import which from "which"
|
||||||
import { setupAptPack } from "../setup/setupAptPack"
|
import { setupAptPack } from "../setup/setupAptPack"
|
||||||
import { isUbuntu } from "./isUbuntu"
|
import { isUbuntu } from "./isUbuntu"
|
||||||
|
import os from "os"
|
||||||
|
import memoize from "micro-memoize"
|
||||||
|
|
||||||
export async function ubuntuVersion(): Promise<number[] | null> {
|
async function ubuntuVersion_raw(): Promise<number[] | null> {
|
||||||
try {
|
try {
|
||||||
if (isUbuntu()) {
|
if (isUbuntu()) {
|
||||||
|
try {
|
||||||
if (which.sync("lsb_release", { nothrow: true }) === null) {
|
if (which.sync("lsb_release", { nothrow: true }) === null) {
|
||||||
await setupAptPack([{ name: "lsb-release" }])
|
await setupAptPack([{ name: "lsb-release" }])
|
||||||
}
|
}
|
||||||
|
} catch {
|
||||||
|
return detectUsingOsVersion()
|
||||||
|
}
|
||||||
|
|
||||||
const versionSplitted = await getUbuntuVersion()
|
const versionSplitted = await getUbuntuVersion()
|
||||||
|
|
||||||
if (versionSplitted.length === 0) {
|
if (versionSplitted.length === 0) {
|
||||||
warning("Failed to get the ubuntu major version.")
|
return detectUsingOsVersion()
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return versionSplitted
|
return versionSplitted
|
||||||
|
@ -26,3 +32,18 @@ export async function ubuntuVersion(): Promise<number[] | null> {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Detect Ubuntu version */
|
||||||
|
export const ubuntuVersion = memoize(ubuntuVersion_raw)
|
||||||
|
|
||||||
|
/** Detect Ubuntu version using os.version() for Ubuntu based distros */
|
||||||
|
function detectUsingOsVersion() {
|
||||||
|
// #46~22.04.1-Ubuntu SMP ...
|
||||||
|
const osVersion = os.version()
|
||||||
|
const versionSplitted = osVersion.split(".")
|
||||||
|
const majorVersion = parseInt(versionSplitted[0].replace("#", ""), 10)
|
||||||
|
const minorVersion = parseInt(versionSplitted[1].replace("~", ""), 10)
|
||||||
|
const patchVersion = parseInt(versionSplitted[2].split("-")[0], 10)
|
||||||
|
|
||||||
|
return [majorVersion, minorVersion, patchVersion]
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
/* eslint-disable require-atomic-updates */
|
|
||||||
import { InstallationInfo } from "./setupBin"
|
import { InstallationInfo } from "./setupBin"
|
||||||
import { execRoot, execRootSync } from "admina"
|
import { execRoot, execRootSync } from "admina"
|
||||||
import { info } from "@actions/core"
|
|
||||||
import { GITHUB_ACTIONS } from "ci-info"
|
import { GITHUB_ACTIONS } from "ci-info"
|
||||||
import { addEnv, cpprc_path, setupCppInProfile } from "../env/addEnv"
|
import { addEnv, cpprc_path, setupCppInProfile } from "../env/addEnv"
|
||||||
import which from "which"
|
import which from "which"
|
||||||
|
@ -10,7 +8,9 @@ import { promises as fsPromises } from "fs"
|
||||||
const { appendFile } = fsPromises
|
const { appendFile } = fsPromises
|
||||||
import { execa } from "execa"
|
import { execa } from "execa"
|
||||||
import escapeRegex from "escape-string-regexp"
|
import escapeRegex from "escape-string-regexp"
|
||||||
|
import { warning, info } from "ci-log"
|
||||||
|
|
||||||
|
/* eslint-disable require-atomic-updates */
|
||||||
let didUpdate: boolean = false
|
let didUpdate: boolean = false
|
||||||
let didInit: boolean = false
|
let didInit: boolean = false
|
||||||
|
|
||||||
|
@ -62,16 +62,24 @@ async function getAptArg(name: string, version: string | undefined) {
|
||||||
const { stdout } = await execa("apt-cache", [
|
const { stdout } = await execa("apt-cache", [
|
||||||
"search",
|
"search",
|
||||||
"--names-only",
|
"--names-only",
|
||||||
`^${escapeRegex(name)}\-${escapeRegex(version)}$`,
|
`^${escapeRegex(name)}-${escapeRegex(version)}$`,
|
||||||
])
|
])
|
||||||
if (stdout.trim() !== "") {
|
if (stdout.trim() !== "") {
|
||||||
return `${name}-${version}`
|
return `${name}-${version}`
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
|
// check if apt-get show can find the version
|
||||||
|
const { stdout: showStdout } = await execa("apt-cache", ["show", `${name}=${version}`])
|
||||||
|
if (showStdout.trim() === "") {
|
||||||
return `${name}=${version}`
|
return `${name}=${version}`
|
||||||
}
|
}
|
||||||
} else {
|
} catch {
|
||||||
return name
|
// ignore
|
||||||
}
|
}
|
||||||
|
warning(`Failed to install ${name} ${version} via apt, trying without version`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
function getApt() {
|
function getApt() {
|
||||||
|
@ -99,13 +107,16 @@ async function initApt(apt: string) {
|
||||||
"ca-certificates",
|
"ca-certificates",
|
||||||
"gnupg",
|
"gnupg",
|
||||||
])
|
])
|
||||||
const promises: Promise<any>[] = [
|
const promises: Promise<string | void>[] = [
|
||||||
addAptKeyViaServer(["3B4FE6ACC0B21F32", "40976EAF437D05B5"], "setup-cpp-ubuntu-archive.gpg"),
|
addAptKeyViaServer(["3B4FE6ACC0B21F32", "40976EAF437D05B5"], "setup-cpp-ubuntu-archive.gpg"),
|
||||||
addAptKeyViaServer(["1E9377A2BA9EF27F"], "launchpad-toolchain.gpg"),
|
addAptKeyViaServer(["1E9377A2BA9EF27F"], "launchpad-toolchain.gpg"),
|
||||||
]
|
]
|
||||||
if (apt === "nala") {
|
if (apt === "nala") {
|
||||||
// enable utf8 otherwise it fails because of the usage of ASCII encoding
|
// enable utf8 otherwise it fails because of the usage of ASCII encoding
|
||||||
promises.push(addEnv("LANG", "C.UTF-8"), addEnv("LC_ALL", "C.UTF-8"))
|
promises.push(
|
||||||
|
addEnv("LANG", "C.UTF-8", { shouldAddOnlyIfNotDefined: true }),
|
||||||
|
addEnv("LC_ALL", "C.UTF-8", { shouldAddOnlyIfNotDefined: true })
|
||||||
|
)
|
||||||
}
|
}
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
}
|
}
|
||||||
|
@ -115,6 +126,7 @@ function initGpg() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addAptKeyViaServer(keys: string[], name: string, server = "keyserver.ubuntu.com") {
|
export async function addAptKeyViaServer(keys: string[], name: string, server = "keyserver.ubuntu.com") {
|
||||||
|
try {
|
||||||
const fileName = `/etc/apt/trusted.gpg.d/${name}`
|
const fileName = `/etc/apt/trusted.gpg.d/${name}`
|
||||||
if (!(await pathExists(fileName))) {
|
if (!(await pathExists(fileName))) {
|
||||||
initGpg()
|
initGpg()
|
||||||
|
@ -135,6 +147,10 @@ export async function addAptKeyViaServer(keys: string[], name: string, server =
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return fileName
|
return fileName
|
||||||
|
} catch (err) {
|
||||||
|
warning(`Failed to add apt key via server ${server}: ${err}`)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addAptKeyViaDownload(name: string, url: string) {
|
export async function addAptKeyViaDownload(name: string, url: string) {
|
||||||
|
|
|
@ -34,6 +34,7 @@ export type InstallationInfo = {
|
||||||
/** The top install dir */
|
/** The top install dir */
|
||||||
installDir?: string
|
installDir?: string
|
||||||
binDir: string
|
binDir: string
|
||||||
|
bin?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
let didInit: boolean = false
|
let didInit: boolean = false
|
||||||
|
@ -104,9 +105,7 @@ export async function setupBin(
|
||||||
info(`Installing extraction dependencies`)
|
info(`Installing extraction dependencies`)
|
||||||
if (process.platform === "linux") {
|
if (process.platform === "linux") {
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
setupPacmanPack("unzip")
|
await Promise.all([setupPacmanPack("unzip"), setupPacmanPack("tar"), setupPacmanPack("xz")])
|
||||||
setupPacmanPack("tar")
|
|
||||||
setupPacmanPack("xz")
|
|
||||||
} else if (hasDnf()) {
|
} else if (hasDnf()) {
|
||||||
setupDnfPack("unzip")
|
setupDnfPack("unzip")
|
||||||
setupDnfPack("tar")
|
setupDnfPack("tar")
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
/* eslint-disable require-atomic-updates */
|
|
||||||
import { InstallationInfo } from "./setupBin"
|
import { InstallationInfo } from "./setupBin"
|
||||||
import { execRootSync } from "admina"
|
import { execRootSync } from "admina"
|
||||||
import { info } from "ci-log"
|
import { info, warning } from "ci-log"
|
||||||
|
import { execa } from "execa"
|
||||||
|
|
||||||
|
/* eslint-disable require-atomic-updates */
|
||||||
let didUpdate: boolean = false
|
let didUpdate: boolean = false
|
||||||
let didInit: boolean = false
|
let didInit: boolean = false
|
||||||
|
|
||||||
/** A function that installs a package using pacman */
|
/** A function that installs a package using pacman */
|
||||||
export function setupPacmanPack(name: string, version?: string, aur?: string): InstallationInfo {
|
export async function setupPacmanPack(name: string, version?: string, aur?: string): Promise<InstallationInfo> {
|
||||||
info(`Installing ${name} ${version ?? ""} via pacman`)
|
info(`Installing ${name} ${version ?? ""} via pacman`)
|
||||||
|
|
||||||
const pacman = "pacman"
|
const pacman = "pacman"
|
||||||
|
@ -18,21 +19,52 @@ export function setupPacmanPack(name: string, version?: string, aur?: string): I
|
||||||
didUpdate = true
|
didUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!didInit) {
|
|
||||||
// install base-devel
|
// install base-devel
|
||||||
|
if (!didInit) {
|
||||||
execRootSync(pacman, ["-S", "--noconfirm", "base-devel"])
|
execRootSync(pacman, ["-S", "--noconfirm", "base-devel"])
|
||||||
didInit = true
|
didInit = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const runInstall = (arg: string) => {
|
||||||
|
return execRootSync(aur ?? pacman, ["-S", "--noconfirm", arg])
|
||||||
|
}
|
||||||
|
|
||||||
if (version !== undefined && version !== "") {
|
if (version !== undefined && version !== "") {
|
||||||
|
// check if version is available
|
||||||
|
const availableVersions = await availablePacmanVersions(pacman, name)
|
||||||
|
if (availableVersions.includes(version)) {
|
||||||
|
// try different version formats
|
||||||
try {
|
try {
|
||||||
execRootSync(aur ?? pacman, ["-S", "--noconfirm", `${name}=${version}`])
|
runInstall(`${name}=${version}`)
|
||||||
} catch {
|
} catch {
|
||||||
execRootSync(aur ?? pacman, ["-S", "--noconfirm", `${name}${version}`])
|
runInstall(`${name}${version}`)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
execRootSync(aur ?? pacman, ["-S", "--noconfirm", name])
|
// try without version
|
||||||
|
info(`Failed to install ${name} ${version} via pacman, trying without version`)
|
||||||
|
runInstall(name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// version not specified, install latest
|
||||||
|
runInstall(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { binDir: "/usr/bin/" }
|
return { binDir: "/usr/bin/" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pacmanSiVersionRegex = /Version\s*:\s*(.*)/g
|
||||||
|
|
||||||
|
/** Query pacman for available versions */
|
||||||
|
async function availablePacmanVersions(pacman: string, name: string) {
|
||||||
|
const availableVersions = []
|
||||||
|
try {
|
||||||
|
const { stdout } = await execa(pacman, ["-Si", name])
|
||||||
|
|
||||||
|
for (const match of stdout.matchAll(pacmanSiVersionRegex)) {
|
||||||
|
availableVersions.push(match[1])
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
warning(`Failed to get available versions for ${name}: ${err}`)
|
||||||
|
}
|
||||||
|
return availableVersions
|
||||||
|
}
|
||||||
|
|
|
@ -1,45 +1,57 @@
|
||||||
/* eslint-disable require-atomic-updates */
|
|
||||||
import { info } from "@actions/core"
|
import { info } from "@actions/core"
|
||||||
import { execaSync } from "execa"
|
import { execaSync } from "execa"
|
||||||
import { pathExists } from "path-exists"
|
import { pathExists } from "path-exists"
|
||||||
import { addExeExt, dirname, join } from "patha"
|
import { addExeExt, dirname, join } from "patha"
|
||||||
import which from "which"
|
import which from "which"
|
||||||
import { addPythonBaseExecPrefix, setupPythonAndPip } from "../../python/python"
|
import { addPythonBaseExecPrefix, setupPython } from "../../python/python"
|
||||||
import { addPath } from "../env/addEnv"
|
import { addPath } from "../env/addEnv"
|
||||||
import { InstallationInfo } from "./setupBin"
|
import { InstallationInfo } from "./setupBin"
|
||||||
|
import { getVersion } from "../../versions/versions"
|
||||||
let python: string | undefined
|
import { ubuntuVersion } from "../env/ubuntu_version"
|
||||||
let binDirs: string[] | undefined
|
import memoize from "micro-memoize"
|
||||||
|
|
||||||
/** A function that installs a package using pip */
|
/** A function that installs a package using pip */
|
||||||
export async function setupPipPack(name: string, version?: string): Promise<InstallationInfo> {
|
export async function setupPipPack(name: string, version?: string, upgrade = false): Promise<InstallationInfo> {
|
||||||
|
return setupPipPackWithPython(await getPython(), name, version, upgrade)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setupPipPackWithPython(
|
||||||
|
givenPython: string,
|
||||||
|
name: string,
|
||||||
|
version?: string,
|
||||||
|
upgrade = false
|
||||||
|
): Promise<InstallationInfo> {
|
||||||
info(`Installing ${name} ${version ?? ""} via pip`)
|
info(`Installing ${name} ${version ?? ""} via pip`)
|
||||||
|
|
||||||
if (python === undefined) {
|
const nameAndVersion = version !== undefined && version !== "" ? `${name}==${version}` : name
|
||||||
python = await setupPythonAndPip()
|
const upgradeFlag = upgrade === true ? ["--upgrade"] : []
|
||||||
}
|
|
||||||
|
|
||||||
execaSync(python, ["-m", "pip", "install", version !== undefined && version !== "" ? `${name}==${version}` : name], {
|
execaSync(givenPython, ["-m", "pip", "install", ...upgradeFlag, nameAndVersion], {
|
||||||
stdio: "inherit",
|
stdio: "inherit",
|
||||||
})
|
})
|
||||||
|
|
||||||
if (binDirs === undefined) {
|
const execPaths = await addPythonBaseExecPrefix(givenPython)
|
||||||
binDirs = await addPythonBaseExecPrefix(python)
|
const binDir = await findBinDir(execPaths, name)
|
||||||
}
|
|
||||||
|
|
||||||
const binDir = await findBinDir(binDirs, name)
|
|
||||||
|
|
||||||
await addPath(binDir)
|
await addPath(binDir)
|
||||||
|
|
||||||
return { binDir }
|
return { binDir }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getPython_raw(): Promise<string> {
|
||||||
|
const pythonBin = (await setupPython(getVersion("python", undefined, await ubuntuVersion()), "", process.arch)).bin
|
||||||
|
if (pythonBin === undefined) {
|
||||||
|
throw new Error("Python binary was not found")
|
||||||
|
}
|
||||||
|
return pythonBin
|
||||||
|
}
|
||||||
|
const getPython = memoize(getPython_raw)
|
||||||
|
|
||||||
async function findBinDir(dirs: string[], name: string) {
|
async function findBinDir(dirs: string[], name: string) {
|
||||||
const exists = await Promise.all(dirs.map((dir) => pathExists(join(dir, addExeExt(name)))))
|
const exists = await Promise.all(dirs.map((dir) => pathExists(join(dir, addExeExt(name)))))
|
||||||
const dirIndex = exists.findIndex((exist) => exist)
|
const dirIndex = exists.findIndex((exist) => exist)
|
||||||
|
if (dirIndex !== -1) {
|
||||||
const foundDir = dirs[dirIndex]
|
const foundDir = dirs[dirIndex]
|
||||||
|
|
||||||
if (foundDir !== undefined) {
|
|
||||||
return foundDir
|
return foundDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,13 @@ import { info } from "ci-log"
|
||||||
export function getSpecificVersions(versions: Set<string>, semversion: string): string[] {
|
export function getSpecificVersions(versions: Set<string>, semversion: string): string[] {
|
||||||
return Array.from(versions)
|
return Array.from(versions)
|
||||||
.filter((v) => /^\d+\.\d+\.\d+$/.test(v) && v.startsWith(semversion))
|
.filter((v) => /^\d+\.\d+\.\d+$/.test(v) && v.startsWith(semversion))
|
||||||
.sort()
|
.sort((a, b) => {
|
||||||
|
try {
|
||||||
|
return semverCompare(a, b)
|
||||||
|
} catch (err) {
|
||||||
|
return a.localeCompare(b)
|
||||||
|
}
|
||||||
|
})
|
||||||
.reverse()
|
.reverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,16 +55,21 @@ export async function getSpecificVersionAndUrl(
|
||||||
|
|
||||||
// if the given set doesn't include the version, throw an error
|
// if the given set doesn't include the version, throw an error
|
||||||
if (!versions.has(version)) {
|
if (!versions.has(version)) {
|
||||||
throw new Error(`Unsupported target! (platform='${platform}', version='${version}')`)
|
throw new Error(
|
||||||
|
`Unsupported target! (platform='${platform}', version='${version}'). Try one of the following: ${JSON.stringify(
|
||||||
|
versions
|
||||||
|
)}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const offlineUrls: string[] = []
|
const offlineUrls: string[] = []
|
||||||
|
|
||||||
|
// TODO use Promise.any
|
||||||
for (const specificVersion of getSpecificVersions(versions, version)) {
|
for (const specificVersion of getSpecificVersions(versions, version)) {
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
const url = await getUrl(platform, specificVersion)
|
const url = await getUrl(platform, specificVersion)
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
if (url !== null) {
|
if (url !== null) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
if (await isUrlOnline(url)) {
|
if (await isUrlOnline(url)) {
|
||||||
return [specificVersion, url]
|
return [specificVersion, url]
|
||||||
} else {
|
} else {
|
||||||
|
@ -68,8 +79,8 @@ export async function getSpecificVersionAndUrl(
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unsupported target! (platform='${platform}', version='${version}'). The offline urls tested:\n${offlineUrls.join(
|
`Unsupported target! (platform='${platform}', version='${version}'). Try one of the following: ${JSON.stringify(
|
||||||
"\n"
|
versions
|
||||||
)}`
|
)}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,14 @@ export async function setupVcpkg(_version: string, setupDir: string, _arch: stri
|
||||||
if (process.platform === "linux") {
|
if (process.platform === "linux") {
|
||||||
// vcpkg download and extraction dependencies
|
// vcpkg download and extraction dependencies
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
setupPacmanPack("curl")
|
await Promise.all([
|
||||||
setupPacmanPack("zip")
|
setupPacmanPack("curl"),
|
||||||
setupPacmanPack("unzip")
|
setupPacmanPack("zip"),
|
||||||
setupPacmanPack("tar")
|
setupPacmanPack("unzip"),
|
||||||
setupPacmanPack("git")
|
setupPacmanPack("tar"),
|
||||||
setupPacmanPack("pkg-config")
|
setupPacmanPack("git"),
|
||||||
|
setupPacmanPack("pkg-config"),
|
||||||
|
])
|
||||||
} else if (hasDnf()) {
|
} else if (hasDnf()) {
|
||||||
setupDnfPack("curl")
|
setupDnfPack("curl")
|
||||||
setupDnfPack("zip")
|
setupDnfPack("zip")
|
||||||
|
|
|
@ -15,27 +15,32 @@ function getLLVMDefault() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DefaultVersions: Record<string, string> = {
|
export const DefaultVersions: Record<string, string | undefined> = {
|
||||||
llvm: getLLVMDefault(), // https://github.com/llvm/llvm-project/releases
|
llvm: getLLVMDefault(), // https://github.com/llvm/llvm-project/releases
|
||||||
clangtidy: getLLVMDefault(),
|
clangtidy: getLLVMDefault(),
|
||||||
clangformat: getLLVMDefault(),
|
clangformat: getLLVMDefault(),
|
||||||
ninja: "1.11.1", // https://github.com/ninja-build/ninja/releases
|
ninja: "1.11.1", // https://github.com/ninja-build/ninja/releases
|
||||||
cmake: "3.25.1", // https://github.com/Kitware/CMake/releases
|
cmake: "3.26.4", // https://github.com/Kitware/CMake/releases
|
||||||
gcovr: "5.2", // https://pypi.org/project/gcovr/
|
gcovr: "5.2", // https://pypi.org/project/gcovr/
|
||||||
conan: "1.57.0", // https://github.com/conan-io/conan/releases
|
conan: "1.60.0", // https://github.com/conan-io/conan/releases
|
||||||
meson: "1.0.0", // https://github.com/mesonbuild/meson/releases
|
meson: "1.0.2", // https://github.com/mesonbuild/meson/releases
|
||||||
kcov: "40", // https://github.com/SimonKagstrom/kcov/releases
|
kcov: "41", // https://github.com/SimonKagstrom/kcov/releases
|
||||||
task: "3.20.0", // https://github.com/go-task/task/releases
|
task: "3.25.0", // https://github.com/go-task/task/releases
|
||||||
doxygen: isArch() ? "1.9.6-1" : "1.9.6", // https://www.doxygen.nl/download.html // https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=doxygen // https://formulae.brew.sh/formula/doxygen // https://archlinux.org/packages/extra/x86_64/doxygen/
|
doxygen: isArch() ? "1.9.6-1" : "1.9.7", // https://www.doxygen.nl/download.html // https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=doxygen // https://formulae.brew.sh/formula/doxygen // https://archlinux.org/packages/extra/x86_64/doxygen/
|
||||||
gcc: isArch() ? "12.2.1-2" : "12", // https://github.com/brechtsanders/winlibs_mingw/releases and // https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=gcc
|
gcc: isArch() ? "13.1.1-1" : "13", // https://github.com/brechtsanders/winlibs_mingw/releases and // https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=gcc
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MinVersions: Record<string, string | undefined> = {
|
||||||
|
pip: "22.3.1",
|
||||||
|
python: "3.7.9",
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If an ubuntu versions is not in this map:
|
/// If an ubuntu versions is not in this map:
|
||||||
// - the newer ubuntu versions use the first entry (e.g. v20),
|
// - the newer ubuntu versions use the first entry (e.g. v20),
|
||||||
// - the older ones use ""
|
// - the older ones use ""
|
||||||
export const DefaultLinuxVersion: Record<string, Record<number, string>> = {
|
export const DefaultLinuxVersion: Record<string, Record<number, string> | undefined> = {
|
||||||
gcc: {
|
gcc: {
|
||||||
22: "12",
|
22: "13",
|
||||||
20: "11",
|
20: "11",
|
||||||
18: "11",
|
18: "11",
|
||||||
16: "11",
|
16: "11",
|
||||||
|
|
|
@ -1,32 +1,35 @@
|
||||||
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 */
|
||||||
export function getVersion(name: string, version: string | undefined, osVersion: number[] | null = null) {
|
export function getVersion(name: string, version: string | undefined, osVersion: number[] | null = null) {
|
||||||
if (isDefault(version, name)) {
|
console.log("isDefault", version, name, isVersionDefault(version))
|
||||||
if (process.platform === "linux" && osVersion !== null && name in DefaultLinuxVersion) {
|
if (isVersionDefault(version) && process.platform === "linux" && osVersion !== null && name in DefaultLinuxVersion) {
|
||||||
return getDefaultLinuxVersion(name, osVersion)
|
return getDefaultLinuxVersion(osVersion, DefaultLinuxVersion[name]!)
|
||||||
|
} else if (isVersionDefault(version) && name in DefaultVersions) {
|
||||||
|
return DefaultVersions[name]!
|
||||||
|
} else if (version === "true") {
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
// anything else
|
|
||||||
return DefaultVersions[name]
|
|
||||||
} else {
|
|
||||||
return version ?? ""
|
return version ?? ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isVersionDefault(version: string | undefined) {
|
||||||
|
return version === "true" || version === undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/// choose the default linux version based on ubuntu version
|
/// choose the default linux version based on ubuntu version
|
||||||
function getDefaultLinuxVersion(name: string, osVersion: number[]) {
|
function getDefaultLinuxVersion(osVersion: number[], toolLinuxVersions: Record<number, string>) {
|
||||||
const osVersionMaj = osVersion[0]
|
const osVersionMaj = osVersion[0]
|
||||||
const newest = parseInt(Object.keys(DefaultLinuxVersion[name])[0], 10) // newest version with the default
|
|
||||||
if (osVersionMaj >= newest) {
|
|
||||||
return DefaultLinuxVersion[name][osVersionMaj]
|
|
||||||
} else {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isDefault(version: string | undefined, name: string) {
|
// find which version block the os version is in
|
||||||
return version === "true" || (version === undefined && name in DefaultVersions)
|
const satisfyingVersion = Object.keys(toolLinuxVersions)
|
||||||
|
.map((v) => parseInt(v, 10))
|
||||||
|
.sort((a, b) => b - a) // sort in descending order
|
||||||
|
.find((v) => osVersionMaj >= v)
|
||||||
|
|
||||||
|
return satisfyingVersion === undefined ? "" : toolLinuxVersions[satisfyingVersion]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,7 +39,7 @@ export function isDefault(version: string | undefined, name: string) {
|
||||||
*/
|
*/
|
||||||
export function syncVersions(opts: Opts, tools: Inputs[]): boolean {
|
export function syncVersions(opts: Opts, tools: Inputs[]): boolean {
|
||||||
const toolsInUse = tools.filter((tool) => opts[tool] !== undefined)
|
const toolsInUse = tools.filter((tool) => opts[tool] !== undefined)
|
||||||
const toolsNonDefaultVersion = toolsInUse.filter((tool) => !isDefault(opts[tool], tool))
|
const toolsNonDefaultVersion = toolsInUse.filter((tool) => !isVersionDefault(opts[tool]))
|
||||||
|
|
||||||
const targetVersion = toolsNonDefaultVersion.length >= 1 ? opts[toolsNonDefaultVersion[0]] : "true"
|
const targetVersion = toolsNonDefaultVersion.length >= 1 ? opts[toolsNonDefaultVersion[0]] : "true"
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue