aboutsummaryrefslogtreecommitdiff
path: root/packages/bun-npm/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/bun-npm/src')
-rw-r--r--packages/bun-npm/src/install.ts159
-rw-r--r--packages/bun-npm/src/platform.ts100
-rw-r--r--packages/bun-npm/src/util.ts212
3 files changed, 0 insertions, 471 deletions
diff --git a/packages/bun-npm/src/install.ts b/packages/bun-npm/src/install.ts
deleted file mode 100644
index 9eabd2c41..000000000
--- a/packages/bun-npm/src/install.ts
+++ /dev/null
@@ -1,159 +0,0 @@
-import { fetch, chmod, join, rename, rm, tmp, write, spawn } from "./util";
-import { unzipSync } from "zlib";
-import type { Platform } from "./platform";
-import { os, arch, supportedPlatforms } from "./platform";
-
-declare const npmVersion: string;
-declare const npmPackage: string;
-declare const npmOwner: string;
-
-export async function importBun(): Promise<string> {
- if (!supportedPlatforms.length) {
- throw new Error(`Unsupported platform: ${os} ${arch}`);
- }
- for (const platform of supportedPlatforms) {
- try {
- return await requireBun(platform);
- } catch (error) {
- console.debug("requireBun failed", error);
- }
- }
- throw new Error(`Failed to install package "${npmPackage}"`);
-}
-
-async function requireBun(platform: Platform): Promise<string> {
- const npmPackage = `${npmOwner}/${platform.bin}`;
- function resolveBun() {
- const exe = require.resolve(join(npmPackage, platform.exe));
- const { exitCode, stderr, stdout } = spawn(exe, ["--version"]);
- if (exitCode === 0) {
- return exe;
- }
- throw new Error(stderr || stdout);
- }
- try {
- return resolveBun();
- } catch (error) {
- console.debug("resolveBun failed", error);
- console.error(
- `Failed to find package "${npmPackage}".`,
- `You may have used the "--no-optional" flag when running "npm install".`,
- );
- }
- const cwd = join("node_modules", npmPackage);
- try {
- installBun(platform, cwd);
- } catch (error) {
- console.debug("installBun failed", error);
- console.error(
- `Failed to install package "${npmPackage}" using "npm install".`,
- error,
- );
- try {
- await downloadBun(platform, cwd);
- } catch (error) {
- console.debug("downloadBun failed", error);
- console.error(
- `Failed to download package "${npmPackage}" from "registry.npmjs.org".`,
- error,
- );
- }
- }
- return resolveBun();
-}
-
-function installBun(platform: Platform, dst: string): void {
- const npmPackage = `${npmOwner}/${platform.bin}`;
- const cwd = tmp();
- try {
- write(join(cwd, "package.json"), "{}");
- const { exitCode } = spawn(
- "npm",
- [
- "install",
- "--loglevel=error",
- "--prefer-offline",
- "--no-audit",
- "--progress=false",
- `${npmPackage}@${npmVersion}`,
- ],
- {
- cwd,
- stdio: "pipe",
- env: {
- ...process.env,
- npm_config_global: undefined,
- },
- },
- );
- if (exitCode === 0) {
- rename(join(cwd, "node_modules", npmPackage), dst);
- }
- } finally {
- try {
- rm(cwd);
- } catch (error) {
- console.debug("rm failed", error);
- // There is nothing to do if the directory cannot be cleaned up.
- }
- }
-}
-
-async function downloadBun(platform: Platform, dst: string): Promise<void> {
- const response = await fetch(
- `https://registry.npmjs.org/${npmOwner}/${platform.bin}/-/${platform.bin}-${npmVersion}.tgz`,
- );
- const tgz = await response.arrayBuffer();
- let buffer: Buffer;
- try {
- buffer = unzipSync(tgz);
- } catch (cause) {
- throw new Error("Invalid gzip data", { cause });
- }
- function str(i: number, n: number): string {
- return String.fromCharCode(...buffer.subarray(i, i + n)).replace(
- /\0.*$/,
- "",
- );
- }
- let offset = 0;
- while (offset < buffer.length) {
- const name = str(offset, 100).replace("package/", "");
- const size = parseInt(str(offset + 124, 12), 8);
- offset += 512;
- if (!isNaN(size)) {
- write(join(dst, name), buffer.subarray(offset, offset + size));
- if (name === platform.exe) {
- try {
- chmod(join(dst, name), 0o755);
- } catch (error) {
- console.debug("chmod failed", error);
- }
- }
- offset += (size + 511) & ~511;
- }
- }
-}
-
-export function optimizeBun(path: string): void {
- if (os === "win32") {
- throw new Error(
- "You must use Windows Subsystem for Linux, aka. WSL, to run bun. Learn more: https://learn.microsoft.com/en-us/windows/wsl/install",
- );
- }
- const { npm_config_user_agent } = process.env;
- if (npm_config_user_agent && /\byarn\//.test(npm_config_user_agent)) {
- throw new Error(
- "Yarn does not support bun, because it does not allow linking to binaries. To use bun, install using the following command: curl -fsSL https://bun.sh/install | bash",
- );
- }
- try {
- rename(path, join(__dirname, "bin", "bun"));
- return;
- } catch (error) {
- console.debug("optimizeBun failed", error);
- }
- throw new Error(
- "Your package manager doesn't seem to support bun. To use bun, install using the following command: curl -fsSL https://bun.sh/install | bash",
- );
-}
diff --git a/packages/bun-npm/src/platform.ts b/packages/bun-npm/src/platform.ts
deleted file mode 100644
index a01cc3ddc..000000000
--- a/packages/bun-npm/src/platform.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-import { read, spawn } from "./util";
-
-export const os = process.platform;
-
-export const arch =
- os === "darwin" && process.arch === "x64" && isRosetta2()
- ? "arm64"
- : process.arch;
-
-export const avx2 =
- (arch === "x64" && os === "linux" && isLinuxAVX2()) ||
- (os === "darwin" && isDarwinAVX2());
-
-export type Platform = {
- os: string;
- arch: string;
- avx2?: boolean;
- bin: string;
- exe: string;
-};
-
-export const platforms: Platform[] = [
- {
- os: "darwin",
- arch: "arm64",
- bin: "bun-darwin-aarch64",
- exe: "bin/bun",
- },
- {
- os: "darwin",
- arch: "x64",
- avx2: true,
- bin: "bun-darwin-x64",
- exe: "bin/bun",
- },
- {
- os: "darwin",
- arch: "x64",
- bin: "bun-darwin-x64-baseline",
- exe: "bin/bun",
- },
- {
- os: "linux",
- arch: "arm64",
- bin: "bun-linux-aarch64",
- exe: "bin/bun",
- },
- {
- os: "linux",
- arch: "x64",
- avx2: true,
- bin: "bun-linux-x64",
- exe: "bin/bun",
- },
- {
- os: "linux",
- arch: "x64",
- bin: "bun-linux-x64-baseline",
- exe: "bin/bun",
- },
-];
-
-export const supportedPlatforms: Platform[] = platforms
- .filter(
- (platform) =>
- platform.os === os && platform.arch === arch && (!platform.avx2 || avx2),
- )
- .sort((a, b) => (a.avx2 === b.avx2 ? 0 : a.avx2 ? -1 : 1));
-
-function isLinuxAVX2(): boolean {
- try {
- return read("/proc/cpuinfo").includes("avx2");
- } catch (error) {
- console.debug("isLinuxAVX2 failed", error);
- return false;
- }
-}
-
-function isDarwinAVX2(): boolean {
- try {
- const { exitCode, stdout } = spawn("sysctl", ["-n", "machdep.cpu"]);
- return exitCode === 0 && stdout.includes("AVX2");
- } catch (error) {
- console.debug("isDarwinAVX2 failed", error);
- return false;
- }
-}
-
-function isRosetta2(): boolean {
- try {
- const { exitCode, stdout } = spawn("sysctl", [
- "-n",
- "sysctl.proc_translated",
- ]);
- return exitCode === 0 && stdout.includes("1");
- } catch (error) {
- console.debug("isRosetta2 failed", error);
- return false;
- }
-}
diff --git a/packages/bun-npm/src/util.ts b/packages/bun-npm/src/util.ts
deleted file mode 100644
index e2cf19ee0..000000000
--- a/packages/bun-npm/src/util.ts
+++ /dev/null
@@ -1,212 +0,0 @@
-import fs from "fs";
-import path, { dirname } from "path";
-import { tmpdir } from "os";
-import child_process from "child_process";
-
-if (process.env["DEBUG"] !== "1") {
- console.debug = () => {};
-}
-
-export function join(...paths: (string | string[])[]): string {
- return path.join(...paths.flat(2));
-}
-
-export function tmp(): string {
- const path = fs.mkdtempSync(join(tmpdir(), "bun-"));
- console.debug("tmp", path);
- return path;
-}
-
-export function rm(path: string): void {
- console.debug("rm", path);
- try {
- fs.rmSync(path, { recursive: true });
- return;
- } catch (error) {
- console.debug("rmSync failed", error);
- // Did not exist before Node.js v14.
- // Attempt again with older, slower implementation.
- }
- let stats: fs.Stats;
- try {
- stats = fs.lstatSync(path);
- } catch (error) {
- console.debug("lstatSync failed", error);
- // The file was likely deleted, so return early.
- return;
- }
- if (!stats.isDirectory()) {
- fs.unlinkSync(path);
- return;
- }
- try {
- fs.rmdirSync(path, { recursive: true });
- return;
- } catch (error) {
- console.debug("rmdirSync failed", error);
- // Recursive flag did not exist before Node.js X.
- // Attempt again with older, slower implementation.
- }
- for (const filename of fs.readdirSync(path)) {
- rm(join(path, filename));
- }
- fs.rmdirSync(path);
-}
-
-export function rename(path: string, newPath: string): void {
- console.debug("rename", path, newPath);
- try {
- fs.renameSync(path, newPath);
- return;
- } catch (error) {
- console.debug("renameSync failed", error);
- // If there is an error, delete the new path and try again.
- }
- try {
- rm(newPath);
- } catch (error) {
- console.debug("rm failed", error);
- // The path could have been deleted already.
- }
- fs.renameSync(path, newPath);
-}
-
-export function write(
- path: string,
- content: string | ArrayBuffer | ArrayBufferView,
-): void {
- console.debug("write", path);
- try {
- fs.writeFileSync(path, content);
- return;
- } catch (error) {
- console.debug("writeFileSync failed", error);
- // If there is an error, ensure the parent directory
- // exists and try again.
- try {
- fs.mkdirSync(dirname(path), { recursive: true });
- } catch (error) {
- console.debug("mkdirSync failed", error);
- // The directory could have been created already.
- }
- fs.writeFileSync(path, content);
- }
-}
-
-export function read(path: string): string {
- console.debug("read", path);
- return fs.readFileSync(path, "utf-8");
-}
-
-export function chmod(path: string, mode: fs.Mode): void {
- console.debug("chmod", path, mode);
- fs.chmodSync(path, mode);
-}
-
-export function copy(path: string, newPath: string): void {
- console.debug("copy", path, newPath);
- try {
- fs.copyFileSync(path, newPath);
- return;
- } catch (error) {
- console.debug("copyFileSync failed", error);
- }
- write(newPath, read(path));
-}
-
-export function exists(path: string): boolean {
- console.debug("exists", path);
- try {
- return fs.existsSync(path);
- } catch (error) {
- console.debug("existsSync failed", error);
- }
- return false;
-}
-
-export function spawn(
- cmd: string,
- args: string[],
- options: child_process.SpawnOptions = {},
-): {
- exitCode: number;
- stdout: string;
- stderr: string;
-} {
- console.debug("spawn", [cmd, ...args].join(" "));
- const { status, stdout, stderr } = child_process.spawnSync(cmd, args, {
- stdio: "pipe",
- encoding: "utf-8",
- ...options,
- });
- return {
- exitCode: status ?? 1,
- stdout,
- stderr,
- };
-}
-
-export type Response = {
- readonly status: number;
- arrayBuffer(): Promise<ArrayBuffer>;
- json<T>(): Promise<T>;
-};
-
-export const fetch = "fetch" in globalThis ? webFetch : nodeFetch;
-
-async function webFetch(url: string, assert?: boolean): Promise<Response> {
- const response = await globalThis.fetch(url);
- console.debug("fetch", url, response.status);
- if (assert !== false && !isOk(response.status)) {
- throw new Error(`${response.status}: ${url}`);
- }
- return response;
-}
-
-async function nodeFetch(url: string, assert?: boolean): Promise<Response> {
- const { get } = await import("node:http");
- return new Promise((resolve, reject) => {
- get(url, (response) => {
- console.debug("get", url, response.statusCode);
- const status = response.statusCode ?? 501;
- if (response.headers.location && isRedirect(status)) {
- return nodeFetch(url).then(resolve, reject);
- }
- if (assert !== false && !isOk(status)) {
- return reject(new Error(`${status}: ${url}`));
- }
- const body: Buffer[] = [];
- response.on("data", (chunk) => {
- body.push(chunk);
- });
- response.on("end", () => {
- resolve({
- status,
- async arrayBuffer() {
- return Buffer.concat(body).buffer as ArrayBuffer;
- },
- async json() {
- const text = Buffer.concat(body).toString("utf-8");
- return JSON.parse(text);
- },
- });
- });
- }).on("error", reject);
- });
-}
-
-function isOk(status: number): boolean {
- return status === 200;
-}
-
-function isRedirect(status: number): boolean {
- switch (status) {
- case 301: // Moved Permanently
- case 308: // Permanent Redirect
- case 302: // Found
- case 307: // Temporary Redirect
- case 303: // See Other
- return true;
- }
- return false;
-}