Skip to content

Commit

Permalink
fix(self-update): download alpine release artifacts on alpine (#5798)
Browse files Browse the repository at this point in the history
* fix(self-update): download alpine release artifacts on alpine

To detect musl target, we use an environment variable in Garden SEA rust
wrapper, because Nodejs does not expose musl target env via process.

* fix(self-update): allow specifying "alpine" platform

* improvement: simplify Platform type

* docs: add alpine to self-update command reference

* improvement: simplify architecture type
  • Loading branch information
stefreak authored Mar 4, 2024
1 parent bf51aa0 commit 418de1c
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 16 deletions.
8 changes: 6 additions & 2 deletions core/src/commands/self-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const selfUpdateOpts = {
help: `Specify an installation directory, instead of using the directory of the Garden CLI being used. Implies --force.`,
}),
"platform": new ChoicesParameter({
choices: ["macos", "linux", "windows"],
choices: ["macos", "linux", "alpine", "windows"],
help: `Override the platform, instead of detecting it automatically.`,
}),
"architecture": new ChoicesParameter({
Expand Down Expand Up @@ -332,7 +332,11 @@ export class SelfUpdateCommand extends Command<SelfUpdateArgs, SelfUpdateOpts> {

try {
if (!platform) {
platform = getPlatform() === "darwin" ? "macos" : getPlatform()
platform = getPlatform()

if (platform === "darwin") {
platform = "macos"
}
}

let architecture: Architecture = opts.architecture ? (opts.architecture as Architecture) : getArchitecture()
Expand Down
2 changes: 1 addition & 1 deletion core/src/plugin/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const toolBuildSchema = createSchema({
keys: () => ({
platform: joi
.string()
.allow("darwin", "linux", "windows")
.allow("darwin", "linux", "alpine", "windows")
.required()
.example("linux")
.description("The platform this build is for."),
Expand Down
56 changes: 45 additions & 11 deletions core/src/util/arch-platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,64 @@

import { memoize } from "lodash-es"
import { execSync } from "child_process"
import { InternalError } from "../exceptions.js"

const platformMap = {
win32: "windows" as const,
}
const archMap = {
x32: "386" as const,
x64: "amd64" as const,
}
export type Architecture = Exclude<NodeJS.Architecture, keyof typeof archMap> | (typeof archMap)[keyof typeof archMap]
export type Platform =
| Exclude<NodeJS.Platform, keyof typeof platformMap>
| (typeof platformMap)[keyof typeof platformMap]
} as const
const supportedArchitectures = ["386", "amd64", "arm64"] as const
const supportedPlatforms = ["darwin", "windows", "linux", "alpine"] as const
export type Platform = (typeof supportedPlatforms)[number]
export type Architecture = (typeof supportedArchitectures)[number]

export function getPlatform(): Platform {
return platformMap[process.platform] || process.platform
const platform = process.platform

if (platform === "win32") {
return "windows"
}

if (platform === "linux") {
if (getRustTargetEnv() === "musl") {
return "alpine"
}

return "linux"
}

if (platform === "darwin") {
return "darwin"
}

throw new InternalError({ message: `Unsupported platform: ${platform}` })
}

// rust target env
// The Garden SEA rust wrapper will set an environment variable called GARDEN_SEA_TARGET_ENV on linux so we can download Alpine binaries if needed.
type RustTargetEnv = undefined | "musl" | "gnu"
export function getRustTargetEnv(): RustTargetEnv {
const targetEnv = process.env.GARDEN_SEA_TARGET_ENV

if (targetEnv === undefined || targetEnv === "musl" || targetEnv === "gnu") {
return targetEnv
}

throw new InternalError({ message: `Invalid value for GARDEN_SEA_TARGET_ENV: ${targetEnv}` })
}

export function getArchitecture(): Architecture {
// Note: When node is running a x64 build,
// process.arch is always x64 even though the underlying CPU architecture may be arm64
// To check if we are running under Rosetta,
// use the `isDarwinARM` function below
const arch = process.arch
return archMap[arch] || arch
const arch = archMap[process.arch] || process.arch

if (!supportedArchitectures.includes(arch)) {
throw new InternalError({ message: `Unsupported architecture: ${arch}` })
}

return arch
}

export const isDarwinARM = memoize(() => {
Expand Down
2 changes: 2 additions & 0 deletions core/src/util/ext-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ export class PluginTool extends CliWrapper {
if (darwinARM) {
// first look for native arch, if not found, then try (potentially emulated) arch
buildSpec = findBuildSpec(spec, platform, "arm64") || findBuildSpec(spec, platform, "amd64")
} else if (platform === "alpine") {
buildSpec = findBuildSpec(spec, "alpine", architecture) || findBuildSpec(spec, "linux", architecture)
} else {
buildSpec = findBuildSpec(spec, platform, architecture)!
}
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -4938,7 +4938,7 @@ Examples:
| -------- | ----- | ---- | ----------- |
| `--force` | | boolean | Install the Garden CLI even if the specified or detected latest version is the same as the current version.
| `--install-dir` | | string | Specify an installation directory, instead of using the directory of the Garden CLI being used. Implies --force.
| `--platform` | | `macos` `linux` `windows` | Override the platform, instead of detecting it automatically.
| `--platform` | | `macos` `linux` `alpine` `windows` | Override the platform, instead of detecting it automatically.
| `--architecture` | | `arm64` `amd64` | Override the architecture, instead of detecting it automatically.
| `--major` | | boolean | Install the latest major version of Garden. Falls back to the current version if the greater major version does not exist.

Expand Down
7 changes: 7 additions & 0 deletions garden-sea/src/artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ pub struct GardenArtifact {
pub sha256: &'static [u8],
}

// needed to tell the self-updater to download alpine binaries on linux
#[cfg(all(target_os = "linux", target_env = "musl"))]
pub static TARGET_ENV: &str = "musl";

#[cfg(all(target_os = "linux", target_env = "gnu"))]
pub static TARGET_ENV: &str = "gnu";

// source

pub static SOURCE: GardenArtifact = GardenArtifact {
Expand Down
13 changes: 12 additions & 1 deletion garden-sea/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ use eyre::{Result, WrapErr};

use crate::{log::debug, signal};

#[cfg(all(target_os = "linux"))]
use crate::artifacts::TARGET_ENV;

pub(crate) fn spawn_garden<T>(path: &Path, sea_args: T) -> Result<Child>
where
T: Iterator<Item = String>,
Expand All @@ -31,12 +34,20 @@ where
command.env("GARDEN_SEA_EXTRACTED_ROOT", OsString::from(path));
command.env("GARDEN_SEA_EXECUTABLE_PATH", executable_path);

// exposes GARDEN_SEA_TARGET_ENV variable to self-update command, so it can decide to download alpine
// binaries on linux.
#[cfg(all(target_os = "linux"))]
command.env("GARDEN_SEA_TARGET_ENV", TARGET_ENV);

// Libuv 1.45.0 is affected by a kernel bug on certain kernels (Ubuntu 22)
// This leads to errors where Garden tool downloading errors with ETXTBSY
// Apparently file descriptor accounting is broken when using USE_IO_URING on older kernels
// See also: https://github.com/libuv/libuv/pull/4141/files
// TODO: Remove this once libuv 1.47 landed in a future NodeJS version, and we upgraded to it.
command.env("UV_USE_IO_URING", env::var("GARDEN_SEA_UV_USE_IO_URING").unwrap_or("0".into()));
command.env(
"UV_USE_IO_URING",
env::var("GARDEN_SEA_UV_USE_IO_URING").unwrap_or("0".into()),
);

// Allow users to override the heap size if needed.
let max_old_space_size = env::var("GARDEN_MAX_OLD_SPACE_SIZE").unwrap_or("4096".into());
Expand Down

0 comments on commit 418de1c

Please sign in to comment.