diff --git a/packages/@postgrestools/backend-jsonrpc/src/command.ts b/packages/@postgrestools/backend-jsonrpc/src/command.ts index 1f3ef398f..881f6d7ba 100644 --- a/packages/@postgrestools/backend-jsonrpc/src/command.ts +++ b/packages/@postgrestools/backend-jsonrpc/src/command.ts @@ -1,36 +1,74 @@ +import { execSync } from "node:child_process"; + /** * Gets the path of the binary for the current platform * * @returns Filesystem path to the binary, or null if no prebuilt distribution exists for the current platform */ export function getCommand(): string | null { - const { platform, arch } = process; - - type PlatformPaths = { - [P in NodeJS.Platform]?: { - [A in NodeJS.Architecture]?: string; - }; - }; - - const PLATFORMS: PlatformPaths = { - win32: { - x64: "@postgrestools/cli-win32-x64/postgrestools.exe", - arm64: "@postgrestools/cli-win32-arm64/postgrestools.exe", - }, - darwin: { - x64: "@postgrestools/cli-darwin-x64/postgrestools", - arm64: "@postgrestools/cli-darwin-arm64/postgrestools", - }, - linux: { - x64: "@postgrestools/cli-linux-x64/postgrestools", - arm64: "@postgrestools/cli-linux-arm64/postgrestools", - }, - }; - - const binPath = PLATFORMS?.[platform]?.[arch]; - if (!binPath) { - return null; - } - - return require.resolve(binPath); + const { platform, arch } = process; + + const PLATFORMS: Partial< + Record< + NodeJS.Platform | "linux-musl", + Partial> + > + > = { + win32: { + x64: "@postgrestools/cli-x86_64-windows-msvc/postgrestools.exe", + arm64: "@postgrestools/cli-aarch64-windows-msvc/postgrestools.exe", + }, + darwin: { + x64: "@postgrestools/cli-x86_64-apple-darwin/postgrestools", + arm64: "@postgrestools/cli-aarch64-apple-darwin/postgrestools", + }, + linux: { + x64: "@postgrestools/cli-x86_64-linux-gnu/postgrestools", + arm64: "@postgrestools/cli-aarch64-linux-gnu/postgrestools", + }, + "linux-musl": { + x64: "@postgrestools/cli-x86_64-linux-musl/postgrestools", + // no arm64 build for musl + }, + }; + + function isMusl() { + let stderr = ""; + try { + stderr = execSync("ldd --version", { + stdio: [ + "ignore", // stdin + "pipe", // stdout – glibc systems print here + "pipe", // stderr – musl systems print here + ], + }).toString(); + } catch (err: unknown) { + if (hasStdErr(err)) { + stderr = err.stderr; + } + } + if (stderr.indexOf("musl") > -1) { + return true; + } + return false; + } + + function getPlatform(): NodeJS.Platform | "linux-musl" { + if (platform === "linux") { + return isMusl() ? "linux-musl" : "linux"; + } + + return platform; + } + + const binPath = PLATFORMS?.[getPlatform()]?.[arch]; + if (!binPath) { + return null; + } + + return require.resolve(binPath); +} + +function hasStdErr(err: unknown): err is { stderr: string } { + return !!(err as any)?.stderr; }