Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: install nala via default repo or installer #276

Merged
merged 2 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions dist/actions/setup-cpp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/actions/setup-cpp.js.map

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions dist/legacy/setup-cpp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/legacy/setup-cpp.js.map

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions dist/modern/setup-cpp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/modern/setup-cpp.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ pre-commit:
test.lint:
run: pnpm run test.lint
build:
run: pnpm run clean && pnpm i && pnpm run build -- --no-color && git add ./dist
run: pnpm run clean && pnpm run build -- --no-color && git add ./dist
126 changes: 94 additions & 32 deletions packages/setup-apt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,34 @@ Add the update-alternatives command to the rc file

**returns:** Promise<void>

### `getAptEnv` (function)

Get the environment variables to use for the apt command

**Parameters:**

- apt (`string`) - The apt command to use

**returns:** ProcessEnv

### `aptTimeout` (variable)

The timeout to use for apt commands
Wait up to 300 seconds if the apt-get lock is held

### `hasNala` (function)

Check if nala is installed

**returns:** boolean

### `getApt` (function)

Get the apt command to use
If nala is installed, use that, otherwise use apt-get

**returns:** string

### `isAptPackInstalled` (function)

Check if a package is installed
Expand All @@ -66,6 +94,8 @@ Check if a package matching a regexp is installed

**returns:** Promise<boolean>

### `updatedRepos` (variable)

### `updateAptRepos` (function)

Update the apt repositories
Expand All @@ -76,14 +106,72 @@ Update the apt repositories

**returns:** void

### `InstallationInfo` (type)
### `updateAptReposMemoized` (variable)

The information about an installation result
Update the apt repositories (memoized)

### `aptTimeout` (variable)
**Parameters:**

The timeout to use for apt commands
Wait up to 300 seconds if the apt-get lock is held
- apt - The apt command to use (optional)

### `filterAndQualifyAptPackages` (function)

Filter out the packages that are already installed and qualify the packages into a full package name/version

**Parameters:**

- packages (`AptPackage[]`)
- apt (`string`)

**returns:** Promise<string[]>

### `qualifiedNeededAptPackage` (function)

Qualify the package into full package name/version.
If the package is not installed, return the full package name/version.
If the package is already installed, return undefined

**Parameters:**

- pack (`AptPackage`)
- apt (`string`)

**returns:** Promise<string>

### `initApt` (function)

Install gnupg and certificates (usually missing from docker containers)

**Parameters:**

- apt (`string`)

**returns:** Promise<void>

### `initAptMemoized` (variable)

Install gnupg and certificates (usually missing from docker containers) (memoized)

### `addAptRepository` (function)

**Parameters:**

- repo (`string`)
- apt (`string`)

**returns:** Promise<void>

### `installAddAptRepo` (function)

**Parameters:**

- apt (`string`)

**returns:** Promise<void>

### `InstallationInfo` (type)

The information about an installation result

### `AptPackage` (type)

Expand Down Expand Up @@ -115,29 +203,6 @@ await installAptPack([
])
```

### `hasNala` (function)

Check if nala is installed

**returns:** boolean

### `getApt` (function)

Get the apt command to use
If nala is installed, use that, otherwise use apt-get

**returns:** string

### `getAptEnv` (function)

Get the environment variables to use for the apt command

**Parameters:**

- apt (`string`) - The apt command to use

**returns:** ProcessEnv

### `AddAptKeyOptions` (type)

### `addAptKey` (function)
Expand All @@ -151,10 +216,7 @@ Add an apt key
**returns:** Promise<string>

```ts
await addAptKey({
key: "3B4FE6ACC0B21F32"
fileName: "bazel-archive-keyring.gpg",
})
await addAptKey({ key: "3B4FE6ACC0B21F32" fileName: "bazel-archive-keyring.gpg"})
```

```ts
Expand Down
1 change: 1 addition & 0 deletions packages/setup-apt/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export * from "./get-apt.js"
export * from "./init-apt.js"
export * from "./install.js"
export * from "./is-installed.js"
export * from "./qualify-install.js"
export * from "./update.js"
4 changes: 2 additions & 2 deletions packages/setup-apt/src/init-apt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ export async function initApt(apt: string) {
// Update the repos
updateAptReposMemoized(apt)

const toInstall = await filterAndQualifyAptPackages(apt, [
const toInstall = await filterAndQualifyAptPackages([
{ name: "ca-certificates" },
{ name: "gnupg" },
{ name: "apt-utils" },
])
], apt)

if (toInstall.length !== 0) {
execRootSync(apt, ["install", "-y", "--fix-broken", "-o", aptTimeout, ...toInstall], {
Expand Down
2 changes: 1 addition & 1 deletion packages/setup-apt/src/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export async function installAptPack(packages: AptPackage[], update = false): Pr
// Add the repos if needed
await addRepositories(apt, packages)

const needToInstall = await filterAndQualifyAptPackages(apt, packages)
const needToInstall = await filterAndQualifyAptPackages(packages, apt)

if (needToInstall.length === 0) {
info("All packages are already installed")
Expand Down
16 changes: 11 additions & 5 deletions packages/setup-apt/src/qualify-install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { warning } from "ci-log"
import escapeRegex from "escape-string-regexp"
import { execa } from "execa"
import { getAptEnv } from "./apt-env.js"
import { getApt } from "./get-apt.js"
import type { AptPackage } from "./install.js"
import { isAptPackInstalled } from "./is-installed.js"
import { updateAptReposMemoized, updatedRepos } from "./update.js"
Expand All @@ -19,15 +20,20 @@ export enum AptPackageType {
/**
* Filter out the packages that are already installed and qualify the packages into a full package name/version
*/
export async function filterAndQualifyAptPackages(apt: string, packages: AptPackage[]) {
return (await Promise.all(packages.map((pack) => qualifiedNeededAptPackage(apt, pack))))
export async function filterAndQualifyAptPackages(packages: AptPackage[], apt: string = getApt()) {
return (await Promise.all(packages.map((pack) => qualifiedNeededAptPackage(pack, apt))))
.filter((pack) => pack !== undefined)
}

async function qualifiedNeededAptPackage(apt: string, pack: AptPackage) {
// Qualify the packages into full package name/version
/**
* Qualify the package into full package name/version.
* If the package is not installed, return the full package name/version.
* If the package is already installed, return undefined
*/
export async function qualifiedNeededAptPackage(pack: AptPackage, apt: string = getApt()) {
// Qualify the package into full package name/version
const qualified = await getAptArg(apt, pack.name, pack.version)
// filter out the packages that are already installed
// filter out the package that are already installed
return (await isAptPackInstalled(qualified)) ? undefined : qualified
}

Expand Down
73 changes: 56 additions & 17 deletions src/nala/nala.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { tmpdir } from "os"
import { execRootSync } from "admina"
import { dirname } from "patha"
import { addAptKeyViaURL, hasNala, installAptPack } from "setup-apt"
import { error, info } from "ci-log"
import { readFile, writeFile } from "fs/promises"
import { DownloaderHelper } from "node-downloader-helper"
import { dirname, join } from "patha"
import { hasNala, installAptPack, qualifiedNeededAptPackage } from "setup-apt"
import which from "which"
import { isUbuntu } from "../utils/env/isUbuntu.js"

Expand All @@ -23,31 +27,66 @@ export async function setupNala(version: string, _setupDir: string, _arch: strin

await installAptPack([{ name: "python3-apt" }])

// https://gitlab.com/volian/nala/-/wikis/Installation
const keyFileName = await addAptKeyViaURL({
fileName: "volian-archive-nala.gpg",
keyUrl: "https://deb.volian.org/volian/nala.key",
})
execRootSync("/bin/bash", [
"-c",
`echo "deb [signed-by=${keyFileName}] http://deb.volian.org/volian/ nala main" | tee /etc/apt/sources.list.d/volian-archive-nala.list`,
])
binDir = "/usr/bin" // eslint-disable-line require-atomic-updates

// If nala is available in the default repositories, install it
try {
if (version !== "legacy") {
await installAptPack([{ name: "nala" }], true)
} else {
await installAptPack([{ name: "nala-legacy" }], true)
const nalaPack = await qualifiedNeededAptPackage({ name: "nala", version })
if (nalaPack !== undefined) {
await installAptPack([{ name: nalaPack }])
return { binDir }
}
} catch (err) {
await installAptPack([{ name: "nala-legacy" }], true)
// ignore
info(`Failed to install nala: ${err}`)
}

binDir = "/usr/bin" // eslint-disable-line require-atomic-updates
// Nala is not available in the default repositories
// Check if the legacy version is available
try {
const nalaLegacyPack = await qualifiedNeededAptPackage({ name: "nala-legacy" })
if (nalaLegacyPack !== undefined) {
await installAptPack([{ name: nalaLegacyPack }], true)
return { binDir }
}
} catch (err) {
// ignore
info(`Failed to install nala-legacy: ${err}`)
}

// Install via the installer script
await setupNalaViaInstaller()

return { binDir }
}

async function setupNalaViaInstaller() {
const installer = new DownloaderHelper(
"https://gitlab.com/volian/volian-archive/-/raw/main/install-nala.sh",
tmpdir(),
{ fileName: "install-nala.sh" },
)
installer.on("error", (err) => {
throw new Error(`Failed to download install-nala.sh: ${err}`)
})
await installer.start()

const installerPath = join(tmpdir(), "install-nala.sh")

// Patch the installer script to not use sudo explicitly
const script = await readFile(installerPath, "utf8")
await writeFile(installerPath, script.replace(/sudo/g, ""))

await installAptPack([{ name: "wget" }])

try {
execRootSync("bash", [installerPath])
} catch (err) {
error(`Failed to install nala via installer: ${err}`)
execRootSync("apt", ["install", "-y", "-t", "nala", "nala"])
}
}

export function bashWithNala(script: string) {
if (hasNala()) {
return `apt-get() { nala $@; }; export -f apt-get; ${script}; unset -f apt-get`
Expand Down
Loading