mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
fix(bun-release): support windows in npm package (#9873)
* fix npm install on windows * try again * again * copy less file * revert changes * remove package.json from git * okay * now?
This commit is contained in:
44
.github/workflows/bun-release-test.yml
vendored
Normal file
44
.github/workflows/bun-release-test.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# This workflow tests bun-release's code and the packages to ensure that npm,
|
||||
# yarn, and pnpm can install bun on all platforms. This does not test that bun
|
||||
# itself works as it hardcodes 1.1.0 as the version to package.
|
||||
name: bun-release-test
|
||||
concurrency: release-test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "packages/bun-release/**"
|
||||
- ".github/workflows/bun-release-test.yml"
|
||||
|
||||
jobs:
|
||||
test-release-script:
|
||||
name: Test Release Script
|
||||
strategy:
|
||||
matrix:
|
||||
machine: [namespace-profile-bun-linux-x64, linux-arm64, macos-arm64, macos-12-large, windows-latest]
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.machine }}
|
||||
permissions:
|
||||
contents: read
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/bun-release
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: "1.1.0"
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Install Dependencies
|
||||
run: bun install && npm i -g pnpm yarn npm
|
||||
|
||||
- name: Release
|
||||
run: bun upload-npm -- 1.1.0 test
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -140,4 +140,4 @@ txt.js
|
||||
x64
|
||||
yarn.lock
|
||||
zig-cache
|
||||
zig-out
|
||||
zig-out
|
||||
14
packages/bun-release/.gitignore
vendored
14
packages/bun-release/.gitignore
vendored
@@ -1,6 +1,8 @@
|
||||
.DS_Store
|
||||
.env
|
||||
node_modules
|
||||
/npm/**/bin
|
||||
/npm/**/*.js
|
||||
/npm/**/.npmrc
|
||||
.DS_Store
|
||||
.env
|
||||
node_modules
|
||||
/npm/**/bin
|
||||
/npm/**/*.js
|
||||
/npm/**/package.json
|
||||
/npm/**/.npmrc
|
||||
*.tgz
|
||||
|
||||
Binary file not shown.
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "@oven/bun-darwin-aarch64",
|
||||
"version": "0.5.3",
|
||||
"description": "This is the macOS arm64 binary for Bun, a fast all-in-one JavaScript runtime.",
|
||||
"homepage": "https://bun.sh",
|
||||
"bugs": "https://github.com/oven-sh/issues",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/oven-sh/bun",
|
||||
"preferUnplugged": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "@oven/bun-darwin-x64-baseline",
|
||||
"version": "0.5.3",
|
||||
"description": "This is the macOS x64 binary for Bun, a fast all-in-one JavaScript runtime.",
|
||||
"homepage": "https://bun.sh",
|
||||
"bugs": "https://github.com/oven-sh/issues",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/oven-sh/bun",
|
||||
"preferUnplugged": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "@oven/bun-darwin-x64",
|
||||
"version": "0.5.3",
|
||||
"description": "This is the macOS x64 binary for Bun, a fast all-in-one JavaScript runtime.",
|
||||
"homepage": "https://bun.sh",
|
||||
"bugs": "https://github.com/oven-sh/issues",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/oven-sh/bun",
|
||||
"preferUnplugged": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "@oven/bun-linux-aarch64",
|
||||
"version": "0.5.3",
|
||||
"description": "This is the Linux arm64 binary for Bun, a fast all-in-one JavaScript runtime.",
|
||||
"homepage": "https://bun.sh",
|
||||
"bugs": "https://github.com/oven-sh/issues",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/oven-sh/bun",
|
||||
"preferUnplugged": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "@oven/bun-linux-x64-baseline",
|
||||
"version": "0.5.3",
|
||||
"description": "This is the Linux x64 binary for Bun, a fast all-in-one JavaScript runtime.",
|
||||
"homepage": "https://bun.sh",
|
||||
"bugs": "https://github.com/oven-sh/issues",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/oven-sh/bun",
|
||||
"preferUnplugged": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "@oven/bun-linux-x64",
|
||||
"version": "0.5.3",
|
||||
"description": "This is the Linux x64 binary for Bun, a fast all-in-one JavaScript runtime.",
|
||||
"homepage": "https://bun.sh",
|
||||
"bugs": "https://github.com/oven-sh/issues",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/oven-sh/bun",
|
||||
"preferUnplugged": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Bun
|
||||
|
||||
This is the Windows x64 binary for Bun, a fast all-in-one JavaScript runtime. https://bun.sh
|
||||
|
||||
_Note: "Baseline" builds are for machines that do not support [AVX2](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions) instructions._
|
||||
3
packages/bun-release/npm/@oven/bun-windows-x64/README.md
Normal file
3
packages/bun-release/npm/@oven/bun-windows-x64/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Bun
|
||||
|
||||
This is the Windows x64 binary for Bun, a fast all-in-one JavaScript runtime. https://bun.sh
|
||||
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"name": "bun",
|
||||
"version": "0.5.3",
|
||||
"description": "Bun is a fast all-in-one JavaScript runtime.",
|
||||
"keywords": [
|
||||
"bun",
|
||||
"bun.js",
|
||||
"node",
|
||||
"node.js",
|
||||
"runtime",
|
||||
"bundler",
|
||||
"transpiler",
|
||||
"typescript"
|
||||
],
|
||||
"homepage": "https://bun.sh",
|
||||
"bugs": "https://github.com/oven-sh/issues",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"bun": "bin/bun",
|
||||
"bunx": "bin/bun"
|
||||
},
|
||||
"repository": "https://github.com/oven-sh/bun",
|
||||
"scripts": {
|
||||
"postinstall": "node install.js"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@oven/bun-darwin-aarch64": "0.5.3",
|
||||
"@oven/bun-darwin-x64": "0.5.3",
|
||||
"@oven/bun-darwin-x64-baseline": "0.5.3",
|
||||
"@oven/bun-linux-aarch64": "0.5.3",
|
||||
"@oven/bun-linux-x64": "0.5.3",
|
||||
"@oven/bun-linux-x64-baseline": "0.5.3"
|
||||
},
|
||||
"os": [
|
||||
"darwin",
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64",
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@octokit/types": "^8.1.1",
|
||||
"bun-types": "^0.4.0",
|
||||
"bun-types": "^1.1.0",
|
||||
"prettier": "^2.8.2"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { importBun } from "../src/npm/install";
|
||||
import { importBun, optimizeBun } from "../src/npm/install";
|
||||
import { execFileSync } from "child_process";
|
||||
|
||||
importBun()
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { join, copy, exists, chmod, write, writeJson } from "../src/fs";
|
||||
import { mkdtemp } from "fs/promises";
|
||||
import { rmSync, mkdirSync } from "fs";
|
||||
import { tmpdir } from "os";
|
||||
import { dirname } from "path";
|
||||
import { fetch } from "../src/fetch";
|
||||
import { spawn } from "../src/spawn";
|
||||
import type { Platform } from "../src/platform";
|
||||
@@ -10,41 +14,51 @@ import { buildSync, formatMessagesSync } from "esbuild";
|
||||
import type { JSZipObject } from "jszip";
|
||||
import { loadAsync } from "jszip";
|
||||
import { debug, log, error } from "../src/console";
|
||||
import { expect } from "bun:test";
|
||||
|
||||
const module = "bun";
|
||||
const owner = "@oven";
|
||||
let version: string;
|
||||
|
||||
const [tag, action] = process.argv.slice(2);
|
||||
|
||||
await build(tag);
|
||||
const release = await getRelease(tag);
|
||||
const version = await getSemver(release.tag_name);
|
||||
|
||||
if (action !== "test-only") await build();
|
||||
|
||||
if (action === "publish") {
|
||||
await publish();
|
||||
} else if (action === "dry-run") {
|
||||
await publish(true);
|
||||
} else if (action === "test") {
|
||||
await publish(true);
|
||||
await test();
|
||||
} else if (action === "test-only") {
|
||||
await test();
|
||||
} else if (action) {
|
||||
throw new Error(`Unknown action: ${action}`);
|
||||
}
|
||||
process.exit(0); // HACK
|
||||
|
||||
async function build(tag?: string): Promise<void> {
|
||||
const release = await getRelease(tag);
|
||||
version = await getSemver(release.tag_name);
|
||||
async function build(): Promise<void> {
|
||||
await buildRootModule();
|
||||
for (const platform of platforms) {
|
||||
if (action !== "publish" && (platform.os !== process.platform || platform.arch !== process.arch)) continue;
|
||||
await buildModule(release, platform);
|
||||
}
|
||||
}
|
||||
|
||||
async function publish(dryRun?: boolean): Promise<void> {
|
||||
const modules = platforms.map(({ bin }) => `${owner}/${bin}`);
|
||||
const modules = platforms
|
||||
.filter(({ os, arch }) => action === "publish" || (os === process.platform && arch === process.arch))
|
||||
.map(({ bin }) => `${owner}/${bin}`);
|
||||
modules.push(module);
|
||||
for (const module of modules) {
|
||||
publishModule(module, dryRun);
|
||||
}
|
||||
}
|
||||
|
||||
async function buildRootModule() {
|
||||
async function buildRootModule(dryRun?: boolean) {
|
||||
log("Building:", `${module}@${version}`);
|
||||
const cwd = join("npm", module);
|
||||
const define = {
|
||||
@@ -54,28 +68,53 @@ async function buildRootModule() {
|
||||
};
|
||||
bundle(join("scripts", "npm-postinstall.ts"), join(cwd, "install.js"), {
|
||||
define,
|
||||
});
|
||||
bundle(join("scripts", "npm-exec.ts"), join(cwd, "bin", "bun"), {
|
||||
define,
|
||||
banner: {
|
||||
js: "#!/usr/bin/env node",
|
||||
js: "// Source code: https://github.com/oven-sh/bun/blob/main/packages/bun-release/scripts/npm-postinstall.ts",
|
||||
},
|
||||
});
|
||||
write(join(cwd, "bin", "bun.exe"), "");
|
||||
write(
|
||||
join(cwd, "bin", "README.txt"),
|
||||
`The 'bun.exe' file is a placeholder for the binary file, which
|
||||
is replaced by Bun's 'postinstall' script. For this to work, make
|
||||
sure that you do not use --ignore-scripts while installing.
|
||||
|
||||
The postinstall script is responsible for linking the binary file
|
||||
directly into 'node_modules/.bin' and avoiding a Node.js wrapper
|
||||
script being called on every invocation of 'bun'. If this wasn't
|
||||
done, Bun would seem to be slower than Node.js, because it would
|
||||
be executing a copy of Node.js every time!
|
||||
|
||||
Unfortunately, it is not possible to fix all cases on all platforms
|
||||
without *requiring* a postinstall script.
|
||||
`,
|
||||
);
|
||||
const os = [...new Set(platforms.map(({ os }) => os))];
|
||||
const cpu = [...new Set(platforms.map(({ arch }) => arch))];
|
||||
writeJson(join(cwd, "package.json"), {
|
||||
name: module,
|
||||
description: "Bun is a fast all-in-one JavaScript runtime.",
|
||||
version: version,
|
||||
scripts: {
|
||||
postinstall: "node install.js",
|
||||
},
|
||||
optionalDependencies: Object.fromEntries(platforms.map(({ bin }) => [`${owner}/${bin}`, version])),
|
||||
optionalDependencies: Object.fromEntries(
|
||||
platforms.map(({ bin }) => [
|
||||
`${owner}/${bin}`,
|
||||
dryRun ? `file:./oven-${bin.replaceAll("/", "-") + "-" + version + ".tgz"}` : version,
|
||||
]),
|
||||
),
|
||||
bin: {
|
||||
bun: "bin/bun",
|
||||
bunx: "bin/bun",
|
||||
bun: "bin/bun.exe",
|
||||
bunx: "bin/bun.exe",
|
||||
},
|
||||
os,
|
||||
cpu,
|
||||
keywords: ["bun", "bun.js", "node", "node.js", "runtime", "bundler", "transpiler", "typescript"],
|
||||
homepage: "https://bun.sh",
|
||||
bugs: "https://github.com/oven-sh/issues",
|
||||
license: "MIT",
|
||||
repository: "https://github.com/oven-sh/bun",
|
||||
});
|
||||
if (exists(".npmrc")) {
|
||||
copy(".npmrc", join(cwd, ".npmrc"));
|
||||
@@ -95,11 +134,17 @@ async function buildModule(
|
||||
}
|
||||
const bun = await extractFromZip(asset.browser_download_url, `${bin}/bun`);
|
||||
const cwd = join("npm", module);
|
||||
mkdirSync(dirname(join(cwd, exe)), { recursive: true });
|
||||
write(join(cwd, exe), await bun.async("arraybuffer"));
|
||||
chmod(join(cwd, exe), 0o755);
|
||||
writeJson(join(cwd, "package.json"), {
|
||||
name: module,
|
||||
version: version,
|
||||
description: "This is the macOS arm64 binary for Bun, a fast all-in-one JavaScript runtime.",
|
||||
homepage: "https://bun.sh",
|
||||
bugs: "https://github.com/oven-sh/issues",
|
||||
license: "MIT",
|
||||
repository: "https://github.com/oven-sh/bun",
|
||||
preferUnplugged: true,
|
||||
os: [os],
|
||||
cpu: [arch],
|
||||
@@ -111,22 +156,33 @@ async function buildModule(
|
||||
|
||||
function publishModule(name: string, dryRun?: boolean): void {
|
||||
log(dryRun ? "Dry-run Publishing:" : "Publishing:", `${name}@${version}`);
|
||||
const { exitCode, stdout, stderr } = spawn(
|
||||
"npm",
|
||||
[
|
||||
"publish",
|
||||
"--access",
|
||||
"public",
|
||||
"--tag",
|
||||
version.includes("canary") ? "canary" : "latest",
|
||||
...(dryRun ? ["--dry-run"] : []),
|
||||
],
|
||||
{
|
||||
cwd: join("npm", name),
|
||||
},
|
||||
);
|
||||
if (exitCode === 0) {
|
||||
if (!dryRun) {
|
||||
const { exitCode, stdout, stderr } = spawn(
|
||||
"npm",
|
||||
[
|
||||
"publish",
|
||||
"--access",
|
||||
"public",
|
||||
"--tag",
|
||||
version.includes("canary") ? "canary" : "latest",
|
||||
...(dryRun ? ["--dry-run"] : []),
|
||||
],
|
||||
{
|
||||
cwd: join("npm", name),
|
||||
},
|
||||
);
|
||||
error(stderr || stdout);
|
||||
if (exitCode !== 0) {
|
||||
throw new Error("npm publish failed with code " + exitCode);
|
||||
}
|
||||
} else {
|
||||
const { exitCode, stdout, stderr } = spawn("npm", ["pack"], {
|
||||
cwd: join("npm", name),
|
||||
});
|
||||
error(stderr || stdout);
|
||||
if (exitCode !== 0) {
|
||||
throw new Error("npm pack failed with code " + exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,3 +218,86 @@ function bundle(src: string, dst: string, options: BuildOptions = {}): void {
|
||||
throw new Error(messages.join("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
async function test() {
|
||||
const root = await mkdtemp(join(tmpdir(), "bun-release-test-"));
|
||||
const $ = new Bun.$.Shell().cwd(root);
|
||||
|
||||
for (const platform of platforms) {
|
||||
if (platform.os !== process.platform) continue;
|
||||
if (platform.arch !== process.arch) continue;
|
||||
copy(
|
||||
join(
|
||||
import.meta.dir,
|
||||
"../npm/@oven/",
|
||||
platform.bin,
|
||||
"oven-" + platform.bin.replaceAll("/", "-") + `-${version}.tgz`,
|
||||
),
|
||||
join(root, `${platform.bin}-${version}.tgz`),
|
||||
);
|
||||
}
|
||||
|
||||
copy(join(import.meta.dir, "../npm", "bun", "bun-" + version + ".tgz"), join(root, "bun-" + version + ".tgz"));
|
||||
|
||||
console.log(root);
|
||||
for (const [install, exec] of [
|
||||
["npm i", "npm exec"],
|
||||
["yarn set version berry; yarn add", "yarn"],
|
||||
["yarn set version latest; yarn add", "yarn"],
|
||||
["pnpm i", "pnpm"],
|
||||
["bun i", "bun run"],
|
||||
]) {
|
||||
rmSync(join(root, "node_modules"), { recursive: true, force: true });
|
||||
rmSync(join(root, "package-lock.json"), { recursive: true, force: true });
|
||||
rmSync(join(root, "package.json"), { recursive: true, force: true });
|
||||
rmSync(join(root, "pnpm-lock.yaml"), { recursive: true, force: true });
|
||||
rmSync(join(root, "yarn.lock"), { recursive: true, force: true });
|
||||
writeJson(join(root, "package.json"), {
|
||||
name: "bun-release-test",
|
||||
});
|
||||
|
||||
console.log("Testing", install + " bun");
|
||||
await $`${{ raw: install }} ./bun-${version}.tgz`;
|
||||
|
||||
console.log("Running " + exec + " bun");
|
||||
|
||||
// let output = await $`${{
|
||||
// raw: exec,
|
||||
// }} bun -- -e "console.log(JSON.stringify([Bun.version, process.platform, process.arch, process.execPath]))"`.text();
|
||||
const split = exec.split(" ");
|
||||
let {
|
||||
stdout: output,
|
||||
stderr,
|
||||
exitCode,
|
||||
} = spawn(
|
||||
split[0],
|
||||
[
|
||||
...split.slice(1),
|
||||
"--",
|
||||
"bun",
|
||||
"-e",
|
||||
"console.log(JSON.stringify([Bun.version, process.platform, process.arch, process.execPath]))",
|
||||
],
|
||||
{
|
||||
cwd: root,
|
||||
},
|
||||
);
|
||||
if (exitCode !== 0) {
|
||||
console.error(stderr);
|
||||
throw new Error("Failed to run " + exec + " bun, exit code: " + exitCode);
|
||||
}
|
||||
|
||||
try {
|
||||
output = JSON.parse(output);
|
||||
} catch (e) {
|
||||
console.log({ output });
|
||||
throw e;
|
||||
}
|
||||
|
||||
expect(output[0]).toBe(version);
|
||||
expect(output[1]).toBe(process.platform);
|
||||
expect(output[2]).toBe(process.arch);
|
||||
expect(output[3]).toStartWith(root);
|
||||
expect(output[3]).toInclude("bun");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,16 +121,9 @@ async function downloadBun(platform: Platform, dst: string): Promise<void> {
|
||||
}
|
||||
|
||||
export function optimizeBun(path: string): void {
|
||||
const installScript =
|
||||
os === "win32" ? 'powershell -c "irm bun.sh/install.ps1 | iex"' : "curl -fsSL https://bun.sh/install | bash";
|
||||
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: ${installScript}`,
|
||||
);
|
||||
}
|
||||
const installScript = os === "win32" ? 'powershell -c "irm bun.sh/install.ps1 | iex"' : "curl -fsSL https://bun.sh/install | bash";
|
||||
try {
|
||||
rename(path, join(__dirname, "bin", "bun"));
|
||||
rename(path, join(__dirname, "bin", "bun.exe"));
|
||||
return;
|
||||
} catch (error) {
|
||||
debug("optimizeBun failed", error);
|
||||
|
||||
@@ -106,6 +106,15 @@ function isRosetta2(): boolean {
|
||||
}
|
||||
|
||||
function isWindowsAVX2(): boolean {
|
||||
// TODO: Implement AVX2 detection on Windows
|
||||
return false;
|
||||
try {
|
||||
return (
|
||||
spawn("powershell", [
|
||||
"-c",
|
||||
`(Add-Type -MemberDefinition '[DllImport("kernel32.dll")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);' -Name 'Kernel32' -Namespace 'Win32' -PassThru)::IsProcessorFeaturePresent(40);`,
|
||||
]).stdout == "True"
|
||||
);
|
||||
} catch (error) {
|
||||
debug("isWindowsAVX2 failed", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user