mirror of https://github.com/aminya/setup-cpp.git
feat: add setup-alpine package
This commit is contained in:
parent
6cd53aa7e2
commit
f737a07371
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "../../.eslintrc.json"
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"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",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"node-downloader-helper": "2.1.9",
|
||||
"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,39 @@
|
|||
import { execRoot } from "admina"
|
||||
import { info, warning } from "ci-log"
|
||||
import { pathExists } from "path-exists"
|
||||
import { hasApk } from "./has-apk.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())) {
|
||||
warning("apk is not available on this system")
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if repositories file exists
|
||||
const reposFile = "/etc/apk/repositories"
|
||||
if (!(await pathExists(reposFile))) {
|
||||
warning(`APK repositories file not found at ${reposFile}`)
|
||||
return false
|
||||
}
|
||||
|
||||
// Add repository to the file
|
||||
info(`Adding repository: ${repoUrl}`)
|
||||
await execRoot("sh", ["-c", `echo "${repoUrl}" >> ${reposFile}`], { stdio: "inherit" })
|
||||
|
||||
// Update package index after adding repository
|
||||
await execRoot("apk", ["update"], { stdio: "inherit" })
|
||||
|
||||
info(`Successfully added repository: ${repoUrl}`)
|
||||
return true
|
||||
} catch (error) {
|
||||
warning(`Failed to add repository ${repoUrl}: ${error}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -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,59 @@
|
|||
import { execRoot } from "admina"
|
||||
import { info, warning } from "ci-log"
|
||||
import { hasApk } from "./has-apk.js"
|
||||
import { type ApkPackage, filterAndQualifyApkPackages } from "./qualify-install.js"
|
||||
import { updateApkMemoized } from "./update.js"
|
||||
|
||||
export type { ApkPackage }
|
||||
|
||||
/**
|
||||
* Options for installing APK packages
|
||||
*/
|
||||
export interface InstallApkPackageOptions {
|
||||
/** The package name to install */
|
||||
package: ApkPackage
|
||||
/** Whether to update the package index before installing */
|
||||
update?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Whether the installation was successful
|
||||
*/
|
||||
export async function installApkPackage(packages: ApkPackage[], update = false): Promise<boolean> {
|
||||
// Check if apk is available
|
||||
if (!(await hasApk())) {
|
||||
warning("apk is not available on this system")
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
// Update package index if requested
|
||||
|
||||
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 true
|
||||
}
|
||||
|
||||
// Install the packages
|
||||
info(`Installing ${packagesToInstall.map((pack) => pack.name).join(" ")}`)
|
||||
await execRoot("apk", ["add", ...packagesToInstall.map((pack) => pack.name)], { stdio: "inherit" })
|
||||
|
||||
info(`Successfully installed ${packagesToInstall.map((pack) => pack.name).join(" ")}`)
|
||||
return true
|
||||
} catch (error) {
|
||||
warning(`Failed to install ${packages.map((pack) => pack.name).join(" ")}: ${error}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
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
|
||||
}
|
||||
|
||||
export async function filterAndQualifyApkPackages(packages: ApkPackage[]) {
|
||||
// Filter out packages that are already installed
|
||||
const installedPackages = await Promise.all(packages.map(checkPackageInstalled))
|
||||
return packages.filter((_pack, index) => !installedPackages[index])
|
||||
}
|
||||
/**
|
||||
* Check if a package is already installed
|
||||
* @param pack The package to check
|
||||
* @returns Whether the package is installed
|
||||
*/
|
||||
|
||||
async function checkPackageInstalled(pack: ApkPackage): Promise<boolean> {
|
||||
try {
|
||||
const { exitCode } = await execRoot("apk", ["info", "-e", pack.name], { reject: false })
|
||||
return exitCode === 0
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import { execRoot } from "admina"
|
||||
import memoizee from "memoizee"
|
||||
|
||||
async function updateApk() {
|
||||
await execRoot("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"]
|
||||
}
|
||||
|
|
@ -364,6 +364,46 @@ 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
|
||||
escape-string-regexp:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
memoizee:
|
||||
specifier: ^0.4.17
|
||||
version: 0.4.17
|
||||
node-downloader-helper:
|
||||
specifier: 2.1.9
|
||||
version: 2.1.9
|
||||
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':
|
||||
|
|
|
|||
Loading…
Reference in New Issue