mirror of https://github.com/aminya/setup-cpp.git
Merge pull request #379 from aminya/alpine
feat: support Alpine + add setup-alpine package + detect externally managed python
This commit is contained in:
commit
be9dd533df
|
|
@ -244,6 +244,7 @@ jobs:
|
|||
- { distro: "ubuntu", image: "setup-cpp-ubuntu", BASE_VERSION: "20.04", tag: "20.04-1.3.0" }
|
||||
- { distro: "fedora", image: "setup-cpp-fedora", tag: "40-1.3.0" }
|
||||
- { distro: "arch", image: "setup-cpp-arch", tag: "base-1.3.0" }
|
||||
- { distro: "alpine", image: "setup-cpp-alpine", BASE_VERSION: "22-alpine3.21", tag: "3.21-1.3.0" }
|
||||
include:
|
||||
- os: ubuntu-24.04-arm
|
||||
platform: linux/arm64
|
||||
|
|
@ -254,6 +255,9 @@ jobs:
|
|||
- os: ubuntu-24.04-arm
|
||||
platform: linux/arm64
|
||||
container: { distro: "ubuntu", image: "setup-cpp-ubuntu", BASE_VERSION: "20.04", tag: "20.04-1.3.0" }
|
||||
- os: ubuntu-24.04-arm
|
||||
platform: linux/arm64
|
||||
container: { distro: "alpine", image: "setup-cpp-alpine", BASE_VERSION: "22-alpine3.21", tag: "3.21-1.3.0" }
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
|
@ -300,7 +304,7 @@ jobs:
|
|||
docker tag aminya/${{ matrix.container.image }}:${{ matrix.container.tag }}-${{ steps.platform.outputs.suffix }} aminya/${{ matrix.container.image }}:latest
|
||||
|
||||
- name: Push latest to Docker Hub
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.container.distro != 'ubuntu' }}
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.container.distro != 'ubuntu' && matrix.container.distro != 'alpine' }}
|
||||
run: docker push aminya/${{ matrix.container.image }}:latest
|
||||
|
||||
- name: Docker Readme for setup-cpp-${{matrix.container.distro }}
|
||||
|
|
@ -331,7 +335,7 @@ jobs:
|
|||
docker tag aminya/${{ matrix.container.image }}-llvm:${{ matrix.container.tag }}-${{ steps.platform.outputs.suffix }} aminya/${{ matrix.container.image }}-llvm:latest
|
||||
|
||||
- name: Push latest to Docker Hub
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.container.distro != 'ubuntu' }}
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.container.distro != 'ubuntu' && matrix.container.distro != 'alpine' }}
|
||||
run: docker push aminya/${{ matrix.container.image }}-llvm:latest
|
||||
|
||||
- name: Docker Readme for setup-cpp-${{matrix.container.distro }}-llvm
|
||||
|
|
@ -372,7 +376,7 @@ jobs:
|
|||
docker tag aminya/${{ matrix.container.image }}-gcc:${{ matrix.container.tag }}-${{ steps.platform.outputs.suffix }} aminya/${{ matrix.container.image }}-gcc:latest
|
||||
|
||||
- name: Push latest to Docker Hub
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.container.distro != 'ubuntu' }}
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.container.distro != 'ubuntu' && matrix.container.distro != 'alpine' }}
|
||||
run: docker push aminya/${{ matrix.container.image }}-gcc:latest
|
||||
|
||||
- name: Docker Readme for setup-cpp-${{matrix.container.distro }}-gcc
|
||||
|
|
@ -396,7 +400,7 @@ jobs:
|
|||
|
||||
- name: Build setup-cpp-${{matrix.container.distro }}-mingw
|
||||
id: build_mingw
|
||||
if: ${{ matrix.container.distro != 'fedora' }}
|
||||
if: ${{ matrix.container.distro != 'fedora' && !(matrix.container.distro == 'alpine' && matrix.platform == 'linux/arm64') }}
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
|
|
@ -410,16 +414,16 @@ jobs:
|
|||
cache-to: type=inline
|
||||
|
||||
- name: Tag latest locally
|
||||
if: ${{ matrix.container.distro != 'fedora' }}
|
||||
if: ${{ matrix.container.distro != 'fedora' && !(matrix.container.distro == 'alpine' && matrix.platform == 'linux/arm64') }}
|
||||
run: |
|
||||
docker tag aminya/${{ matrix.container.image }}-mingw:${{ matrix.container.tag }}-${{ steps.platform.outputs.suffix }} aminya/${{ matrix.container.image }}-mingw:latest
|
||||
|
||||
- name: Push latest to Docker Hub
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.container.distro != 'ubuntu' && matrix.container.distro != 'fedora' }}
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.container.distro != 'ubuntu' && matrix.container.distro != 'fedora' && matrix.container.distro != 'alpine' }}
|
||||
run: docker push aminya/${{ matrix.container.image }}-mingw:latest
|
||||
|
||||
- name: Docker Readme for setup-cpp-${{matrix.container.distro }}-mingw
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.container.distro != 'fedora' }}
|
||||
if: ${{ github.event_name != 'pull_request' && matrix.container.distro != 'fedora' && !(matrix.container.distro == 'alpine' && matrix.platform == 'linux/arm64') }}
|
||||
uses: peter-evans/dockerhub-description@v4
|
||||
with:
|
||||
username: aminya
|
||||
|
|
@ -428,7 +432,7 @@ jobs:
|
|||
readme-filepath: ./README_DOCKER.md
|
||||
|
||||
- name: Test Mingw
|
||||
if: ${{ !contains(github.event.head_commit.message, '[skip test]') && matrix.container.distro != 'fedora' }}
|
||||
if: ${{ !contains(github.event.head_commit.message, '[skip test]') && matrix.container.distro != 'fedora' && matrix.container.distro != 'alpine' }}
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
|
|
@ -459,6 +463,11 @@ jobs:
|
|||
- { distro: "ubuntu", image: "setup-cpp-ubuntu", tag: "24.04-1.3.0", suffix: "-llvm", latest: true }
|
||||
- { distro: "ubuntu", image: "setup-cpp-ubuntu", tag: "24.04-1.3.0", suffix: "-gcc", latest: true }
|
||||
- { distro: "ubuntu", image: "setup-cpp-ubuntu", tag: "24.04-1.3.0", suffix: "-mingw", latest: true }
|
||||
|
||||
- { distro: "alpine", image: "setup-cpp-alpine", tag: "3.21-1.3.0", suffix: "", latest: true }
|
||||
- { distro: "alpine", image: "setup-cpp-alpine", tag: "3.21-1.3.0", suffix: "-llvm", latest: true }
|
||||
- { distro: "alpine", image: "setup-cpp-alpine", tag: "3.21-1.3.0", suffix: "-gcc", latest: true }
|
||||
- { distro: "alpine", image: "setup-cpp-alpine", tag: "3.21-1.3.0", suffix: "-mingw", latest: true }
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
FROM aminya/setup-cpp-alpine:latest AS setup-cpp-alpine-gcc
|
||||
|
||||
# install gcc
|
||||
RUN node --enable-source-maps /usr/lib/setup-cpp/setup-cpp.mjs \
|
||||
--compiler gcc && \
|
||||
# cleanup
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
SHELL ["/entrypoint.sh", "/bin/sh", "-c"]
|
||||
ENTRYPOINT ["/entrypoint.sh", "/bin/sh"]
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
FROM aminya/setup-cpp-alpine:latest AS setup-cpp-alpine-llvm
|
||||
|
||||
# install llvm
|
||||
RUN node --enable-source-maps /usr/lib/setup-cpp/setup-cpp.mjs \
|
||||
--compiler llvm && \
|
||||
# cleanup
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
SHELL ["/entrypoint.sh", "/bin/sh", "-c"]
|
||||
ENTRYPOINT ["/entrypoint.sh", "/bin/sh"]
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
FROM aminya/setup-cpp-alpine:latest AS setup-cpp-alpine-mingw
|
||||
|
||||
# install mingw/powershell
|
||||
RUN node --enable-source-maps /usr/lib/setup-cpp/setup-cpp.mjs \
|
||||
--compiler mingw \
|
||||
--powershell true && \
|
||||
# cleanup
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
SHELL ["/entrypoint.sh", "/bin/sh", "-c"]
|
||||
ENTRYPOINT ["/entrypoint.sh", "/bin/sh"]
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
ARG BASE_VERSION=22-alpine3.21
|
||||
|
||||
#### Base Image with Node.js
|
||||
FROM --platform=$BUILDPLATFORM node:${BASE_VERSION} AS alpine-nodejs
|
||||
|
||||
#### Base Image with Tools
|
||||
FROM alpine-nodejs AS setup-cpp-alpine
|
||||
|
||||
COPY "./dist/modern" "/usr/lib/setup-cpp/"
|
||||
|
||||
# install the cpp tools
|
||||
RUN node --enable-source-maps /usr/lib/setup-cpp/setup-cpp.mjs \
|
||||
--cmake true \
|
||||
--ninja true \
|
||||
--task true \
|
||||
--python true \
|
||||
--make true \
|
||||
--cppcheck true \
|
||||
--gcovr true \
|
||||
--doxygen true \
|
||||
--vcpkg true \
|
||||
--ccache true \
|
||||
--conan true \
|
||||
--cmakelang true \
|
||||
--meson true && \
|
||||
# cleanup
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
# Custom entrypoint due to bash -l limitations on Alpine
|
||||
RUN printf '#!/bin/bash\nsource $HOME/.cpprc\nexec "$@"\n' > /entrypoint.sh && \
|
||||
chmod +x /entrypoint.sh
|
||||
|
||||
SHELL ["/entrypoint.sh", "/bin/sh", "-c"]
|
||||
ENTRYPOINT ["/entrypoint.sh", "/bin/sh"]
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#### Building (example)
|
||||
FROM aminya/setup-cpp-alpine-gcc AS builder
|
||||
|
||||
COPY ./dev/cpp_vcpkg_project /home/app
|
||||
WORKDIR /home/app
|
||||
RUN task build
|
||||
|
||||
#### Running environment
|
||||
# use a fresh image as the runner
|
||||
FROM alpine:3.21 AS runner
|
||||
|
||||
# copy the built binaries and their runtime dependencies
|
||||
COPY --from=builder /home/app/build/my_exe/Release/ /home/app/
|
||||
WORKDIR /home/app/
|
||||
ENTRYPOINT ["./my_exe"]
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#### Building (example)
|
||||
FROM aminya/setup-cpp-alpine-llvm AS builder
|
||||
|
||||
COPY ./dev/cpp_vcpkg_project /home/app
|
||||
WORKDIR /home/app
|
||||
RUN task build
|
||||
|
||||
#### Running environment
|
||||
# use a fresh image as the runner
|
||||
FROM alpine:3.21 AS runner
|
||||
|
||||
# copy the built binaries and their runtime dependencies
|
||||
COPY --from=builder /home/app/build/my_exe/Release/ /home/app/
|
||||
WORKDIR /home/app/
|
||||
ENTRYPOINT ["./my_exe"]
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#### Cross Building (example)
|
||||
FROM aminya/setup-cpp-alpine-mingw AS builder-mingw
|
||||
|
||||
COPY ./dev/cpp_vcpkg_project /home/app
|
||||
WORKDIR /home/app
|
||||
RUN bash -c 'source ~/.cpprc \
|
||||
&& task build_cross_mingw'
|
||||
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
|
|
@ -135,6 +135,7 @@
|
|||
"safe-stable-stringify": "^2.5.0",
|
||||
"semver": "7.7.1",
|
||||
"setup-apt": "workspace:*",
|
||||
"setup-alpine": "workspace:*",
|
||||
"setup-brew": "workspace:*",
|
||||
"setup-python": "github:aminya/setup-python#9700887",
|
||||
"shx": "0.4.0",
|
||||
|
|
@ -184,6 +185,7 @@
|
|||
"retry-as-promised",
|
||||
"semver",
|
||||
"setup-apt",
|
||||
"setup-alpine",
|
||||
"setup-brew",
|
||||
"setup-python",
|
||||
"simple-update-notifier",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "envosman",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"description": "Manage environment variables, PATH, and rc files",
|
||||
"repository": "https://github.com/aminya/setup-cpp",
|
||||
"homepage": "https://github.com/aminya/setup-cpp/tree/master/packages/envosman",
|
||||
|
|
|
|||
|
|
@ -89,6 +89,8 @@ async function addEnvSystem(name: string, valGiven: string | undefined, options:
|
|||
await appendFile(options.rcPath, `\nexport ${name}="${val}"\n`)
|
||||
info(`${name}="${val}" was added to "${options.rcPath}`)
|
||||
}
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
process.env[name] = val
|
||||
return
|
||||
}
|
||||
default: {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "../../.eslintrc.json"
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "setup-alpine",
|
||||
"version": "1.0.0",
|
||||
"description": "Setup apk packages and repositories in Alpine Linux distributions",
|
||||
"repository": "https://github.com/aminya/setup-cpp",
|
||||
"homepage": "https://github.com/aminya/setup-cpp/tree/master/packages/setup-alpine",
|
||||
"license": "Apache-2.0",
|
||||
"author": "Amin Yahyaabadi",
|
||||
"main": "./dist/index.js",
|
||||
"source": "./src/index.ts",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"dist",
|
||||
"src",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc --pretty",
|
||||
"dev": "tsc --watch --pretty",
|
||||
"lint.tsc": "tsc --noEmit --pretty",
|
||||
"lint.eslint": "eslint '**/*.{ts,tsx,js,jsx,cjs,mjs,json,yaml}' --no-error-on-unmatched-pattern --cache --cache-location ./.cache/eslint/ --fix",
|
||||
"prepublishOnly": "pnpm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "22.13.11",
|
||||
"admina": "^1.0.1",
|
||||
"ci-info": "^4.0.0",
|
||||
"path-exists": "^5.0.0",
|
||||
"ci-log": "workspace:*",
|
||||
"envosman": "workspace:*",
|
||||
"which": "4.0.0",
|
||||
"execa": "7.2.0",
|
||||
"memoizee": "^0.4.17"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"keywords": [
|
||||
"setup",
|
||||
"apk",
|
||||
"apk-add",
|
||||
"repository",
|
||||
"alpine",
|
||||
"install",
|
||||
"setup-apk",
|
||||
"repositories",
|
||||
"linux",
|
||||
"alpine-linux",
|
||||
"package"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/memoizee": "0.4.11",
|
||||
"@types/which": "~3.0.4"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
import { info } from "ci-log"
|
||||
import { appendFile, readFile } from "fs/promises"
|
||||
import { pathExists } from "path-exists"
|
||||
import { hasApk } from "./has-apk.js"
|
||||
import { updateApkMemoized } from "./update.js"
|
||||
|
||||
/**
|
||||
* Add an APK repository
|
||||
* @param repoUrl The URL of the repository to add
|
||||
* @returns Whether the repository was added successfully
|
||||
*/
|
||||
|
||||
export async function addApkRepository(repoUrl: string): Promise<boolean> {
|
||||
if (!(await hasApk())) {
|
||||
throw new Error("apk is not available on this system")
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if repositories file exists
|
||||
const reposFile = "/etc/apk/repositories"
|
||||
if (!(await pathExists(reposFile))) {
|
||||
throw new Error(`APK repositories file not found at ${reposFile}`)
|
||||
}
|
||||
|
||||
// Add repository to the file
|
||||
info(`Adding repository: ${repoUrl}`)
|
||||
await appendFile(reposFile, `${repoUrl}\n`)
|
||||
|
||||
// Update package index after adding repository
|
||||
await updateApkMemoized.clear()
|
||||
await updateApkMemoized()
|
||||
|
||||
info(`Successfully added repository: ${repoUrl}`)
|
||||
return true
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to add repository ${repoUrl}: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the community repository
|
||||
* @returns Whether the repository was added successfully
|
||||
*/
|
||||
export async function enableCommunityRepository() {
|
||||
const alpineVersion = (await getAlpineVersion()).split(".").slice(0, 2).join(".")
|
||||
|
||||
return addApkRepository(`https://dl-cdn.alpinelinux.org/alpine/v${alpineVersion}/community/`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Alpine version
|
||||
* @returns The Alpine version
|
||||
*/
|
||||
export async function getAlpineVersion() {
|
||||
const releaseFile = "/etc/alpine-release"
|
||||
if (!(await pathExists(releaseFile))) {
|
||||
throw new Error(`Alpine release file not found at ${releaseFile}`)
|
||||
}
|
||||
return readFile(releaseFile, "utf8")
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import memoizee from "memoizee"
|
||||
import which from "which"
|
||||
|
||||
async function hasApk_() {
|
||||
try {
|
||||
await which("apk")
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Check if apk is available on the system
|
||||
*/
|
||||
export const hasApk = memoizee(hasApk_, { promise: true })
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
export * from "./apk-repository.js"
|
||||
export * from "./has-apk.js"
|
||||
export * from "./init-apt.js"
|
||||
export * from "./install-package.js"
|
||||
export * from "./qualify-install.js"
|
||||
export * from "./update.js"
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { defaultExecOptions, execRootSync } from "admina"
|
||||
import memoize from "memoizee"
|
||||
import { filterAndQualifyApkPackages } from "./qualify-install.js"
|
||||
|
||||
/** Install bash (usually missing from docker containers) */
|
||||
export async function initApk() {
|
||||
const toInstall = await filterAndQualifyApkPackages([
|
||||
{ name: "bash" },
|
||||
])
|
||||
|
||||
if (toInstall.length !== 0) {
|
||||
execRootSync("apk", ["add", ...toInstall], {
|
||||
...defaultExecOptions,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/** Install bash (usually missing from docker containers) (memoized) */
|
||||
export const initApkMemoized = memoize(initApk, { promise: true })
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import { execRoot } from "admina"
|
||||
import { info, warning } from "ci-log"
|
||||
import { hasApk } from "./has-apk.js"
|
||||
import { initApkMemoized } from "./init-apt.js"
|
||||
import { type ApkPackage, filterAndQualifyApkPackages, formatPackageWithVersion } from "./qualify-install.js"
|
||||
import { updateApkMemoized } from "./update.js"
|
||||
|
||||
/**
|
||||
* The information about an installation result
|
||||
*/
|
||||
export type InstallationInfo = {
|
||||
/** The install dir of the package (Defaults to `undefined`) */
|
||||
installDir?: string
|
||||
/** The bin dir of the package (Defaults to `/usr/bin`) */
|
||||
binDir: string
|
||||
/** The bin path of the package (Defaults to `undefined`) */
|
||||
bin?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a package using Alpine's apk package manager
|
||||
* @param packages The packages to install
|
||||
* @param update Whether to update the package index before installing
|
||||
* @returns The installation information
|
||||
*/
|
||||
export async function installApkPack(packages: ApkPackage[], update = false): Promise<InstallationInfo> {
|
||||
// Check if apk is available
|
||||
if (!(await hasApk())) {
|
||||
throw new Error("apk is not available on this system")
|
||||
}
|
||||
|
||||
try {
|
||||
// Update package index if requested
|
||||
|
||||
// init the apk
|
||||
await initApkMemoized()
|
||||
|
||||
if (update) {
|
||||
// Force update the repos
|
||||
await updateApkMemoized.clear()
|
||||
}
|
||||
// Update the repos if needed
|
||||
await updateApkMemoized()
|
||||
|
||||
const packagesToInstall = await filterAndQualifyApkPackages(packages)
|
||||
|
||||
if (packagesToInstall.length === 0) {
|
||||
info("All packages are already installed")
|
||||
return { binDir: "/usr/bin" }
|
||||
}
|
||||
|
||||
// Install the packages
|
||||
info(`Installing ${packagesToInstall.join(" ")}`)
|
||||
await execRoot("apk", ["add", ...packagesToInstall])
|
||||
|
||||
info(`Successfully installed ${packagesToInstall.join(" ")}`)
|
||||
return { binDir: "/usr/bin" }
|
||||
} catch (error) {
|
||||
warning(`Failed to install ${packages.map((pkg) => formatPackageWithVersion(pkg)).join(" ")}: ${error}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
import { execRoot } from "admina"
|
||||
|
||||
/**
|
||||
* The information about an apt package
|
||||
*/
|
||||
export type ApkPackage = {
|
||||
/** The name of the package */
|
||||
name: string
|
||||
/** The version of the package (optional) */
|
||||
version?: string
|
||||
/** The repository to add before installing the package (optional) */
|
||||
repository?: string
|
||||
/**
|
||||
* If the given version is not available, fall back to the latest version
|
||||
* @default false
|
||||
*/
|
||||
fallBackToLatest?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a package is already installed
|
||||
* @param pkg The package to check
|
||||
* @returns Whether the package is installed
|
||||
*/
|
||||
export async function checkPackageInstalled(pkg: ApkPackage): Promise<boolean> {
|
||||
try {
|
||||
// First check if the package is installed at all
|
||||
const { exitCode } = await execRoot("apk", ["info", "-e", pkg.name], {
|
||||
reject: false,
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
})
|
||||
|
||||
if (exitCode !== 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If no specific version is required, we're done
|
||||
if (pkg.version === undefined || pkg.version === "") {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check the installed version
|
||||
const { stdout: versionOutput } = await execRoot("apk", ["info", "-v", pkg.name], {
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
})
|
||||
|
||||
// Parse the version from output (format is typically "package-name-version")
|
||||
const installedVersion = versionOutput.trim().split("-").slice(-1)[0]
|
||||
|
||||
return installedVersion === pkg.version
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out packages that are already installed and qualify those that need installation
|
||||
* @param packages List of packages to check
|
||||
* @returns List of packages that need to be installed
|
||||
*/
|
||||
export async function filterAndQualifyApkPackages(packages: ApkPackage[]): Promise<string[]> {
|
||||
const results = await Promise.all(
|
||||
packages.map(async (pack) => {
|
||||
const isInstalled = await checkPackageInstalled(pack)
|
||||
return isInstalled ? undefined : pack
|
||||
}),
|
||||
)
|
||||
|
||||
return results.filter((pack): pack is ApkPackage => pack !== undefined)
|
||||
.map(formatPackageWithVersion)
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a package with its version if specified
|
||||
* @param pkg The package object
|
||||
* @returns Formatted package string (name=version or just name)
|
||||
*/
|
||||
export function formatPackageWithVersion(pkg: ApkPackage): string {
|
||||
if (pkg.version !== undefined && pkg.version !== "") {
|
||||
return `${pkg.name}=${pkg.version}`
|
||||
}
|
||||
return pkg.name
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import { execa } from "execa"
|
||||
import memoizee from "memoizee"
|
||||
|
||||
async function updateApk() {
|
||||
await execa("apk", ["update"], { stdio: "inherit" })
|
||||
}
|
||||
export const updateApkMemoized = memoizee(updateApk, { promise: true })
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false
|
||||
},
|
||||
"include": ["./src"]
|
||||
}
|
||||
|
|
@ -232,6 +232,9 @@ importers:
|
|||
semver:
|
||||
specifier: 7.7.1
|
||||
version: 7.7.1
|
||||
setup-alpine:
|
||||
specifier: workspace:*
|
||||
version: link:packages/setup-alpine
|
||||
setup-apt:
|
||||
specifier: workspace:*
|
||||
version: link:packages/setup-apt
|
||||
|
|
@ -364,6 +367,43 @@ importers:
|
|||
specifier: ^3.0.0
|
||||
version: 3.0.4
|
||||
|
||||
packages/setup-alpine:
|
||||
dependencies:
|
||||
'@types/node':
|
||||
specifier: 22.13.11
|
||||
version: 22.13.11
|
||||
admina:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1
|
||||
ci-info:
|
||||
specifier: ^4.0.0
|
||||
version: 4.2.0
|
||||
ci-log:
|
||||
specifier: workspace:*
|
||||
version: link:../ci-log
|
||||
envosman:
|
||||
specifier: workspace:*
|
||||
version: link:../envosman
|
||||
execa:
|
||||
specifier: 7.2.0
|
||||
version: 7.2.0
|
||||
memoizee:
|
||||
specifier: ^0.4.17
|
||||
version: 0.4.17
|
||||
path-exists:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
which:
|
||||
specifier: 4.0.0
|
||||
version: 4.0.0
|
||||
devDependencies:
|
||||
'@types/memoizee':
|
||||
specifier: 0.4.11
|
||||
version: 0.4.11
|
||||
'@types/which':
|
||||
specifier: ~3.0.4
|
||||
version: 3.0.4
|
||||
|
||||
packages/setup-apt:
|
||||
dependencies:
|
||||
'@types/node':
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { execRoot } from "admina"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { addAptKeyViaURL, installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { getDebArch } from "../utils/env/arch.js"
|
||||
|
|
@ -40,6 +41,8 @@ export async function setupBazel(version: string, _setupDir: string, _arch: stri
|
|||
} signed-by=${keyFileName}] https://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list`,
|
||||
])
|
||||
return installAptPack([{ name: "bazel", version }], true)
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([{ name: "bazel", version }], true)
|
||||
}
|
||||
throw new Error("Unsupported linux distribution")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { hasDnf } from "../utils/env/hasDnf.js"
|
||||
|
|
@ -8,7 +9,7 @@ import { setupDnfPack } from "../utils/setup/setupDnfPack.js"
|
|||
import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js"
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export function setupCcache(version: string, _setupDir: string, _arch: string) {
|
||||
export async function setupCcache(version: string, _setupDir: string, _arch: string) {
|
||||
switch (process.platform) {
|
||||
case "win32": {
|
||||
return setupChocoPack("ccache", version)
|
||||
|
|
@ -23,6 +24,8 @@ export function setupCcache(version: string, _setupDir: string, _arch: string) {
|
|||
return setupDnfPack([{ name: "ccache", version }])
|
||||
} else if (isUbuntu()) {
|
||||
return installAptPack([{ name: "ccache", version }])
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([{ name: "ccache", version }])
|
||||
}
|
||||
throw new Error("Unsupported linux distribution")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { info } from "ci-log"
|
|||
import { addExeExt } from "patha"
|
||||
import semverCoerce from "semver/functions/coerce"
|
||||
import semverLte from "semver/functions/lte"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { arm64, x86, x86_64 } from "../utils/env/arch.js"
|
||||
import { type InstallationInfo, type PackageInfo, setupBin } from "../utils/setup/setupBin.js"
|
||||
|
||||
|
|
@ -66,6 +67,15 @@ function getCmakePackageInfo(version: string, platform: NodeJS.Platform, arch: s
|
|||
}
|
||||
|
||||
/** Setup cmake */
|
||||
export function setupCmake(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
|
||||
export async function setupCmake(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
|
||||
if (await hasApk()) {
|
||||
return installApkPack([
|
||||
{
|
||||
name: "cmake",
|
||||
// version,
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
return setupBin("cmake", version, getCmakePackageInfo, setupDir, arch)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { addPath } from "envosman"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
|
|
@ -27,6 +28,8 @@ export async function setupCppcheck(version: string | undefined, _setupDir: stri
|
|||
return setupDnfPack([{ name: "ccache", version }])
|
||||
} else if (isUbuntu()) {
|
||||
return installAptPack([{ name: "cppcheck", version }])
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([{ name: "cppcheck", version }])
|
||||
}
|
||||
throw new Error("Unsupported linux distribution")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
import { join } from "path"
|
||||
import { info, notice } from "ci-log"
|
||||
import { addPath } from "envosman"
|
||||
import { pathExists } from "path-exists"
|
||||
import { addExeExt } from "patha"
|
||||
import retry from "retry-as-promised"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { setupGraphviz } from "../graphviz/graphviz.js"
|
||||
import { type PackageInfo, setupBin } from "../utils/setup/setupBin.js"
|
||||
import { setupChocoPack } from "../utils/setup/setupChocoPack.js"
|
||||
import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js"
|
||||
import { getVersion } from "../versions/versions.js"
|
||||
|
||||
import { pathExists } from "path-exists"
|
||||
import retry from "retry-as-promised"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
import { setupGraphviz } from "../graphviz/graphviz.js"
|
||||
import { arm64 } from "../utils/env/arch.js"
|
||||
import { hasDnf } from "../utils/env/hasDnf.js"
|
||||
import { isArch } from "../utils/env/isArch.js"
|
||||
import { isUbuntu } from "../utils/env/isUbuntu.js"
|
||||
import { macosVersion } from "../utils/env/macos_version.js"
|
||||
import { ubuntuVersion } from "../utils/env/ubuntu_version.js"
|
||||
import { type PackageInfo, setupBin } from "../utils/setup/setupBin.js"
|
||||
import { setupChocoPack } from "../utils/setup/setupChocoPack.js"
|
||||
import { setupDmg } from "../utils/setup/setupDmg.js"
|
||||
import { setupDnfPack } from "../utils/setup/setupDnfPack.js"
|
||||
import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js"
|
||||
import { getVersion } from "../versions/versions.js"
|
||||
|
||||
/** Get the platform data for cmake */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
|
@ -111,6 +111,13 @@ async function setupLinuxDoxygen(version: string, setupDir: string, arch: string
|
|||
return setupDnfPack([{ name: "doxygen", version }])
|
||||
} else if (isUbuntu()) {
|
||||
return await installAptPack([{ name: "doxygen", version, fallBackToLatest: arm64.includes(arch) }])
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([
|
||||
{
|
||||
name: "doxygen",
|
||||
// version,
|
||||
},
|
||||
])
|
||||
} else {
|
||||
throw new Error("Unsupported linux distributions")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { readdir } from "fs/promises"
|
|||
import { pathExists } from "path-exists"
|
||||
import { addExeExt } from "patha"
|
||||
import semverMajor from "semver/functions/major"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { addUpdateAlternativesToRc, installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
|
|
@ -46,6 +47,8 @@ export async function setupGcc(version: string, setupDir: string, arch: string,
|
|||
{ name: "gcc-c++", version },
|
||||
{ name: "libstdc++-devel" },
|
||||
])
|
||||
} else if (await hasApk()) {
|
||||
installationInfo = await installApkPack([{ name: "gcc", version }, { name: "g++", version }])
|
||||
} else if (isUbuntu()) {
|
||||
if (version === "") {
|
||||
// the default version
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { pathExists } from "path-exists"
|
|||
import { addExeExt } from "patha"
|
||||
import semverCoerce from "semver/functions/coerce.js"
|
||||
import semverSatisfies from "semver/functions/satisfies.js"
|
||||
import { enableCommunityRepository, hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
import { loadAssetList, matchAsset } from "../utils/asset/load-assets.js"
|
||||
|
|
@ -45,6 +46,12 @@ export async function setupMingw(version: string, setupDir: string, arch: string
|
|||
installationInfo = await setupDnfPack([{ name: "mingw64-gcc", version }])
|
||||
} else if (isUbuntu()) {
|
||||
installationInfo = await installAptPack([{ name: "mingw-w64", version }])
|
||||
} else if (await hasApk()) {
|
||||
await enableCommunityRepository()
|
||||
installationInfo = await installApkPack([
|
||||
{ name: "mingw-w64-gcc", version },
|
||||
{ name: "mingw-w64-crt", version },
|
||||
])
|
||||
} else {
|
||||
throw new Error(`Unsupported Linux distro for ${arch}`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { existsSync } from "fs"
|
||||
import { info, warning } from "ci-log"
|
||||
import { addPath } from "envosman"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import which from "which"
|
||||
|
|
@ -39,6 +40,8 @@ export async function setupGit(version: string, _setupDir: string, _arch: string
|
|||
return setupDnfPack([{ name: "git", version }])
|
||||
} else if (isUbuntu()) {
|
||||
return installAptPack([{ name: "git", version }])
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([{ name: "git", version }])
|
||||
}
|
||||
throw new Error("Unsupported linux distribution")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { addPath } from "envosman"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
|
|
@ -27,6 +28,8 @@ export async function setupGraphviz(version: string, _setupDir: string, _arch: s
|
|||
return setupDnfPack([{ name: "graphviz", version }])
|
||||
} else if (isUbuntu()) {
|
||||
return installAptPack([{ name: "graphviz", version }])
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([{ name: "graphviz", version }])
|
||||
}
|
||||
throw new Error("Unsupported linux distribution")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { ubuntuVersion } from "../utils/env/ubuntu_version.js"
|
|||
import type { InstallationInfo } from "../utils/setup/setupBin.js"
|
||||
import { quoteIfHasSpace } from "../utils/std/index.js"
|
||||
import { getVersion } from "../versions/versions.js"
|
||||
import { trySetupLLVMApk } from "./llvm_apk_installer.js"
|
||||
import { LLVMPackages, trySetupLLVMApt } from "./llvm_apt_installer.js"
|
||||
import { setupLLVMBin } from "./llvm_bin.js"
|
||||
import { trySetupLLVMBrew } from "./llvm_brew_installer.js"
|
||||
|
|
@ -50,6 +51,11 @@ async function setupLLVMOnly(
|
|||
return aptInstallInfo
|
||||
}
|
||||
|
||||
const apkInstallInfo = await trySetupLLVMApk(version)
|
||||
if (apkInstallInfo !== undefined) {
|
||||
return apkInstallInfo
|
||||
}
|
||||
|
||||
const brewInstallInfo = await trySetupLLVMBrew(version, setupDir, arch)
|
||||
if (brewInstallInfo !== undefined) {
|
||||
return brewInstallInfo
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
import { info } from "ci-log"
|
||||
import { type InstallationInfo, hasApk, installApkPack } from "setup-alpine"
|
||||
import { majorLLVMVersion } from "./utils.ts"
|
||||
|
||||
/**
|
||||
* Try to setup LLVM via the apk package manager
|
||||
*
|
||||
* @param {string} version - The version of LLVM to install
|
||||
*
|
||||
* @returns {InstallationInfo} The installation info if the installation was successful
|
||||
* @returns {undefined} If the installation fails, it will try to remove the repository and will return undefined
|
||||
*/
|
||||
export async function trySetupLLVMApk(
|
||||
version: string,
|
||||
): Promise<InstallationInfo | undefined> {
|
||||
if (!await hasApk()) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
try {
|
||||
return await setupLLVMApk(version)
|
||||
} catch (err) {
|
||||
info(`Failed to install llvm via system package manager ${err}.`)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function setupLLVMApk(version: string): Promise<InstallationInfo> {
|
||||
const majorVersion = majorLLVMVersion(version)
|
||||
return installApkPack([{ name: `llvm${majorVersion}` }])
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { join } from "path"
|
||||
import { addPath } from "envosman"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { getBrewDir, installBrewPack } from "setup-brew"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
|
|
@ -30,6 +31,8 @@ export async function setupMake(version: string, _setupDir: string, _arch: strin
|
|||
return setupDnfPack([{ name: "make", version }])
|
||||
} else if (isUbuntu()) {
|
||||
return installAptPack([{ name: "make", version }])
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([{ name: "make", version }])
|
||||
}
|
||||
throw new Error("Unsupported linux distribution")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
import { addPath } from "envosman"
|
||||
import { addExeExt } from "patha"
|
||||
import { enableCommunityRepository, hasApk, installApkPack } from "setup-alpine"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
import { arm64, x86, x86_64 } from "../utils/env/arch.js"
|
||||
import { type InstallationInfo, type PackageInfo, setupBin } from "../utils/setup/setupBin.js"
|
||||
|
||||
|
|
@ -37,6 +40,25 @@ function getNinjaPackageInfo(version: string, platform: NodeJS.Platform, arch: s
|
|||
}
|
||||
}
|
||||
|
||||
export function setupNinja(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
|
||||
export async function setupNinja(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
|
||||
if (await hasApk()) {
|
||||
await enableCommunityRepository()
|
||||
await installApkPack([
|
||||
{
|
||||
name: "ninja-build",
|
||||
// version,
|
||||
},
|
||||
{
|
||||
name: "ninja-is-really-ninja",
|
||||
},
|
||||
])
|
||||
await addPath("/usr/lib/ninja-build/bin", rcOptions)
|
||||
return {
|
||||
binDir: "/usr/lib/ninja-build/bin",
|
||||
installDir: "/usr/lib/ninja-build/",
|
||||
bin: "/usr/lib/ninja-build/bin/ninja",
|
||||
}
|
||||
}
|
||||
|
||||
return setupBin("ninja", version, getNinjaPackageInfo, setupDir, arch)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { execRootSync } from "admina"
|
|||
import { error } from "ci-log"
|
||||
import { addPath } from "envosman"
|
||||
import { addExeExt } from "patha"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
|
|
@ -62,6 +63,10 @@ function getPowershellUrl(
|
|||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export async function setupPowershell(version: string, setupDir: string, arch: string) {
|
||||
try {
|
||||
if (await hasApk()) {
|
||||
return setupPowershellSystem(version, setupDir, arch)
|
||||
}
|
||||
|
||||
return await setupBin("pwsh", version, getPowerShellPackageInfo, setupDir, arch)
|
||||
} catch (err) {
|
||||
error(`Failed to setup pwsh via download: ${err}. Trying package managers...`)
|
||||
|
|
@ -113,6 +118,8 @@ export async function setupPowershellSystem(version: string | undefined, _setupD
|
|||
// ])
|
||||
|
||||
return installAptPack([{ name: "powershell", version }], true)
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([{ name: "powershell", version: undefined }])
|
||||
}
|
||||
throw new Error("Unsupported linux distribution")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import assert from "assert"
|
||||
import { homedir } from "os"
|
||||
import { dirname, join, parse as pathParse } from "path"
|
||||
import { getExecOutput } from "@actions/exec"
|
||||
import ciInfo from "ci-info"
|
||||
const { GITHUB_ACTIONS } = ciInfo
|
||||
import { endGroup, startGroup } from "@actions/core"
|
||||
|
|
@ -9,9 +8,9 @@ import { info, notice, warning } from "ci-log"
|
|||
import { addPath } from "envosman"
|
||||
import { execa } from "execa"
|
||||
import { readdir } from "fs/promises"
|
||||
import memoize from "memoizee"
|
||||
import { pathExists } from "path-exists"
|
||||
import { addExeExt } from "patha"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack, isAptPackInstalled } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import which from "which"
|
||||
|
|
@ -26,11 +25,11 @@ import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js"
|
|||
import {
|
||||
hasPipxBinary,
|
||||
hasPipxModule,
|
||||
isExternallyManaged,
|
||||
setupPipPackSystem,
|
||||
setupPipPackWithPython,
|
||||
} from "../utils/setup/setupPipPack.js"
|
||||
import { isBinUptoDate } from "../utils/setup/version.js"
|
||||
import { unique } from "../utils/std/index.js"
|
||||
import { getVersionDefault, isMinVersion } from "../versions/versions.js"
|
||||
|
||||
export async function setupPython(
|
||||
|
|
@ -75,7 +74,7 @@ async function setupPipx(foundPython: string) {
|
|||
if (!(await hasPipxModule(foundPython))) {
|
||||
// install pipx for the system-wide python
|
||||
try {
|
||||
await setupPipPackSystem("pipx", isArch())
|
||||
await setupPipPackSystem("pipx")
|
||||
} catch (err) {
|
||||
notice(`pipx was not installed completely for the system-wide python: ${err}`)
|
||||
}
|
||||
|
|
@ -234,6 +233,8 @@ async function setupPythonSystem(setupDir: string, version: string) {
|
|||
installInfo = await setupDnfPack([{ name: "python3", version }])
|
||||
} else if (isUbuntu()) {
|
||||
installInfo = await installAptPack([{ name: "python3", version }, { name: "python-is-python3" }])
|
||||
} else if (await hasApk()) {
|
||||
installInfo = await installApkPack([{ name: "python3", version }])
|
||||
} else {
|
||||
throw new Error("Unsupported linux distributions")
|
||||
}
|
||||
|
|
@ -353,6 +354,11 @@ async function setupPip(foundPython: string) {
|
|||
}
|
||||
|
||||
async function ensurePipUpgrade(foundPython: string) {
|
||||
if (await isExternallyManaged(foundPython)) {
|
||||
// let system tools handle pip
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
await execa(foundPython, ["-m", "ensurepip", "-U", "--upgrade"], { stdio: "inherit" })
|
||||
return true
|
||||
|
|
@ -370,29 +376,3 @@ async function ensurePipUpgrade(foundPython: string) {
|
|||
// all methods failed
|
||||
return false
|
||||
}
|
||||
|
||||
async function addPythonBaseExecPrefix_(python: string) {
|
||||
const dirs: string[] = []
|
||||
|
||||
// detection based on the platform
|
||||
if (process.platform === "linux") {
|
||||
dirs.push("/home/runner/.local/bin/")
|
||||
} else if (process.platform === "darwin") {
|
||||
dirs.push("/usr/local/bin/")
|
||||
}
|
||||
|
||||
// detection using python.sys
|
||||
const base_exec_prefix = (await getExecOutput(`${python} -c "import sys;print(sys.base_exec_prefix);"`)).stdout.trim()
|
||||
// any of these are possible depending on the operating system!
|
||||
dirs.push(join(base_exec_prefix, "Scripts"), join(base_exec_prefix, "Scripts", "bin"), join(base_exec_prefix, "bin"))
|
||||
|
||||
// remove duplicates
|
||||
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_, { promise: true })
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { getUbuntuVersion } from "ubuntu-version"
|
||||
|
|
@ -16,6 +17,8 @@ export async function setupSccache(version: string, _setupDir: string, _arch: st
|
|||
if (ubuntuVersion[0] >= 24) {
|
||||
return installAptPack([{ name: "sccache", version }])
|
||||
}
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([{ name: "sccache", version }])
|
||||
}
|
||||
|
||||
return installBrewPack("sccache", version)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { hasDnf } from "../utils/env/hasDnf.js"
|
||||
|
|
@ -8,7 +9,7 @@ import { setupDnfPack } from "../utils/setup/setupDnfPack.js"
|
|||
import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js"
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export function setupSevenZip(version: string, _setupDir: string, _arch: string) {
|
||||
export async function setupSevenZip(version: string, _setupDir: string, _arch: string) {
|
||||
switch (process.platform) {
|
||||
case "win32": {
|
||||
return setupChocoPack("7zip", version)
|
||||
|
|
@ -26,6 +27,8 @@ export function setupSevenZip(version: string, _setupDir: string, _arch: string)
|
|||
])
|
||||
} else if (isUbuntu()) {
|
||||
return installAptPack([{ name: "p7zip-full", version }])
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([{ name: "p7zip", version }])
|
||||
}
|
||||
throw new Error("Unsupported linux distribution")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { info, warning } from "ci-log"
|
|||
import { execa } from "execa"
|
||||
import { mkdirp, move } from "fs-extra"
|
||||
import { rm } from "fs/promises"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import which from "which"
|
||||
import { setupSevenZip } from "../../sevenzip/sevenzip.js"
|
||||
|
|
@ -172,6 +173,8 @@ async function installTarDependencies(archiveType: ArchiveType) {
|
|||
await setupDnfPack([{ name: "gzip" }, { name: "tar" }])
|
||||
} else if (isUbuntu()) {
|
||||
await installAptPack([{ name: "gzip" }, { name: "tar" }])
|
||||
} else if (await hasApk()) {
|
||||
await installApkPack([{ name: "gzip" }, { name: "tar" }])
|
||||
}
|
||||
}
|
||||
break
|
||||
|
|
@ -185,6 +188,8 @@ async function installTarDependencies(archiveType: ArchiveType) {
|
|||
await setupDnfPack([{ name: "xz" }, { name: "tar" }])
|
||||
} else if (isUbuntu()) {
|
||||
await installAptPack([{ name: "xz-utils" }, { name: "tar" }])
|
||||
} else if (await hasApk()) {
|
||||
await installApkPack([{ name: "xz" }, { name: "tar" }])
|
||||
}
|
||||
}
|
||||
break
|
||||
|
|
|
|||
|
|
@ -1,25 +1,30 @@
|
|||
import { dirname, join } from "path"
|
||||
import { info } from "@actions/core"
|
||||
import { getExecOutput } from "@actions/exec"
|
||||
import { warning } from "ci-log"
|
||||
import { addPath } from "envosman"
|
||||
import { execa, execaSync } from "execa"
|
||||
import memoize from "memoizee"
|
||||
import { mkdirp } from "mkdirp"
|
||||
import { pathExists } from "path-exists"
|
||||
import { addExeExt } from "patha"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { untildifyUser } from "untildify-user"
|
||||
import which from "which"
|
||||
import { rcOptions } from "../../cli-options.js"
|
||||
import { addPythonBaseExecPrefix, setupPython } from "../../python/python.js"
|
||||
import { setupPython } from "../../python/python.js"
|
||||
import { getVersion } from "../../versions/versions.js"
|
||||
import { hasDnf } from "../env/hasDnf.js"
|
||||
import { isArch } from "../env/isArch.js"
|
||||
import { isUbuntu } from "../env/isUbuntu.js"
|
||||
import { ubuntuVersion } from "../env/ubuntu_version.js"
|
||||
import { unique } from "../std/index.js"
|
||||
import type { InstallationInfo } from "./setupBin.js"
|
||||
import { setupDnfPack } from "./setupDnfPack.js"
|
||||
import { setupPacmanPack } from "./setupPacmanPack.js"
|
||||
import { getBinVersion } from "./version.js"
|
||||
|
||||
export type SetupPipPackOptions = {
|
||||
/** Whether to use pipx instead of pip */
|
||||
|
|
@ -49,40 +54,42 @@ export async function setupPipPackWithPython(
|
|||
version?: string,
|
||||
options: SetupPipPackOptions = {},
|
||||
): Promise<InstallationInfo> {
|
||||
const { usePipx = true, user = true, upgrade = false, isLibrary = false } = options
|
||||
const { usePipx: givenUsePipx = true, user = true, upgrade = false, isLibrary = false } = options
|
||||
|
||||
const isPipx = usePipx && !isLibrary && (await hasPipxModule(givenPython))
|
||||
const usePipx = givenUsePipx && !isLibrary && (await hasPipxModule(givenPython))
|
||||
|
||||
const pip = isPipx ? "pipx" : "pip"
|
||||
// if the package is externally managed, let the system tools handle it
|
||||
const externallyManaged = !usePipx && (await isExternallyManaged(givenPython))
|
||||
|
||||
const pip = usePipx ? "pipx" : "pip"
|
||||
|
||||
// remove `[]` extensions
|
||||
const nameOnly = getPackageName(name)
|
||||
|
||||
// if upgrade is not requested, check if the package is already installed, and return if it is
|
||||
if (!upgrade) {
|
||||
const installed = isPipx
|
||||
const installed = usePipx
|
||||
? await pipxPackageInstalled(givenPython, nameOnly)
|
||||
: await pipPackageIsInstalled(givenPython, nameOnly)
|
||||
if (installed) {
|
||||
const binDir = isPipx
|
||||
const binDir = usePipx
|
||||
? await finishPipxPackageInstall()
|
||||
: await finishPipPackageInstall(givenPython, nameOnly)
|
||||
return { binDir }
|
||||
}
|
||||
}
|
||||
|
||||
const hasPackage = await pipHasPackage(givenPython, nameOnly)
|
||||
if (hasPackage) {
|
||||
if (!externallyManaged && await pipHasPackage(givenPython, nameOnly)) {
|
||||
try {
|
||||
info(`Installing ${name} ${version ?? ""} via ${pip}`)
|
||||
|
||||
const nameAndVersion = version !== undefined && version !== "" ? `${name}==${version}` : name
|
||||
const upgradeFlag = upgrade ? (isPipx ? ["upgrade"] : ["install", "--upgrade"]) : ["install"]
|
||||
const userFlag = !isPipx && user ? ["--user"] : []
|
||||
const upgradeFlag = upgrade ? (usePipx ? ["upgrade"] : ["install", "--upgrade"]) : ["install"]
|
||||
const userFlag = !usePipx && user ? ["--user"] : []
|
||||
|
||||
const env = process.env
|
||||
|
||||
if (isPipx && user) {
|
||||
if (usePipx && user) {
|
||||
// install to user home
|
||||
env.PIPX_HOME = await getPipxHome()
|
||||
env.PIPX_BIN_DIR = await getPipxBinDir()
|
||||
|
|
@ -103,7 +110,7 @@ export async function setupPipPackWithPython(
|
|||
throw new Error(`Failed to install ${name} as it was not found via ${pip} or the system package manager`)
|
||||
}
|
||||
|
||||
const binDir = isPipx
|
||||
const binDir = usePipx
|
||||
? await finishPipxPackageInstall()
|
||||
: await finishPipPackageInstall(givenPython, nameOnly)
|
||||
return { binDir }
|
||||
|
|
@ -275,15 +282,20 @@ async function findBinDir(dirs: string[], name: string) {
|
|||
return dirs[dirs.length - 1]
|
||||
}
|
||||
|
||||
export function setupPipPackSystem(name: string, addPythonPrefix = true) {
|
||||
export async function setupPipPackSystem(name: string, givenAddPythonPrefix?: boolean) {
|
||||
if (process.platform === "linux") {
|
||||
info(`Installing ${name} via the system package manager`)
|
||||
|
||||
const addPythonPrefix = name === "pipx" ? isArch() : (givenAddPythonPrefix ?? true)
|
||||
|
||||
if (isArch()) {
|
||||
return setupPacmanPack(addPythonPrefix ? `python-${name}` : name)
|
||||
} else if (hasDnf()) {
|
||||
return setupDnfPack([{ name: addPythonPrefix ? `python3-${name}` : name }])
|
||||
} else if (isUbuntu()) {
|
||||
return installAptPack([{ name: addPythonPrefix ? `python3-${name}` : name }])
|
||||
} else if (await hasApk()) {
|
||||
return installApkPack([{ name: addPythonPrefix ? `py3-${name}` : name }])
|
||||
}
|
||||
} else if (process.platform === "darwin") {
|
||||
// brew doesn't have venv
|
||||
|
|
@ -295,3 +307,70 @@ export function setupPipPackSystem(name: string, addPythonPrefix = true) {
|
|||
}
|
||||
return null
|
||||
}
|
||||
|
||||
async function addPythonBaseExecPrefix_(python: string) {
|
||||
const dirs: string[] = []
|
||||
|
||||
// detection based on the platform
|
||||
if (process.platform === "linux") {
|
||||
dirs.push("/home/runner/.local/bin/")
|
||||
} else if (process.platform === "darwin") {
|
||||
dirs.push("/usr/local/bin/")
|
||||
}
|
||||
|
||||
// detection using python.sys
|
||||
const base_exec_prefix = await getPythonBaseExecPrefix(python)
|
||||
// any of these are possible depending on the operating system!
|
||||
dirs.push(join(base_exec_prefix, "Scripts"), join(base_exec_prefix, "Scripts", "bin"), join(base_exec_prefix, "bin"))
|
||||
|
||||
// remove duplicates
|
||||
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_, { promise: true })
|
||||
|
||||
async function getPythonBaseExecPrefix_(python: string) {
|
||||
return (await getExecOutput(`${python} -c "import sys;print(sys.base_exec_prefix);"`)).stdout.trim()
|
||||
}
|
||||
/**
|
||||
* Get the base exec prefix of a Python installation
|
||||
* This is the directory where the Python interpreter is installed
|
||||
* and where the standard library is located
|
||||
*/
|
||||
export const getPythonBaseExecPrefix = memoize(getPythonBaseExecPrefix_, { promise: true })
|
||||
|
||||
async function isExternallyManaged_(python: string) {
|
||||
try {
|
||||
const base_exec_prefix = await getPythonBaseExecPrefix(python)
|
||||
|
||||
const pythonVersion = await getBinVersion(python)
|
||||
if (pythonVersion === undefined) {
|
||||
warning(`Failed to get the version of ${python}`)
|
||||
return false
|
||||
}
|
||||
|
||||
const externallyManagedPath = join(
|
||||
base_exec_prefix,
|
||||
"lib",
|
||||
`python${pythonVersion.major}.${pythonVersion.minor}`,
|
||||
"EXTERNALLY-MANAGED",
|
||||
)
|
||||
return pathExists(externallyManagedPath)
|
||||
} catch (err) {
|
||||
warning(`Failed to check if ${python} is externally managed: ${err}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given Python installation is externally managed
|
||||
* This is required for Conan, Meson, etc. to work properly
|
||||
*
|
||||
* The answer is cached for subsequent calls
|
||||
*/
|
||||
export const isExternallyManaged = memoize(isExternallyManaged_, { promise: true })
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { addEnv, addPath } from "envosman"
|
|||
import { execa } from "execa"
|
||||
import { pathExists } from "path-exists"
|
||||
import { addShExt, addShRelativePrefix } from "patha"
|
||||
import { hasApk, installApkPack } from "setup-alpine"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import which from "which"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
|
|
@ -54,6 +55,18 @@ export async function setupVcpkg(version: string, setupDir: string, arch: string
|
|||
{ name: "tar" },
|
||||
{ name: "pkg-config" },
|
||||
])
|
||||
} else if (await hasApk()) {
|
||||
const deps = [
|
||||
{ name: "curl" },
|
||||
{ name: "zip" },
|
||||
{ name: "unzip" },
|
||||
{ name: "tar" },
|
||||
{ name: "pkgconf" },
|
||||
]
|
||||
if (arm64.includes(arch)) {
|
||||
deps.push({ name: "build-base" })
|
||||
}
|
||||
await installApkPack(deps)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +87,7 @@ export async function setupVcpkg(version: string, setupDir: string, arch: string
|
|||
}
|
||||
|
||||
// Add VCPKG_FORCE_SYSTEM_BINARIES=1 for Linux arm64
|
||||
if (process.platform === "linux" && arch in arm64) {
|
||||
if (process.platform === "linux" && arm64.includes(arch)) {
|
||||
await addEnv("VCPKG_FORCE_SYSTEM_BINARIES", "1")
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue