mirror of
https://github.com/oven-sh/bun
synced 2026-02-16 22:01:47 +00:00
Compare commits
104 Commits
claude/fix
...
dylan/nati
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56c16ef6cf | ||
|
|
1f3b213f51 | ||
|
|
139825309e | ||
|
|
eb6f5e76b9 | ||
|
|
f7767b4f43 | ||
|
|
ee0aed4836 | ||
|
|
457ccf227f | ||
|
|
deed9b507d | ||
|
|
e898511c40 | ||
|
|
88a317a0c0 | ||
|
|
808334982f | ||
|
|
5590cd7d47 | ||
|
|
b4908e7415 | ||
|
|
1c2ecc63e9 | ||
|
|
08b348935d | ||
|
|
1880201027 | ||
|
|
ac226ed93d | ||
|
|
f21e99a8dc | ||
|
|
e739d3e0ac | ||
|
|
f6f75ce393 | ||
|
|
f00eed8c6d | ||
|
|
1f1118940a | ||
|
|
e10529e4ae | ||
|
|
f4e9cdef6f | ||
|
|
8e9aeb7ad4 | ||
|
|
f1539f843e | ||
|
|
aa098cfa6b | ||
|
|
8f37779b8f | ||
|
|
04528baa4a | ||
|
|
f5fe6da89a | ||
|
|
cd3734895d | ||
|
|
e477c3a33b | ||
|
|
34c893a3ed | ||
|
|
8d34a9303c | ||
|
|
cb23d5ced0 | ||
|
|
a44351d839 | ||
|
|
71a5a1bf4d | ||
|
|
288b247f11 | ||
|
|
da3246fd6b | ||
|
|
85607af74f | ||
|
|
4d3425702f | ||
|
|
be321246fb | ||
|
|
0620e2dba3 | ||
|
|
e9454881eb | ||
|
|
d208189f17 | ||
|
|
57a7345a39 | ||
|
|
4ec90d886b | ||
|
|
7a0c9047be | ||
|
|
632b5bb2e8 | ||
|
|
0cefa2c753 | ||
|
|
24e3598d2b | ||
|
|
4f0546f919 | ||
|
|
928fc7888b | ||
|
|
1980c8e12a | ||
|
|
d55d35acc7 | ||
|
|
d75f4e1135 | ||
|
|
c999c5a24d | ||
|
|
684d577d14 | ||
|
|
9546b6d395 | ||
|
|
fed0567860 | ||
|
|
4056e5927f | ||
|
|
3313ff96b8 | ||
|
|
a82cf004dd | ||
|
|
48c0d5d3b5 | ||
|
|
346d662547 | ||
|
|
4846534f00 | ||
|
|
ecd6d8ea68 | ||
|
|
58e5724a9b | ||
|
|
4aafb2a29f | ||
|
|
76c2b12821 | ||
|
|
35c00e250d | ||
|
|
899f08a58d | ||
|
|
34f4ecfcc8 | ||
|
|
83d1c92cda | ||
|
|
00589c3215 | ||
|
|
ef5f9adb2c | ||
|
|
60e21aea92 | ||
|
|
1de01eefd4 | ||
|
|
6c0a4b3fa1 | ||
|
|
6897c110c0 | ||
|
|
e84f625569 | ||
|
|
36944ee646 | ||
|
|
4790197d1d | ||
|
|
a118ed1851 | ||
|
|
44defe3c43 | ||
|
|
582bf80c6c | ||
|
|
65af35706b | ||
|
|
5246c7ab27 | ||
|
|
82e279f894 | ||
|
|
0358db543a | ||
|
|
9716a815de | ||
|
|
df34cecd6b | ||
|
|
4bfd1562b8 | ||
|
|
4631e9cd4b | ||
|
|
130a55de48 | ||
|
|
b93c216e92 | ||
|
|
7353a01312 | ||
|
|
cab53d74d2 | ||
|
|
eff4c098b1 | ||
|
|
fd07535f4e | ||
|
|
435f5842ce | ||
|
|
1cbd606db2 | ||
|
|
ab0d5cdd78 | ||
|
|
5b69da3111 |
@@ -99,6 +99,23 @@ function getTargetLabel(target) {
|
||||
* @property {string[]} [features]
|
||||
*/
|
||||
|
||||
// Azure VM sizes for Windows CI runners.
|
||||
// DDSv6 = x64, DPSv6 = ARM64 (Cobalt 100). Quota: 100 cores per family in eastus2.
|
||||
const azureVmSizes = {
|
||||
"windows-x64": {
|
||||
build: "Standard_D16ds_v6", // 16 vCPU, 64 GiB — C++ build, link
|
||||
test: "Standard_D4ds_v6", // 4 vCPU, 16 GiB — test shards
|
||||
},
|
||||
"windows-aarch64": {
|
||||
build: "Standard_D16ps_v6", // 16 vCPU, 64 GiB — C++ build, link
|
||||
test: "Standard_D4ps_v6", // 4 vCPU, 16 GiB — test shards
|
||||
},
|
||||
};
|
||||
|
||||
function getAzureVmSize(os, arch, tier = "build") {
|
||||
return azureVmSizes[`${os}-${arch}`]?.[tier];
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Platform[]}
|
||||
*/
|
||||
@@ -114,8 +131,7 @@ const buildPlatforms = [
|
||||
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.23" },
|
||||
{ os: "windows", arch: "x64", release: "2019" },
|
||||
{ os: "windows", arch: "x64", baseline: true, release: "2019" },
|
||||
// TODO: Re-enable when Windows ARM64 VS component installation is resolved on Buildkite runners
|
||||
// { os: "windows", arch: "aarch64", release: "2019" },
|
||||
{ os: "windows", arch: "aarch64", release: "11" },
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -138,8 +154,7 @@ const testPlatforms = [
|
||||
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.23", tier: "latest" },
|
||||
{ os: "windows", arch: "x64", release: "2019", tier: "oldest" },
|
||||
{ os: "windows", arch: "x64", release: "2019", baseline: true, tier: "oldest" },
|
||||
// TODO: Enable when Windows ARM64 CI runners are ready
|
||||
// { os: "windows", arch: "aarch64", release: "2019", tier: "oldest" },
|
||||
{ os: "windows", arch: "aarch64", release: "11", tier: "latest" },
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -304,15 +319,8 @@ function getCppAgent(platform, options) {
|
||||
};
|
||||
}
|
||||
|
||||
// Cross-compile Windows ARM64 from x64 runners
|
||||
if (os === "windows" && arch === "aarch64") {
|
||||
return getEc2Agent({ ...platform, arch: "x64" }, options, {
|
||||
instanceType: "c7i.4xlarge",
|
||||
});
|
||||
}
|
||||
|
||||
return getEc2Agent(platform, options, {
|
||||
instanceType: arch === "aarch64" ? "c8g.4xlarge" : "c7i.4xlarge",
|
||||
instanceType: os === "windows" ? getAzureVmSize(os, arch) : arch === "aarch64" ? "c8g.4xlarge" : "c7i.4xlarge",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -333,10 +341,8 @@ function getLinkBunAgent(platform, options) {
|
||||
}
|
||||
|
||||
if (os === "windows") {
|
||||
// Cross-compile Windows ARM64 from x64 runners
|
||||
const agentPlatform = arch === "aarch64" ? { ...platform, arch: "x64" } : platform;
|
||||
return getEc2Agent(agentPlatform, options, {
|
||||
instanceType: "r7i.large",
|
||||
return getEc2Agent(platform, options, {
|
||||
instanceType: getAzureVmSize(os, arch),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -363,7 +369,17 @@ function getZigPlatform() {
|
||||
* @param {PipelineOptions} options
|
||||
* @returns {Agent}
|
||||
*/
|
||||
function getZigAgent(_platform, options) {
|
||||
function getZigAgent(platform, options) {
|
||||
const { os, arch } = platform;
|
||||
|
||||
// Windows builds Zig natively on Azure
|
||||
if (os === "windows") {
|
||||
return getEc2Agent(platform, options, {
|
||||
instanceType: getAzureVmSize(os, arch),
|
||||
});
|
||||
}
|
||||
|
||||
// Everything else cross-compiles from Linux aarch64
|
||||
return getEc2Agent(getZigPlatform(), options, {
|
||||
instanceType: "r8g.large",
|
||||
});
|
||||
@@ -388,7 +404,7 @@ function getTestAgent(platform, options) {
|
||||
// TODO: delete this block when we upgrade to mimalloc v3
|
||||
if (os === "windows") {
|
||||
return getEc2Agent(platform, options, {
|
||||
instanceType: "c7i.2xlarge",
|
||||
instanceType: getAzureVmSize(os, arch, "test"),
|
||||
cpuCount: 2,
|
||||
threadsPerCore: 1,
|
||||
});
|
||||
@@ -465,17 +481,6 @@ function getBuildCommand(target, options, label) {
|
||||
return `bun run build:${buildProfile}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extra flags needed when cross-compiling Windows ARM64 from x64.
|
||||
* Applied to C++ and link steps (not Zig, which has its own toolchain handling).
|
||||
*/
|
||||
function getWindowsArm64CrossFlags(target) {
|
||||
if (target.os === "windows" && target.arch === "aarch64") {
|
||||
return " --toolchain windows-aarch64";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Platform} platform
|
||||
* @param {PipelineOptions} options
|
||||
@@ -483,7 +488,6 @@ function getWindowsArm64CrossFlags(target) {
|
||||
*/
|
||||
function getBuildCppStep(platform, options) {
|
||||
const command = getBuildCommand(platform, options);
|
||||
const crossFlags = getWindowsArm64CrossFlags(platform);
|
||||
|
||||
return {
|
||||
key: `${getTargetKey(platform)}-build-cpp`,
|
||||
@@ -498,7 +502,7 @@ function getBuildCppStep(platform, options) {
|
||||
// We used to build the C++ dependencies and bun in separate steps.
|
||||
// However, as long as the zig build takes longer than both sequentially,
|
||||
// it's cheaper to run them in the same step. Can be revisited in the future.
|
||||
command: [`${command}${crossFlags} --target bun`, `${command}${crossFlags} --target dependencies`],
|
||||
command: [`${command} --target bun`, `${command} --target dependencies`],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -524,7 +528,10 @@ function getBuildToolchain(target) {
|
||||
* @returns {Step}
|
||||
*/
|
||||
function getBuildZigStep(platform, options) {
|
||||
const { os, arch } = platform;
|
||||
const toolchain = getBuildToolchain(platform);
|
||||
// Native Windows builds don't need a cross-compilation toolchain
|
||||
const toolchainArg = os === "windows" ? "" : ` --toolchain ${toolchain}`;
|
||||
return {
|
||||
key: `${getTargetKey(platform)}-build-zig`,
|
||||
retry: getRetry(),
|
||||
@@ -532,7 +539,7 @@ function getBuildZigStep(platform, options) {
|
||||
agents: getZigAgent(platform, options),
|
||||
cancel_on_build_failing: isMergeQueue(),
|
||||
env: getBuildEnv(platform, options),
|
||||
command: `${getBuildCommand(platform, options)} --target bun-zig --toolchain ${toolchain}`,
|
||||
command: `${getBuildCommand(platform, options)} --target bun-zig${toolchainArg}`,
|
||||
timeout_in_minutes: 35,
|
||||
};
|
||||
}
|
||||
@@ -555,7 +562,7 @@ function getLinkBunStep(platform, options) {
|
||||
ASAN_OPTIONS: "allow_user_segv_handler=1:disable_coredump=0:detect_leaks=0",
|
||||
...getBuildEnv(platform, options),
|
||||
},
|
||||
command: `${getBuildCommand(platform, options, "build-bun")}${getWindowsArm64CrossFlags(platform)} --target bun`,
|
||||
command: `${getBuildCommand(platform, options, "build-bun")} --target bun`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -717,14 +724,14 @@ function getTestBunStep(platform, options, testOptions = {}) {
|
||||
agents: getTestAgent(platform, options),
|
||||
retry: getRetry(),
|
||||
cancel_on_build_failing: isMergeQueue(),
|
||||
parallelism: os === "darwin" ? 2 : 20,
|
||||
parallelism: os === "darwin" ? 2 : os === "windows" ? 8 : 20,
|
||||
timeout_in_minutes: profile === "asan" || os === "windows" ? 45 : 30,
|
||||
env: {
|
||||
ASAN_OPTIONS: "allow_user_segv_handler=1:disable_coredump=0:detect_leaks=0",
|
||||
},
|
||||
command:
|
||||
os === "windows"
|
||||
? `node .\\scripts\\runner.node.mjs ${args.join(" ")}`
|
||||
? `pwsh -NoProfile -File .\\scripts\\vs-shell.ps1 node .\\scripts\\runner.node.mjs ${args.join(" ")}`
|
||||
: `./scripts/runner.node.mjs ${args.join(" ")}`,
|
||||
};
|
||||
}
|
||||
@@ -739,6 +746,7 @@ function getBuildImageStep(platform, options) {
|
||||
const { publishImages } = options;
|
||||
const action = publishImages ? "publish-image" : "create-image";
|
||||
|
||||
const cloud = os === "windows" ? "azure" : "aws";
|
||||
const command = [
|
||||
"node",
|
||||
"./scripts/machine.mjs",
|
||||
@@ -747,7 +755,7 @@ function getBuildImageStep(platform, options) {
|
||||
`--arch=${arch}`,
|
||||
distro && `--distro=${distro}`,
|
||||
`--release=${release}`,
|
||||
"--cloud=aws",
|
||||
`--cloud=${cloud}`,
|
||||
"--ci",
|
||||
"--authorized-org=oven-sh",
|
||||
];
|
||||
@@ -1169,9 +1177,10 @@ async function getPipelineOptions() {
|
||||
skipBuilds: parseOption(/\[(skip builds?|no builds?|only tests?)\]/i),
|
||||
forceBuilds: parseOption(/\[(force builds?)\]/i),
|
||||
skipTests: parseOption(/\[(skip tests?|no tests?|only builds?)\]/i),
|
||||
buildImages: parseOption(/\[(build images?)\]/i),
|
||||
buildImages: parseOption(/\[(build (?:(?:windows|linux) )?images?)\]/i),
|
||||
dryRun: parseOption(/\[(dry run)\]/i),
|
||||
publishImages: parseOption(/\[(publish images?)\]/i),
|
||||
publishImages: parseOption(/\[(publish (?:(?:windows|linux) )?images?)\]/i),
|
||||
imageFilter: (commitMessage.match(/\[(?:build|publish) (windows|linux) images?\]/i) || [])[1]?.toLowerCase(),
|
||||
buildPlatforms: Array.from(buildPlatformsMap.values()),
|
||||
testPlatforms: Array.from(testPlatformsMap.values()),
|
||||
};
|
||||
@@ -1196,13 +1205,12 @@ async function getPipeline(options = {}) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { buildPlatforms = [], testPlatforms = [], buildImages, publishImages } = options;
|
||||
const { buildPlatforms = [], testPlatforms = [], buildImages, publishImages, imageFilter } = options;
|
||||
const imagePlatforms = new Map(
|
||||
buildImages || publishImages
|
||||
? [...buildPlatforms, ...testPlatforms]
|
||||
.filter(({ os }) => os !== "darwin")
|
||||
// Windows ARM64 cross-compiles from x64 runners, no separate image needed
|
||||
.filter(({ os, arch }) => !(os === "windows" && arch === "aarch64"))
|
||||
.filter(({ os, distro }) => !imageFilter || os === imageFilter || distro === imageFilter)
|
||||
.map(platform => [getImageKey(platform), platform])
|
||||
: [],
|
||||
);
|
||||
|
||||
25
CLAUDE.md
25
CLAUDE.md
@@ -161,6 +161,31 @@ test("(multi-file test) my feature", async () => {
|
||||
- `src/sql/` - SQL database integrations
|
||||
- `src/bake/` - Server-side rendering framework
|
||||
|
||||
#### Vendored Dependencies (`vendor/`)
|
||||
|
||||
Third-party C/C++ libraries are vendored locally and can be read from disk:
|
||||
|
||||
- `vendor/boringssl/` - BoringSSL (TLS/crypto)
|
||||
- `vendor/brotli/` - Brotli compression
|
||||
- `vendor/cares/` - c-ares (async DNS)
|
||||
- `vendor/hdrhistogram/` - HdrHistogram (latency tracking)
|
||||
- `vendor/highway/` - Google Highway (SIMD)
|
||||
- `vendor/libarchive/` - libarchive (tar/zip)
|
||||
- `vendor/libdeflate/` - libdeflate (fast deflate)
|
||||
- `vendor/libuv/` - libuv (Windows event loop)
|
||||
- `vendor/lolhtml/` - lol-html (HTML rewriter)
|
||||
- `vendor/lshpack/` - ls-hpack (HTTP/2 HPACK)
|
||||
- `vendor/mimalloc/` - mimalloc (memory allocator)
|
||||
- `vendor/nodejs/` - Node.js headers (compatibility)
|
||||
- `vendor/picohttpparser/` - PicoHTTPParser (HTTP parsing)
|
||||
- `vendor/tinycc/` - TinyCC (FFI JIT compiler, fork: oven-sh/tinycc)
|
||||
- `vendor/WebKit/` - WebKit/JavaScriptCore (JS engine)
|
||||
- `vendor/zig/` - Zig compiler/stdlib
|
||||
- `vendor/zlib/` - zlib (compression, cloudflare fork)
|
||||
- `vendor/zstd/` - Zstandard (compression)
|
||||
|
||||
Build configuration for these is in `cmake/targets/Build*.cmake`.
|
||||
|
||||
### JavaScript Class Implementation (C++)
|
||||
|
||||
When implementing JavaScript classes in C++:
|
||||
|
||||
@@ -434,7 +434,7 @@ function(register_command)
|
||||
endif()
|
||||
|
||||
# SKIP_CODEGEN: Skip commands that use BUN_EXECUTABLE if all outputs exist
|
||||
# This is used for Windows ARM64 builds where x64 bun crashes under emulation
|
||||
# Useful for bootstrapping new platforms where bun may not be available
|
||||
if(SKIP_CODEGEN AND CMD_EXECUTABLE STREQUAL "${BUN_EXECUTABLE}")
|
||||
set(ALL_OUTPUTS_EXIST TRUE)
|
||||
foreach(output ${CMD_OUTPUTS})
|
||||
@@ -456,7 +456,7 @@ function(register_command)
|
||||
endif()
|
||||
return()
|
||||
else()
|
||||
message(FATAL_ERROR "SKIP_CODEGEN: Cannot skip ${CMD_TARGET} - missing outputs. Run codegen on x64 first.")
|
||||
message(FATAL_ERROR "SKIP_CODEGEN: Cannot skip ${CMD_TARGET} - missing outputs.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -831,13 +831,6 @@ function(register_cmake_command)
|
||||
list(APPEND MAKE_EFFECTIVE_ARGS "-DCMAKE_${flag}=${MAKE_${flag}}")
|
||||
endforeach()
|
||||
|
||||
# Workaround for CMake 4.1.0 bug: Force correct machine type for Windows ARM64
|
||||
# Use toolchain file and set CMP0197 policy to prevent duplicate /machine: flags
|
||||
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|AARCH64")
|
||||
list(APPEND MAKE_EFFECTIVE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CWD}/cmake/toolchains/windows-aarch64.cmake")
|
||||
list(APPEND MAKE_EFFECTIVE_ARGS "-DCMAKE_POLICY_DEFAULT_CMP0197=NEW")
|
||||
list(APPEND MAKE_EFFECTIVE_ARGS "-DCMAKE_PROJECT_INCLUDE=${CWD}/cmake/arm64-static-lib-fix.cmake")
|
||||
endif()
|
||||
|
||||
if(DEFINED FRESH)
|
||||
list(APPEND MAKE_EFFECTIVE_ARGS --fresh)
|
||||
|
||||
@@ -4,7 +4,7 @@ endif()
|
||||
|
||||
optionx(BUN_LINK_ONLY BOOL "If only the linking step should be built" DEFAULT OFF)
|
||||
optionx(BUN_CPP_ONLY BOOL "If only the C++ part of Bun should be built" DEFAULT OFF)
|
||||
optionx(SKIP_CODEGEN BOOL "Skip JavaScript codegen (for Windows ARM64 debug)" DEFAULT OFF)
|
||||
optionx(SKIP_CODEGEN BOOL "Skip JavaScript codegen (useful for bootstrapping new platforms)" DEFAULT OFF)
|
||||
|
||||
optionx(BUILDKITE BOOL "If Buildkite is enabled" DEFAULT OFF)
|
||||
optionx(GITHUB_ACTIONS BOOL "If GitHub Actions is enabled" DEFAULT OFF)
|
||||
@@ -58,18 +58,6 @@ else()
|
||||
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
# CMake 4.0+ policy CMP0197 controls how MSVC machine type flags are handled
|
||||
# Setting to NEW prevents duplicate /machine: flags being added to linker commands
|
||||
if(WIN32 AND ARCH STREQUAL "aarch64")
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0197 NEW)
|
||||
set(CMAKE_MSVC_CMP0197 NEW)
|
||||
# Set linker flags for exe/shared linking
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /machine:ARM64")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /machine:ARM64")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /machine:ARM64")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /machine:ARM64")
|
||||
endif()
|
||||
|
||||
# Windows Code Signing Option
|
||||
if(WIN32)
|
||||
optionx(ENABLE_WINDOWS_CODESIGNING BOOL "Enable Windows code signing with DigiCert KeyLocker" DEFAULT OFF)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# This file is included after project() via CMAKE_PROJECT_INCLUDE
|
||||
# It fixes the static library creation command to use ARM64 machine type
|
||||
|
||||
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL \"aarch64\")
|
||||
# Override the static library creation commands to avoid spurious /machine:x64 flags
|
||||
set(CMAKE_C_CREATE_STATIC_LIBRARY \"<CMAKE_AR> /nologo /machine:ARM64 /out:<TARGET> <OBJECTS>\" CACHE STRING \"\" FORCE)
|
||||
set(CMAKE_CXX_CREATE_STATIC_LIBRARY \"<CMAKE_AR> /nologo /machine:ARM64 /out:<TARGET> <OBJECTS>\" CACHE STRING \"\" FORCE)
|
||||
endif()
|
||||
@@ -21,12 +21,7 @@ if(NOT DEFINED CMAKE_HOST_SYSTEM_PROCESSOR)
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm64|ARM64|aarch64|AARCH64")
|
||||
# Windows ARM64 can run x86_64 via emulation, and no native ARM64 Zig build exists yet
|
||||
if(CMAKE_HOST_WIN32)
|
||||
set(ZIG_ARCH "x86_64")
|
||||
else()
|
||||
set(ZIG_ARCH "aarch64")
|
||||
endif()
|
||||
set(ZIG_ARCH "aarch64")
|
||||
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|AMD64|x86_64|X86_64|x64|X64")
|
||||
set(ZIG_ARCH "x86_64")
|
||||
else()
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM Wrapper for llvm-lib that strips conflicting /machine:x64 flag for ARM64 builds
|
||||
REM This is a workaround for CMake 4.1.0 bug
|
||||
|
||||
REM Find llvm-lib.exe - check LLVM_LIB env var, then PATH, then known locations
|
||||
if defined LLVM_LIB (
|
||||
set "LLVM_LIB_EXE=!LLVM_LIB!"
|
||||
) else (
|
||||
where llvm-lib.exe >nul 2>&1
|
||||
if !ERRORLEVEL! equ 0 (
|
||||
for /f "delims=" %%i in ('where llvm-lib.exe') do set "LLVM_LIB_EXE=%%i"
|
||||
) else if exist "C:\Program Files\LLVM\bin\llvm-lib.exe" (
|
||||
set "LLVM_LIB_EXE=C:\Program Files\LLVM\bin\llvm-lib.exe"
|
||||
) else (
|
||||
echo Error: Cannot find llvm-lib.exe. Set LLVM_LIB environment variable or add LLVM to PATH.
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
set "ARGS="
|
||||
|
||||
for %%a in (%*) do (
|
||||
set "ARG=%%a"
|
||||
if /i "!ARG!"=="/machine:x64" (
|
||||
REM Skip this argument
|
||||
) else (
|
||||
set "ARGS=!ARGS! %%a"
|
||||
)
|
||||
)
|
||||
|
||||
"!LLVM_LIB_EXE!" %ARGS%
|
||||
exit /b %ERRORLEVEL%
|
||||
@@ -1,18 +0,0 @@
|
||||
# Wrapper for llvm-lib that strips conflicting /machine:x64 flag for ARM64 builds
|
||||
# This is a workaround for CMake 4.1.0 bug where both /machine:ARM64 and /machine:x64 are added
|
||||
|
||||
# Find llvm-lib.exe - check LLVM_LIB env var, then PATH, then known locations
|
||||
if ($env:LLVM_LIB) {
|
||||
$llvmLib = $env:LLVM_LIB
|
||||
} elseif (Get-Command llvm-lib.exe -ErrorAction SilentlyContinue) {
|
||||
$llvmLib = (Get-Command llvm-lib.exe).Source
|
||||
} elseif (Test-Path "C:\Program Files\LLVM\bin\llvm-lib.exe") {
|
||||
$llvmLib = "C:\Program Files\LLVM\bin\llvm-lib.exe"
|
||||
} else {
|
||||
Write-Error "Cannot find llvm-lib.exe. Set LLVM_LIB environment variable or add LLVM to PATH."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$filteredArgs = $args | Where-Object { $_ -ne "/machine:x64" }
|
||||
& $llvmLib @filteredArgs
|
||||
exit $LASTEXITCODE
|
||||
@@ -1,34 +0,0 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM Wrapper for llvm-lib that strips conflicting /machine:x64 flag for ARM64 builds
|
||||
REM This is a workaround for CMake 4.1.0 bug
|
||||
|
||||
REM Find llvm-lib.exe - check LLVM_LIB env var, then PATH, then known locations
|
||||
if defined LLVM_LIB (
|
||||
set "LLVM_LIB_EXE=!LLVM_LIB!"
|
||||
) else (
|
||||
where llvm-lib.exe >nul 2>&1
|
||||
if !ERRORLEVEL! equ 0 (
|
||||
for /f "delims=" %%i in ('where llvm-lib.exe') do set "LLVM_LIB_EXE=%%i"
|
||||
) else if exist "C:\Program Files\LLVM\bin\llvm-lib.exe" (
|
||||
set "LLVM_LIB_EXE=C:\Program Files\LLVM\bin\llvm-lib.exe"
|
||||
) else (
|
||||
echo Error: Cannot find llvm-lib.exe. Set LLVM_LIB environment variable or add LLVM to PATH.
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
set NEWARGS=
|
||||
|
||||
for %%a in (%*) do (
|
||||
set "ARG=%%a"
|
||||
if /i "!ARG!"=="/machine:x64" (
|
||||
REM Skip /machine:x64 argument
|
||||
) else (
|
||||
set "NEWARGS=!NEWARGS! %%a"
|
||||
)
|
||||
)
|
||||
|
||||
"!LLVM_LIB_EXE!" %NEWARGS%
|
||||
exit /b %ERRORLEVEL%
|
||||
@@ -7,13 +7,6 @@ register_repository(
|
||||
4f4f5ef8ebc6e23cbf393428f0ab1b526773f7ac
|
||||
)
|
||||
|
||||
set(BORINGSSL_CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF)
|
||||
|
||||
# Disable ASM on Windows ARM64 to avoid mixing non-ARM object files into ARM64 libs
|
||||
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|AARCH64")
|
||||
list(APPEND BORINGSSL_CMAKE_ARGS -DOPENSSL_NO_ASM=1)
|
||||
endif()
|
||||
|
||||
register_cmake_command(
|
||||
TARGET
|
||||
boringssl
|
||||
@@ -22,7 +15,7 @@ register_cmake_command(
|
||||
ssl
|
||||
decrepit
|
||||
ARGS
|
||||
${BORINGSSL_CMAKE_ARGS}
|
||||
-DBUILD_SHARED_LIBS=OFF
|
||||
INCLUDES
|
||||
include
|
||||
)
|
||||
|
||||
@@ -341,6 +341,7 @@ register_command(
|
||||
SOURCES
|
||||
${BUN_JAVASCRIPT_CODEGEN_SOURCES}
|
||||
${BUN_CXX_SOURCES}
|
||||
${ESBUILD_EXECUTABLE}
|
||||
OUTPUTS
|
||||
${BUN_CPP_OUTPUTS}
|
||||
)
|
||||
@@ -362,7 +363,7 @@ register_command(
|
||||
)
|
||||
|
||||
if(SKIP_CODEGEN)
|
||||
# Skip JavaScript codegen - useful for Windows ARM64 debug builds where bun crashes
|
||||
# Skip JavaScript codegen - useful for bootstrapping new platforms
|
||||
message(STATUS "SKIP_CODEGEN is ON - skipping bun-js-modules codegen")
|
||||
foreach(output ${BUN_JAVASCRIPT_OUTPUTS})
|
||||
if(NOT EXISTS ${output})
|
||||
@@ -680,8 +681,7 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM|arm64|ARM64|aarch64|AARCH64")
|
||||
if(APPLE)
|
||||
set(ZIG_CPU "apple_m1")
|
||||
elseif(WIN32)
|
||||
# Windows ARM64: use a specific CPU with NEON support
|
||||
# Zig running under x64 emulation would detect wrong CPU with "native"
|
||||
# Windows ARM64: use a specific CPU target for consistent builds
|
||||
set(ZIG_CPU "cortex_a76")
|
||||
else()
|
||||
set(ZIG_CPU "native")
|
||||
@@ -1457,8 +1457,6 @@ if(NOT BUN_CPP_ONLY)
|
||||
# ==856230==See https://github.com/google/sanitizers/issues/856 for possible workarounds.
|
||||
# the linked issue refers to very old kernels but this still happens to us on modern ones.
|
||||
# disabling ASLR to run the binary works around it
|
||||
# Skip post-build test/features when cross-compiling (can't run the target binary on the host)
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
set(TEST_BUN_COMMAND_BASE ${BUILD_PATH}/${bunExe} --revision)
|
||||
set(TEST_BUN_COMMAND_ENV_WRAP
|
||||
${CMAKE_COMMAND} -E env BUN_DEBUG_QUIET_LOGS=1)
|
||||
@@ -1507,7 +1505,6 @@ if(NOT BUN_CPP_ONLY)
|
||||
${BUILD_PATH}/features.json
|
||||
)
|
||||
endif()
|
||||
endif() # NOT CMAKE_CROSSCOMPILING
|
||||
|
||||
if(CMAKE_HOST_APPLE AND bunStrip)
|
||||
register_command(
|
||||
@@ -1554,10 +1551,7 @@ if(NOT BUN_CPP_ONLY)
|
||||
string(REPLACE bun ${bunTriplet} bunPath ${bun})
|
||||
endif()
|
||||
|
||||
set(bunFiles ${bunExe})
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
list(APPEND bunFiles features.json)
|
||||
endif()
|
||||
set(bunFiles ${bunExe} features.json)
|
||||
if(WIN32)
|
||||
list(APPEND bunFiles ${bun}.pdb)
|
||||
elseif(APPLE)
|
||||
|
||||
@@ -26,7 +26,7 @@ if(RELEASE)
|
||||
list(APPEND LOLHTML_BUILD_ARGS --release)
|
||||
endif()
|
||||
|
||||
# Cross-compilation: tell cargo to target ARM64
|
||||
# Explicitly tell cargo to target ARM64 on Windows ARM64
|
||||
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|AARCH64")
|
||||
list(APPEND LOLHTML_BUILD_ARGS --target aarch64-pc-windows-msvc)
|
||||
set(LOLHTML_LIBRARY ${LOLHTML_BUILD_PATH}/aarch64-pc-windows-msvc/${LOLHTML_BUILD_TYPE}/${CMAKE_STATIC_LIBRARY_PREFIX}lolhtml${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
@@ -57,11 +57,11 @@ if(WIN32)
|
||||
if(MSVC_VERSIONS)
|
||||
list(GET MSVC_VERSIONS -1 MSVC_LATEST) # Get the latest version
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64")
|
||||
# Use Hostx64/arm64 for cross-compilation from x64, fall back to native
|
||||
if(EXISTS "${MSVC_LATEST}/bin/Hostx64/arm64/link.exe")
|
||||
set(MSVC_LINK_PATH "${MSVC_LATEST}/bin/Hostx64/arm64/link.exe")
|
||||
else()
|
||||
# Prefer native HostARM64, fall back to Hostx64/arm64
|
||||
if(EXISTS "${MSVC_LATEST}/bin/HostARM64/arm64/link.exe")
|
||||
set(MSVC_LINK_PATH "${MSVC_LATEST}/bin/HostARM64/arm64/link.exe")
|
||||
else()
|
||||
set(MSVC_LINK_PATH "${MSVC_LATEST}/bin/Hostx64/arm64/link.exe")
|
||||
endif()
|
||||
set(CARGO_LINKER_VAR "CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER")
|
||||
set(MSVC_LIB_ARCH "arm64")
|
||||
|
||||
@@ -7,6 +7,32 @@ register_repository(
|
||||
886098f3f339617b4243b286f5ed364b9989e245
|
||||
)
|
||||
|
||||
# cloudflare/zlib hardcodes STATIC_LIBRARY_FLAGS "/machine:x64" for 64-bit MSVC,
|
||||
# which conflicts with ARM64 object files. Patch it after clone to use the correct
|
||||
# machine type based on CMAKE_SYSTEM_PROCESSOR.
|
||||
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|AARCH64")
|
||||
set(ZLIB_PATCH_SCRIPT "${BUILD_PATH}/zlib-arm64-patch.cmake")
|
||||
file(WRITE ${ZLIB_PATCH_SCRIPT} "
|
||||
file(READ \"\${ZLIB_CMAKELISTS}\" content)
|
||||
string(REPLACE \"/machine:x64\" \"/machine:ARM64\" content \"\${content}\")
|
||||
file(WRITE \"\${ZLIB_CMAKELISTS}\" \"\${content}\")
|
||||
file(TOUCH \"\${ZLIB_PATCH_MARKER}\")
|
||||
")
|
||||
register_command(
|
||||
COMMENT "Patching zlib for ARM64"
|
||||
TARGET patch-zlib
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DZLIB_CMAKELISTS=${VENDOR_PATH}/zlib/CMakeLists.txt
|
||||
-DZLIB_PATCH_MARKER=${VENDOR_PATH}/zlib/.arm64-patched
|
||||
-P ${ZLIB_PATCH_SCRIPT}
|
||||
SOURCES ${VENDOR_PATH}/zlib/.ref
|
||||
OUTPUTS ${VENDOR_PATH}/zlib/.arm64-patched
|
||||
)
|
||||
if(TARGET clone-zlib)
|
||||
add_dependencies(patch-zlib clone-zlib)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/issues/25755
|
||||
if(APPLE)
|
||||
set(ZLIB_CMAKE_C_FLAGS "-fno-define-target-os-macros")
|
||||
@@ -38,3 +64,8 @@ register_cmake_command(
|
||||
INCLUDES
|
||||
.
|
||||
)
|
||||
|
||||
# Ensure zlib is patched before configure
|
||||
if(TARGET patch-zlib)
|
||||
add_dependencies(configure-zlib patch-zlib)
|
||||
endif()
|
||||
|
||||
@@ -4,34 +4,3 @@ set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
set(CMAKE_C_COMPILER_WORKS ON)
|
||||
set(CMAKE_CXX_COMPILER_WORKS ON)
|
||||
set(CMAKE_CROSSCOMPILING ON)
|
||||
|
||||
# The rest only applies when building on Windows (C++ and link steps).
|
||||
# The Zig step runs on Linux and only needs CMAKE_SYSTEM_NAME/PROCESSOR above.
|
||||
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
|
||||
# Ensure clang/clang-cl targets Windows ARM64 (otherwise ARM64-specific flags like
|
||||
# -march=armv8-a are rejected as x86-only).
|
||||
set(CMAKE_C_COMPILER_TARGET aarch64-pc-windows-msvc CACHE STRING "" FORCE)
|
||||
set(CMAKE_CXX_COMPILER_TARGET aarch64-pc-windows-msvc CACHE STRING "" FORCE)
|
||||
|
||||
# ARM64 has lock-free atomics (highway's FindAtomics check can't run ARM64 test binary on x64)
|
||||
set(ATOMICS_LOCK_FREE_INSTRUCTIONS TRUE CACHE BOOL "" FORCE)
|
||||
set(HAVE_CXX_ATOMICS_WITHOUT_LIB TRUE CACHE BOOL "" FORCE)
|
||||
set(HAVE_CXX_ATOMICS64_WITHOUT_LIB TRUE CACHE BOOL "" FORCE)
|
||||
|
||||
# Force ARM64 architecture ID - this is what CMake uses to determine /machine: flag
|
||||
set(MSVC_C_ARCHITECTURE_ID ARM64 CACHE INTERNAL "")
|
||||
set(MSVC_CXX_ARCHITECTURE_ID ARM64 CACHE INTERNAL "")
|
||||
|
||||
# CMake 4.0+ policy CMP0197 controls how MSVC machine type flags are handled
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0197 NEW CACHE INTERNAL "")
|
||||
|
||||
# Clear any inherited static linker flags that might have wrong machine types
|
||||
set(CMAKE_STATIC_LINKER_FLAGS "" CACHE STRING "" FORCE)
|
||||
|
||||
# Use wrapper script for llvm-lib that strips /machine:x64 flags
|
||||
# This works around CMake 4.1.0 bug where both ARM64 and x64 machine flags are added
|
||||
get_filename_component(_TOOLCHAIN_DIR "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY)
|
||||
set(CMAKE_AR "${_TOOLCHAIN_DIR}/scripts/llvm-lib-wrapper.bat" CACHE FILEPATH "" FORCE)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -17,13 +17,7 @@ if (NOT CI)
|
||||
set(BUN_EXECUTABLE ${BUN_EXECUTABLE} CACHE FILEPATH "Bun executable" FORCE)
|
||||
endif()
|
||||
|
||||
# On Windows ARM64, we need to add --smol flag to avoid crashes when running
|
||||
# x64 bun under WoW64 emulation
|
||||
if(WIN32 AND ARCH STREQUAL "aarch64")
|
||||
set(BUN_FLAGS "--smol" CACHE STRING "Extra flags for bun executable")
|
||||
else()
|
||||
set(BUN_FLAGS "" CACHE STRING "Extra flags for bun executable")
|
||||
endif()
|
||||
set(BUN_FLAGS "" CACHE STRING "Extra flags for bun executable")
|
||||
|
||||
# If this is not set, some advanced features are not checked.
|
||||
# https://github.com/oven-sh/bun/blob/cd7f6a1589db7f1e39dc4e3f4a17234afbe7826c/src/bun.js/javascript.zig#L1069-L1072
|
||||
|
||||
@@ -51,7 +51,7 @@ if(APPLE)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# Prefer standalone LLVM over VS-bundled (standalone supports cross-compilation)
|
||||
# Prefer standalone LLVM over VS-bundled
|
||||
list(APPEND LLVM_PATHS "C:/Program Files/LLVM/bin")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@ if(NOT WEBKIT_VERSION)
|
||||
set(WEBKIT_VERSION 8af7958ff0e2a4787569edf64641a1ae7cfe074a)
|
||||
endif()
|
||||
|
||||
# Use preview build URL for Windows ARM64 until the fix is merged to main
|
||||
set(WEBKIT_PREVIEW_PR 140)
|
||||
|
||||
string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX)
|
||||
string(SUBSTRING ${WEBKIT_VERSION} 0 8 WEBKIT_VERSION_SHORT)
|
||||
|
||||
@@ -20,7 +20,7 @@ else()
|
||||
unsupported(CMAKE_SYSTEM_NAME)
|
||||
endif()
|
||||
|
||||
set(ZIG_COMMIT "c1423ff3fc7064635773a4a4616c5bf986eb00fe")
|
||||
set(ZIG_COMMIT "c031cbebf5b063210473ff5204a24ebfb2492c72")
|
||||
optionx(ZIG_TARGET STRING "The zig target to use" DEFAULT ${DEFAULT_ZIG_TARGET})
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
@@ -55,7 +55,14 @@ optionx(ZIG_OBJECT_FORMAT "obj|bc" "Output file format for Zig object files" DEF
|
||||
optionx(ZIG_LOCAL_CACHE_DIR FILEPATH "The path to local the zig cache directory" DEFAULT ${CACHE_PATH}/zig/local)
|
||||
optionx(ZIG_GLOBAL_CACHE_DIR FILEPATH "The path to the global zig cache directory" DEFAULT ${CACHE_PATH}/zig/global)
|
||||
|
||||
optionx(ZIG_COMPILER_SAFE BOOL "Download a ReleaseSafe build of the Zig compiler." DEFAULT ${CI})
|
||||
# The ReleaseSafe Zig compiler for Windows ARM64 has an LLVM SEH epilogue bug
|
||||
# (incorrect size for compiler_rt.rem_pio2_large epilogue). Use the default build instead.
|
||||
if(CI AND WIN32 AND DEFAULT_ZIG_ARCH STREQUAL "aarch64")
|
||||
set(DEFAULT_ZIG_COMPILER_SAFE OFF)
|
||||
else()
|
||||
set(DEFAULT_ZIG_COMPILER_SAFE ${CI})
|
||||
endif()
|
||||
optionx(ZIG_COMPILER_SAFE BOOL "Download a ReleaseSafe build of the Zig compiler." DEFAULT ${DEFAULT_ZIG_COMPILER_SAFE})
|
||||
|
||||
setenv(ZIG_LOCAL_CACHE_DIR ${ZIG_LOCAL_CACHE_DIR})
|
||||
setenv(ZIG_GLOBAL_CACHE_DIR ${ZIG_GLOBAL_CACHE_DIR})
|
||||
|
||||
@@ -24,6 +24,7 @@ bun upgrade
|
||||
- [Linux, x64 (without AVX2 instructions)](https://www.npmjs.com/package/@oven/bun-linux-x64-baseline)
|
||||
- [Windows](https://www.npmjs.com/package/@oven/bun-windows-x64)
|
||||
- [Windows (without AVX2 instructions)](https://www.npmjs.com/package/@oven/bun-windows-x64-baseline)
|
||||
- [Windows ARM64](https://www.npmjs.com/package/@oven/bun-windows-aarch64)
|
||||
|
||||
### Future Platforms
|
||||
|
||||
|
||||
@@ -95,12 +95,12 @@ export const platforms: Platform[] = [
|
||||
bin: "bun-windows-x64-baseline",
|
||||
exe: "bin/bun.exe",
|
||||
},
|
||||
// {
|
||||
// os: "win32",
|
||||
// arch: "arm64",
|
||||
// bin: "bun-windows-aarch64",
|
||||
// exe: "bin/bun.exe",
|
||||
// },
|
||||
{
|
||||
os: "win32",
|
||||
arch: "arm64",
|
||||
bin: "bun-windows-aarch64",
|
||||
exe: "bin/bun.exe",
|
||||
},
|
||||
];
|
||||
|
||||
export const supportedPlatforms: Platform[] = platforms
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
@@ -828,7 +829,7 @@ struct us_socket_t *us_socket_context_adopt_socket(int ssl, struct us_socket_con
|
||||
struct us_socket_t *new_s = s;
|
||||
if (ext_size != -1) {
|
||||
struct us_poll_t *pool_ref = &s->p;
|
||||
new_s = (struct us_socket_t *) us_poll_resize(pool_ref, loop, sizeof(struct us_socket_t) + old_ext_size, sizeof(struct us_socket_t) + ext_size);
|
||||
new_s = (struct us_socket_t *) us_poll_resize(pool_ref, loop, sizeof(struct us_socket_t) - sizeof(struct us_poll_t) + old_ext_size, sizeof(struct us_socket_t) - sizeof(struct us_poll_t) + ext_size);
|
||||
if(new_s != s) {
|
||||
/* Mark the old socket as closed */
|
||||
s->flags.is_closed = 1;
|
||||
|
||||
785
scripts/azure.mjs
Normal file
785
scripts/azure.mjs
Normal file
@@ -0,0 +1,785 @@
|
||||
// Azure REST API client for machine.mjs
|
||||
// Used by the [build images] pipeline to create Windows VM images (x64 and ARM64)
|
||||
|
||||
import { getSecret, isCI } from "./utils.mjs";
|
||||
|
||||
/**
|
||||
* @typedef {Object} AzureConfig
|
||||
* @property {string} tenantId
|
||||
* @property {string} clientId
|
||||
* @property {string} clientSecret
|
||||
* @property {string} subscriptionId
|
||||
* @property {string} resourceGroup
|
||||
* @property {string} location
|
||||
* @property {string} galleryName
|
||||
*/
|
||||
|
||||
/** @returns {AzureConfig} */
|
||||
function getConfig() {
|
||||
const env = (name, fallback) => {
|
||||
if (isCI) {
|
||||
try {
|
||||
return getSecret(name, { required: !fallback }) || fallback;
|
||||
} catch {
|
||||
if (fallback) return fallback;
|
||||
throw new Error(`Azure secret not found: ${name}`);
|
||||
}
|
||||
}
|
||||
return process.env[name] || fallback;
|
||||
};
|
||||
|
||||
return {
|
||||
tenantId: env("AZURE_TENANT_ID"),
|
||||
clientId: env("AZURE_CLIENT_ID"),
|
||||
clientSecret: env("AZURE_CLIENT_SECRET"),
|
||||
subscriptionId: env("AZURE_SUBSCRIPTION_ID"),
|
||||
resourceGroup: env("AZURE_RESOURCE_GROUP", "BUN-CI"),
|
||||
location: env("AZURE_LOCATION", "eastus2"),
|
||||
galleryName: env("AZURE_GALLERY_NAME", "bunCIGallery2"),
|
||||
};
|
||||
}
|
||||
|
||||
let _config;
|
||||
function config() {
|
||||
return (_config ??= getConfig());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Authentication
|
||||
// ============================================================================
|
||||
|
||||
let _accessToken = null;
|
||||
let _tokenExpiry = 0;
|
||||
|
||||
async function getAccessToken() {
|
||||
if (_accessToken && Date.now() < _tokenExpiry - 300_000) {
|
||||
return _accessToken;
|
||||
}
|
||||
|
||||
const { tenantId, clientId, clientSecret } = config();
|
||||
const response = await fetch(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: new URLSearchParams({
|
||||
grant_type: "client_credentials",
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
scope: "https://management.azure.com/.default",
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`[azure] Auth failed: ${response.status} ${await response.text()}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
_accessToken = data.access_token;
|
||||
_tokenExpiry = Date.now() + data.expires_in * 1000;
|
||||
return _accessToken;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// REST Client
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @param {"GET"|"PUT"|"POST"|"PATCH"|"DELETE"} method
|
||||
* @param {string} path - Relative path under management.azure.com, or absolute URL
|
||||
* @param {object} [body]
|
||||
* @param {string} [apiVersion]
|
||||
*/
|
||||
async function azureFetch(method, path, body, apiVersion = "2024-07-01") {
|
||||
const token = await getAccessToken();
|
||||
|
||||
const url = path.startsWith("http") ? new URL(path) : new URL(`https://management.azure.com${path}`);
|
||||
|
||||
if (!url.searchParams.has("api-version")) {
|
||||
url.searchParams.set("api-version", apiVersion);
|
||||
}
|
||||
|
||||
const options = {
|
||||
method,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
|
||||
if (body && method !== "GET" && method !== "DELETE") {
|
||||
options.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
for (let attempt = 0; attempt < 3; attempt++) {
|
||||
const response = await fetch(url, options);
|
||||
|
||||
if (response.status === 429 || response.status >= 500) {
|
||||
const wait = Math.pow(2, attempt) * 1000;
|
||||
console.warn(`[azure] ${method} ${path} returned ${response.status}, retrying in ${wait}ms...`);
|
||||
await new Promise(r => setTimeout(r, wait));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 202 Accepted — async operation, poll for completion
|
||||
if (response.status === 202) {
|
||||
const operationUrl = response.headers.get("Azure-AsyncOperation") || response.headers.get("Location");
|
||||
if (operationUrl) {
|
||||
return waitForOperation(operationUrl);
|
||||
}
|
||||
}
|
||||
|
||||
if (response.status === 204) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(`[azure] ${method} ${path} failed: ${response.status} ${text}`);
|
||||
}
|
||||
|
||||
const text = await response.text();
|
||||
return text ? JSON.parse(text) : null;
|
||||
}
|
||||
|
||||
throw new Error(`[azure] ${method} ${path} failed after 3 retries`);
|
||||
}
|
||||
|
||||
async function waitForOperation(operationUrl, maxWaitMs = 3_600_000) {
|
||||
const start = Date.now();
|
||||
let fetchErrors = 0;
|
||||
|
||||
while (Date.now() - start < maxWaitMs) {
|
||||
const token = await getAccessToken();
|
||||
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(operationUrl, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
} catch (err) {
|
||||
fetchErrors++;
|
||||
if (fetchErrors > 10) {
|
||||
throw new Error(`[azure] Operation poll failed after ${fetchErrors} fetch errors`, { cause: err });
|
||||
}
|
||||
console.warn(`[azure] Operation poll fetch error (${fetchErrors}), retrying...`);
|
||||
await new Promise(r => setTimeout(r, 10_000));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`[azure] Operation poll failed: ${response.status} ${await response.text()}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.status === "Succeeded") {
|
||||
return data.properties?.output ?? data;
|
||||
}
|
||||
if (data.status === "Failed" || data.status === "Canceled") {
|
||||
throw new Error(`[azure] Operation ${data.status}: ${data.error?.message ?? "unknown"}`);
|
||||
}
|
||||
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
}
|
||||
|
||||
throw new Error(`[azure] Operation timed out after ${maxWaitMs}ms`);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Resource helpers
|
||||
// ============================================================================
|
||||
|
||||
function rgPath() {
|
||||
const { subscriptionId, resourceGroup } = config();
|
||||
return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}`;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Public IP
|
||||
// ============================================================================
|
||||
|
||||
async function createPublicIp(name) {
|
||||
const { location } = config();
|
||||
console.log(`[azure] Creating public IP: ${name}`);
|
||||
const result = await azureFetch("PUT", `${rgPath()}/providers/Microsoft.Network/publicIPAddresses/${name}`, {
|
||||
location,
|
||||
sku: { name: "Standard" },
|
||||
properties: {
|
||||
publicIPAllocationMethod: "Static",
|
||||
deleteOption: "Delete",
|
||||
},
|
||||
});
|
||||
return result?.properties?.ipAddress;
|
||||
}
|
||||
|
||||
async function deletePublicIp(name) {
|
||||
await azureFetch("DELETE", `${rgPath()}/providers/Microsoft.Network/publicIPAddresses/${name}`).catch(() => {});
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Network Security Group
|
||||
// ============================================================================
|
||||
|
||||
async function ensureNsg(name) {
|
||||
const { location } = config();
|
||||
const path = `${rgPath()}/providers/Microsoft.Network/networkSecurityGroups/${name}`;
|
||||
|
||||
try {
|
||||
const existing = await azureFetch("GET", path);
|
||||
if (existing) return path;
|
||||
} catch {}
|
||||
|
||||
console.log(`[azure] Creating NSG: ${name}`);
|
||||
await azureFetch("PUT", path, {
|
||||
location,
|
||||
properties: {
|
||||
securityRules: [
|
||||
{
|
||||
name: "AllowSSH",
|
||||
properties: {
|
||||
priority: 100,
|
||||
protocol: "Tcp",
|
||||
access: "Allow",
|
||||
direction: "Inbound",
|
||||
sourceAddressPrefix: "*",
|
||||
sourcePortRange: "*",
|
||||
destinationAddressPrefix: "*",
|
||||
destinationPortRange: "22",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AllowRDP",
|
||||
properties: {
|
||||
priority: 110,
|
||||
protocol: "Tcp",
|
||||
access: "Allow",
|
||||
direction: "Inbound",
|
||||
sourceAddressPrefix: "*",
|
||||
sourcePortRange: "*",
|
||||
destinationAddressPrefix: "*",
|
||||
destinationPortRange: "3389",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
return path;
|
||||
}
|
||||
|
||||
async function deleteNsg(name) {
|
||||
await azureFetch("DELETE", `${rgPath()}/providers/Microsoft.Network/networkSecurityGroups/${name}`).catch(() => {});
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Network Interface
|
||||
// ============================================================================
|
||||
|
||||
async function createNic(name, publicIpName, subnetId, nsgId) {
|
||||
const { location } = config();
|
||||
console.log(`[azure] Creating NIC: ${name}`);
|
||||
const publicIpId = `${rgPath()}/providers/Microsoft.Network/publicIPAddresses/${publicIpName}`;
|
||||
await azureFetch("PUT", `${rgPath()}/providers/Microsoft.Network/networkInterfaces/${name}`, {
|
||||
location,
|
||||
properties: {
|
||||
ipConfigurations: [
|
||||
{
|
||||
name: "ipconfig1",
|
||||
properties: {
|
||||
privateIPAllocationMethod: "Dynamic",
|
||||
publicIPAddress: { id: publicIpId, properties: { deleteOption: "Delete" } },
|
||||
subnet: { id: subnetId },
|
||||
},
|
||||
},
|
||||
],
|
||||
...(nsgId ? { networkSecurityGroup: { id: nsgId } } : {}),
|
||||
},
|
||||
});
|
||||
return `${rgPath()}/providers/Microsoft.Network/networkInterfaces/${name}`;
|
||||
}
|
||||
|
||||
async function deleteNic(name) {
|
||||
await azureFetch("DELETE", `${rgPath()}/providers/Microsoft.Network/networkInterfaces/${name}`).catch(() => {});
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Virtual Machines
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @param {object} opts
|
||||
* @param {string} opts.name
|
||||
* @param {string} opts.vmSize
|
||||
* @param {object} opts.imageReference
|
||||
* @param {number} opts.osDiskSizeGB
|
||||
* @param {string} opts.nicId
|
||||
* @param {string} opts.adminUsername
|
||||
* @param {string} opts.adminPassword
|
||||
* @param {Record<string, string>} [opts.tags]
|
||||
*/
|
||||
async function createVm(opts) {
|
||||
const { location } = config();
|
||||
console.log(`[azure] Creating VM: ${opts.name} (${opts.vmSize})`);
|
||||
const result = await azureFetch("PUT", `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${opts.name}`, {
|
||||
location,
|
||||
tags: opts.tags,
|
||||
properties: {
|
||||
hardwareProfile: { vmSize: opts.vmSize },
|
||||
storageProfile: {
|
||||
imageReference: opts.imageReference,
|
||||
osDisk: {
|
||||
createOption: "FromImage",
|
||||
diskSizeGB: opts.osDiskSizeGB,
|
||||
deleteOption: "Delete",
|
||||
managedDisk: { storageAccountType: "Premium_LRS" },
|
||||
},
|
||||
},
|
||||
osProfile: {
|
||||
computerName: opts.name.substring(0, 15),
|
||||
adminUsername: opts.adminUsername,
|
||||
adminPassword: opts.adminPassword,
|
||||
},
|
||||
securityProfile: {
|
||||
securityType: "TrustedLaunch",
|
||||
},
|
||||
networkProfile: {
|
||||
networkInterfaces: [{ id: opts.nicId, properties: { deleteOption: "Delete" } }],
|
||||
},
|
||||
},
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
async function getVm(name) {
|
||||
try {
|
||||
return await azureFetch(
|
||||
"GET",
|
||||
`${rgPath()}/providers/Microsoft.Compute/virtualMachines/${name}?$expand=instanceView`,
|
||||
);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function getVmPowerState(name) {
|
||||
const vm = await getVm(name);
|
||||
const statuses = vm?.properties?.instanceView?.statuses ?? [];
|
||||
const powerStatus = statuses.find(s => s.code?.startsWith("PowerState/"));
|
||||
return powerStatus?.code;
|
||||
}
|
||||
|
||||
async function stopVm(name) {
|
||||
console.log(`[azure] Stopping VM: ${name}`);
|
||||
await azureFetch("POST", `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${name}/deallocate`);
|
||||
}
|
||||
|
||||
async function generalizeVm(name) {
|
||||
console.log(`[azure] Generalizing VM: ${name}`);
|
||||
await azureFetch("POST", `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${name}/generalize`);
|
||||
}
|
||||
|
||||
async function deleteVm(name) {
|
||||
console.log(`[azure] Deleting VM: ${name}`);
|
||||
await azureFetch("DELETE", `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${name}?forceDeletion=true`);
|
||||
}
|
||||
|
||||
async function getPublicIpAddress(publicIpName) {
|
||||
const result = await azureFetch("GET", `${rgPath()}/providers/Microsoft.Network/publicIPAddresses/${publicIpName}`);
|
||||
return result?.properties?.ipAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a PowerShell script on a Windows VM via Azure Run Command.
|
||||
* This works even without SSH installed on the VM.
|
||||
*/
|
||||
async function runCommand(vmName, script) {
|
||||
console.log(`[azure] Running command on VM: ${vmName}`);
|
||||
return azureFetch("POST", `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${vmName}/runCommand`, {
|
||||
commandId: "RunPowerShellScript",
|
||||
script: Array.isArray(script) ? script : [script],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Install OpenSSH server and configure authorized keys on a Windows VM.
|
||||
*/
|
||||
// SSH is not used — all remote operations go through Azure Run Command API.
|
||||
|
||||
// ============================================================================
|
||||
// Virtual Network
|
||||
// ============================================================================
|
||||
|
||||
async function ensureVNet(vnetName, subnetName) {
|
||||
const { location } = config();
|
||||
const path = `${rgPath()}/providers/Microsoft.Network/virtualNetworks/${vnetName}`;
|
||||
|
||||
// Check if VNet exists
|
||||
try {
|
||||
const vnet = await azureFetch("GET", path);
|
||||
if (vnet) {
|
||||
const subnet = vnet.properties?.subnets?.find(s => s.name === subnetName);
|
||||
if (subnet) return subnet.id;
|
||||
}
|
||||
} catch {}
|
||||
|
||||
console.log(`[azure] Creating VNet: ${vnetName} with subnet: ${subnetName}`);
|
||||
await azureFetch("PUT", path, {
|
||||
location,
|
||||
properties: {
|
||||
addressSpace: { addressPrefixes: ["10.0.0.0/16"] },
|
||||
subnets: [
|
||||
{
|
||||
name: subnetName,
|
||||
properties: { addressPrefix: "10.0.0.0/24" },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const vnet = await azureFetch("GET", path);
|
||||
return vnet.properties.subnets.find(s => s.name === subnetName).id;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Compute Gallery
|
||||
// ============================================================================
|
||||
|
||||
const GALLERY_API_VERSION = "2024-03-03";
|
||||
|
||||
async function ensureGallery() {
|
||||
const { location, galleryName } = config();
|
||||
const path = `${rgPath()}/providers/Microsoft.Compute/galleries/${galleryName}`;
|
||||
|
||||
try {
|
||||
const gallery = await azureFetch("GET", path, undefined, GALLERY_API_VERSION);
|
||||
if (gallery) return;
|
||||
} catch {}
|
||||
|
||||
console.log(`[azure] Creating gallery: ${galleryName}`);
|
||||
await azureFetch("PUT", path, { location }, GALLERY_API_VERSION);
|
||||
}
|
||||
|
||||
async function ensureImageDefinition(name, os, arch) {
|
||||
const { location, galleryName } = config();
|
||||
const path = `${rgPath()}/providers/Microsoft.Compute/galleries/${galleryName}/images/${name}`;
|
||||
|
||||
try {
|
||||
const def = await azureFetch("GET", path, undefined, GALLERY_API_VERSION);
|
||||
if (def) return;
|
||||
} catch {}
|
||||
|
||||
console.log(`[azure] Creating image definition: ${name}`);
|
||||
await azureFetch(
|
||||
"PUT",
|
||||
path,
|
||||
{
|
||||
location,
|
||||
properties: {
|
||||
osType: os === "windows" ? "Windows" : "Linux",
|
||||
osState: "Generalized",
|
||||
hyperVGeneration: "V2",
|
||||
architecture: arch === "aarch64" ? "Arm64" : "x64",
|
||||
identifier: {
|
||||
publisher: "bun",
|
||||
offer: `${os}-${arch}-ci`,
|
||||
sku: name,
|
||||
},
|
||||
features: [
|
||||
{ name: "DiskControllerTypes", value: "SCSI, NVMe" },
|
||||
{ name: "SecurityType", value: "TrustedLaunch" },
|
||||
],
|
||||
},
|
||||
},
|
||||
GALLERY_API_VERSION,
|
||||
);
|
||||
}
|
||||
|
||||
async function createImageVersion(imageDefName, version, vmId) {
|
||||
const { location, galleryName } = config();
|
||||
const path = `${rgPath()}/providers/Microsoft.Compute/galleries/${galleryName}/images/${imageDefName}/versions/${version}`;
|
||||
|
||||
console.log(`[azure] Creating image version: ${imageDefName}/${version}`);
|
||||
const result = await azureFetch(
|
||||
"PUT",
|
||||
path,
|
||||
{
|
||||
location,
|
||||
properties: {
|
||||
storageProfile: {
|
||||
source: { virtualMachineId: vmId },
|
||||
},
|
||||
},
|
||||
},
|
||||
GALLERY_API_VERSION,
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
async function createImageVersionWithLabel(imageDefName, version, vmId, label) {
|
||||
const { location, galleryName } = config();
|
||||
const path = `${rgPath()}/providers/Microsoft.Compute/galleries/${galleryName}/images/${imageDefName}/versions/${version}`;
|
||||
|
||||
console.log(`[azure] Creating image version: ${imageDefName}/${version} (label: ${label})`);
|
||||
const result = await azureFetch(
|
||||
"PUT",
|
||||
path,
|
||||
{
|
||||
location,
|
||||
tags: { "image-name": label },
|
||||
properties: {
|
||||
storageProfile: {
|
||||
source: { virtualMachineId: vmId },
|
||||
},
|
||||
},
|
||||
},
|
||||
GALLERY_API_VERSION,
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Base Images
|
||||
// ============================================================================
|
||||
|
||||
function getBaseImageReference(os, arch) {
|
||||
if (os === "windows") {
|
||||
if (arch === "aarch64") {
|
||||
return {
|
||||
publisher: "MicrosoftWindowsDesktop",
|
||||
offer: "windows11preview-arm64",
|
||||
sku: "win11-24h2-pro",
|
||||
version: "latest",
|
||||
};
|
||||
}
|
||||
// Windows Server 2019 x64 — oldest supported version
|
||||
return {
|
||||
publisher: "MicrosoftWindowsServer",
|
||||
offer: "WindowsServer",
|
||||
sku: "2019-datacenter-gensecond",
|
||||
version: "latest",
|
||||
};
|
||||
}
|
||||
throw new Error(`[azure] Unsupported OS: ${os}`);
|
||||
}
|
||||
|
||||
function getVmSize(arch) {
|
||||
return arch === "aarch64" ? "Standard_D4ps_v6" : "Standard_D4ds_v6";
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Exports
|
||||
// ============================================================================
|
||||
|
||||
export const azure = {
|
||||
get name() {
|
||||
return "azure";
|
||||
},
|
||||
|
||||
config,
|
||||
|
||||
/**
|
||||
* @param {import("./machine.mjs").MachineOptions} options
|
||||
* @returns {Promise<import("./machine.mjs").Machine>}
|
||||
*/
|
||||
async createMachine(options) {
|
||||
const { os, arch, tags, sshKeys } = options;
|
||||
const vmName = `bun-${os}-${arch}-${Date.now()}`;
|
||||
const publicIpName = `${vmName}-ip`;
|
||||
const nicName = `${vmName}-nic`;
|
||||
const vmSize = options.instanceType || getVmSize(arch);
|
||||
const diskSizeGB = options.diskSizeGb || (os === "windows" ? 150 : 40);
|
||||
|
||||
// Generate a random password for the admin account
|
||||
const adminPassword = `P@${crypto.randomUUID().replace(/-/g, "").substring(0, 20)}!`;
|
||||
|
||||
// Ensure VNet exists
|
||||
const subnetId = await ensureVNet("bun-ci-vnet", "default");
|
||||
|
||||
// Create public IP (needed for outbound internet during bootstrap)
|
||||
await createPublicIp(publicIpName);
|
||||
|
||||
// Create NIC (no NSG needed — all operations go through Azure Run Command, not SSH)
|
||||
const nicId = await createNic(nicName, publicIpName, subnetId, null);
|
||||
|
||||
// Create VM
|
||||
const imageReference = options.imageId ? { id: options.imageId } : getBaseImageReference(os, arch);
|
||||
|
||||
await createVm({
|
||||
name: vmName,
|
||||
vmSize,
|
||||
imageReference,
|
||||
osDiskSizeGB: diskSizeGB,
|
||||
nicId,
|
||||
adminUsername: "bunadmin",
|
||||
adminPassword,
|
||||
tags: tags
|
||||
? Object.fromEntries(
|
||||
Object.entries(tags)
|
||||
.filter(([_, v]) => v != null)
|
||||
.map(([k, v]) => [k, String(v)]),
|
||||
)
|
||||
: undefined,
|
||||
});
|
||||
|
||||
// Wait for public IP to be assigned
|
||||
let publicIp;
|
||||
for (let i = 0; i < 30; i++) {
|
||||
publicIp = await getPublicIpAddress(publicIpName);
|
||||
if (publicIp) break;
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
}
|
||||
|
||||
if (!publicIp) {
|
||||
throw new Error(`[azure] Failed to get public IP for ${vmName}`);
|
||||
}
|
||||
|
||||
console.log(`[azure] VM created: ${vmName} at ${publicIp}`);
|
||||
|
||||
// Use Azure Run Command for all remote operations instead of SSH.
|
||||
// This avoids the sshd startup issues on Azure Windows VMs.
|
||||
|
||||
const spawnFn = async (command, opts) => {
|
||||
const script = command.join(" ");
|
||||
console.log(`[azure] Run: ${script}`);
|
||||
// Note: Azure Run Command output is limited to the last 4096 bytes.
|
||||
// Full output is not available — only the tail is returned.
|
||||
// value[0] = stdout (ComponentStatus/StdOut), value[1] = stderr (ComponentStatus/StdErr)
|
||||
const result = await runCommand(vmName, [script]);
|
||||
const values = result?.value ?? [];
|
||||
const stdout = values[0]?.message ?? "";
|
||||
const stderr = values[1]?.message ?? "";
|
||||
if (opts?.stdio === "inherit") {
|
||||
if (stdout) process.stdout.write(stdout);
|
||||
if (stderr) process.stderr.write(stderr);
|
||||
}
|
||||
// Only use displayStatus to detect errors — stderr often contains non-error
|
||||
// output (rustup progress, cargo warnings, PowerShell Write-Warning, etc.)
|
||||
const hasError = values.some(v => v?.displayStatus === "Provisioning failed");
|
||||
const exitCode = hasError ? 1 : 0;
|
||||
return { exitCode, stdout, stderr };
|
||||
};
|
||||
|
||||
const spawnSafeFn = async (command, opts) => {
|
||||
const result = await spawnFn(command, opts);
|
||||
if (result.exitCode !== 0) {
|
||||
const msg = result.stderr || result.stdout || "Unknown error";
|
||||
throw new Error(`[azure] Command failed (exit ${result.exitCode}): ${command.join(" ")}\n${msg}`);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const upload = async (source, destination) => {
|
||||
// Read the file locally and write it on the VM via Run Command
|
||||
const { readFileSync } = await import("node:fs");
|
||||
const content = readFileSync(source, "utf-8");
|
||||
// Escape for PowerShell — use base64 to avoid escaping issues
|
||||
const b64 = Buffer.from(content).toString("base64");
|
||||
const script = [
|
||||
`$bytes = [Convert]::FromBase64String('${b64}')`,
|
||||
`$dir = Split-Path '${destination}' -Parent`,
|
||||
`if (-not (Test-Path $dir)) { New-Item -Path $dir -ItemType Directory -Force | Out-Null }`,
|
||||
`[IO.File]::WriteAllBytes('${destination}', $bytes)`,
|
||||
`Write-Host "Uploaded to ${destination} ($($bytes.Length) bytes)"`,
|
||||
];
|
||||
console.log(`[azure] Uploading ${source} -> ${destination}`);
|
||||
await runCommand(vmName, script);
|
||||
};
|
||||
|
||||
const attach = async () => {
|
||||
console.log(`[azure] Attach not supported via Run Command (VM: ${vmName}, IP: ${publicIp})`);
|
||||
};
|
||||
|
||||
const waitForSsh = async () => {
|
||||
// No SSH needed — Run Command works immediately after VM is provisioned
|
||||
// Just verify the VM is responsive
|
||||
console.log(`[azure] Verifying VM is responsive...`);
|
||||
await runCommand(vmName, ["Write-Host 'VM is ready'"]);
|
||||
console.log(`[azure] VM is responsive`);
|
||||
};
|
||||
|
||||
const snapshot = async label => {
|
||||
const vmId = `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${vmName}`;
|
||||
|
||||
// Run sysprep inside the VM before deallocating.
|
||||
// This prepares Windows for generalization so the gallery image
|
||||
// can be used to create new VMs with OS provisioning.
|
||||
console.log(`[azure] Running sysprep on ${vmName}...`);
|
||||
await runCommand(vmName, ["C:\\Windows\\System32\\Sysprep\\sysprep.exe /generalize /oobe /shutdown /quiet"]);
|
||||
|
||||
// Wait for VM to shut down after sysprep (sysprep triggers shutdown)
|
||||
for (let i = 0; i < 60; i++) {
|
||||
const state = await getVmPowerState(vmName);
|
||||
if (state === "PowerState/stopped" || state === "PowerState/deallocated") break;
|
||||
await new Promise(r => setTimeout(r, 10000));
|
||||
}
|
||||
|
||||
// Deallocate the VM
|
||||
await stopVm(vmName);
|
||||
// Wait for VM to be deallocated
|
||||
for (let i = 0; i < 60; i++) {
|
||||
const state = await getVmPowerState(vmName);
|
||||
if (state === "PowerState/deallocated") break;
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
}
|
||||
|
||||
await generalizeVm(vmName);
|
||||
|
||||
// Ensure gallery and image definition exist.
|
||||
// Use the label as the image definition name — this matches what ci.mjs
|
||||
// emits as the image-name agent tag, so robobun can look it up directly.
|
||||
await ensureGallery();
|
||||
const imageDefName = label;
|
||||
await ensureImageDefinition(imageDefName, os, arch);
|
||||
|
||||
// Create a single version "1.0.0" under this definition.
|
||||
await createImageVersion(imageDefName, "1.0.0", vmId);
|
||||
|
||||
// Wait for image replication to complete before returning.
|
||||
// Single-region replication typically takes 5-15 minutes.
|
||||
const { galleryName } = config();
|
||||
const versionPath = `${rgPath()}/providers/Microsoft.Compute/galleries/${galleryName}/images/${imageDefName}/versions/1.0.0`;
|
||||
console.log(`[azure] Waiting for image replication...`);
|
||||
for (let i = 0; i < 120; i++) {
|
||||
const ver = await azureFetch("GET", versionPath, undefined, GALLERY_API_VERSION);
|
||||
const state = ver?.properties?.provisioningState;
|
||||
if (state === "Succeeded") {
|
||||
console.log(`[azure] Image ready: ${imageDefName}/1.0.0`);
|
||||
break;
|
||||
}
|
||||
if (state === "Failed") {
|
||||
throw new Error(`[azure] Image replication failed: ${JSON.stringify(ver?.properties)}`);
|
||||
}
|
||||
if (i % 6 === 0) {
|
||||
console.log(`[azure] Image replicating... (${i}m elapsed)`);
|
||||
}
|
||||
await new Promise(r => setTimeout(r, 10_000));
|
||||
}
|
||||
|
||||
return label;
|
||||
};
|
||||
|
||||
const terminate = async () => {
|
||||
await deleteVm(vmName);
|
||||
// Resources with deleteOption=Delete are cleaned up automatically
|
||||
// But clean up anything that might be left
|
||||
await deleteNic(nicName);
|
||||
await deletePublicIp(publicIpName);
|
||||
};
|
||||
|
||||
return {
|
||||
cloud: "azure",
|
||||
id: vmName,
|
||||
imageId: options.imageId,
|
||||
instanceType: vmSize,
|
||||
region: config().location,
|
||||
get publicIp() {
|
||||
return publicIp;
|
||||
},
|
||||
spawn: spawnFn,
|
||||
spawnSafe: spawnSafeFn,
|
||||
upload,
|
||||
attach,
|
||||
snapshot,
|
||||
waitForSsh,
|
||||
close: terminate,
|
||||
[Symbol.asyncDispose]: terminate,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
# Version: 12
|
||||
# A script that installs the dependencies needed to build and test Bun.
|
||||
# This should work on Windows 10 or newer with PowerShell.
|
||||
# Version: 13
|
||||
# A script that installs the dependencies needed to build and test Bun on Windows.
|
||||
# Supports both x64 and ARM64 using Scoop for package management.
|
||||
# Used by Azure [build images] pipeline.
|
||||
|
||||
# If this script does not work on your machine, please open an issue:
|
||||
# https://github.com/oven-sh/bun/issues
|
||||
@@ -11,7 +12,7 @@
|
||||
|
||||
param (
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$CI = $false,
|
||||
[switch]$CI = ($env:CI -eq "true"),
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$Optimize = $CI
|
||||
)
|
||||
@@ -19,17 +20,26 @@ param (
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
|
||||
|
||||
function Execute-Command {
|
||||
$command = $args -join ' '
|
||||
Write-Output "$ $command"
|
||||
# Detect ARM64 from registry (works even under x64 emulation)
|
||||
$realArch = (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment').PROCESSOR_ARCHITECTURE
|
||||
$script:IsARM64 = $realArch -eq "ARM64"
|
||||
|
||||
& $args[0] $args[1..$args.Length]
|
||||
|
||||
if ((-not $?) -or ($LASTEXITCODE -ne 0 -and $null -ne $LASTEXITCODE)) {
|
||||
throw "Command failed: $command"
|
||||
# If we're on ARM64 but running under x64 emulation, re-launch as native ARM64.
|
||||
# Azure Run Command uses x64-emulated PowerShell which breaks package installs.
|
||||
if ($script:IsARM64 -and $env:PROCESSOR_ARCHITECTURE -ne "ARM64") {
|
||||
$nativePS = "$env:SystemRoot\Sysnative\WindowsPowerShell\v1.0\powershell.exe"
|
||||
if (Test-Path $nativePS) {
|
||||
Write-Output "Re-launching bootstrap as native ARM64 PowerShell..."
|
||||
& $nativePS -NoProfile -ExecutionPolicy Bypass -File $MyInvocation.MyCommand.Path @PSBoundParameters
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Utility functions
|
||||
# ============================================================================
|
||||
|
||||
|
||||
function Which {
|
||||
param ([switch]$Required = $false)
|
||||
|
||||
@@ -46,16 +56,6 @@ function Which {
|
||||
}
|
||||
}
|
||||
|
||||
function Execute-Script {
|
||||
param (
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
$pwsh = Which pwsh powershell -Required
|
||||
Execute-Command $pwsh $Path
|
||||
}
|
||||
|
||||
function Download-File {
|
||||
param (
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
@@ -87,18 +87,6 @@ function Download-File {
|
||||
return $Path
|
||||
}
|
||||
|
||||
function Install-Chocolatey {
|
||||
if (Which choco) {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Output "Installing Chocolatey..."
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
|
||||
$installScript = Download-File "https://community.chocolatey.org/install.ps1"
|
||||
Execute-Script $installScript
|
||||
Refresh-Path
|
||||
}
|
||||
|
||||
function Refresh-Path {
|
||||
$paths = @(
|
||||
[System.Environment]::GetEnvironmentVariable("Path", "Machine"),
|
||||
@@ -111,15 +99,19 @@ function Refresh-Path {
|
||||
Where-Object { $_ -and (Test-Path $_) } |
|
||||
Select-Object -Unique
|
||||
$env:Path = ($uniquePaths -join ';').TrimEnd(';')
|
||||
|
||||
if ($env:ChocolateyInstall) {
|
||||
Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
function Add-To-Path {
|
||||
$absolutePath = Resolve-Path $args[0]
|
||||
$currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine")
|
||||
param (
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[string]$PathToAdd,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateSet("Machine", "User")]
|
||||
[string]$Scope = "Machine"
|
||||
)
|
||||
|
||||
$absolutePath = Resolve-Path $PathToAdd
|
||||
$currentPath = [Environment]::GetEnvironmentVariable("Path", $Scope)
|
||||
if ($currentPath -like "*$absolutePath*") {
|
||||
return
|
||||
}
|
||||
@@ -140,8 +132,8 @@ function Add-To-Path {
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output "Adding $absolutePath to PATH..."
|
||||
[Environment]::SetEnvironmentVariable("Path", "$newPath", "Machine")
|
||||
Write-Output "Adding $absolutePath to PATH ($Scope)..."
|
||||
[Environment]::SetEnvironmentVariable("Path", "$newPath", $Scope)
|
||||
Refresh-Path
|
||||
}
|
||||
|
||||
@@ -158,64 +150,149 @@ function Set-Env {
|
||||
[System.Environment]::SetEnvironmentVariable("$Name", "$Value", "Process")
|
||||
}
|
||||
|
||||
function Install-Package {
|
||||
# ============================================================================
|
||||
# Scoop — ARM64-native package manager
|
||||
# ============================================================================
|
||||
|
||||
function Install-Scoop {
|
||||
if (Which scoop) {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Output "Installing Scoop..."
|
||||
# Scoop blocks admin installs unless -RunAsAdmin is passed.
|
||||
# Install to a known global location so all users can access it.
|
||||
$env:SCOOP = "C:\Scoop"
|
||||
[Environment]::SetEnvironmentVariable("SCOOP", $env:SCOOP, "Machine")
|
||||
iex "& {$(irm get.scoop.sh)} -RunAsAdmin -ScoopDir C:\Scoop"
|
||||
Add-To-Path "C:\Scoop\shims"
|
||||
Refresh-Path
|
||||
Write-Output "Scoop version: $(scoop --version)"
|
||||
}
|
||||
|
||||
function Install-Scoop-Package {
|
||||
param (
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[string]$Name,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Command = $Name,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Version,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$Force = $false,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string[]]$ExtraArgs = @()
|
||||
[string]$Command = $Name
|
||||
)
|
||||
|
||||
if (-not $Force `
|
||||
-and (Which $Command) `
|
||||
-and (-not $Version -or (& $Command --version) -like "*$Version*")) {
|
||||
if (Which $Command) {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Output "Installing $Name..."
|
||||
$flags = @(
|
||||
"--yes",
|
||||
"--accept-license",
|
||||
"--no-progress",
|
||||
"--force"
|
||||
)
|
||||
if ($Version) {
|
||||
$flags += "--version=$Version"
|
||||
}
|
||||
|
||||
Execute-Command choco install $Name @flags @ExtraArgs
|
||||
Write-Output "Installing $Name (via Scoop)..."
|
||||
# Scoop post_install scripts can have non-fatal Remove-Item errors
|
||||
# (e.g. 7zip ARM64 7zr.exe locked, llvm-arm64 missing Uninstall.exe).
|
||||
# Suppress all error streams so they don't kill the bootstrap or Packer.
|
||||
$prevErrorPref = $ErrorActionPreference
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
scoop install $Name *>&1 | ForEach-Object { "$_" } | Write-Host
|
||||
$ErrorActionPreference = $prevErrorPref
|
||||
Refresh-Path
|
||||
}
|
||||
|
||||
function Install-Packages {
|
||||
foreach ($package in $args) {
|
||||
Install-Package $package
|
||||
# ============================================================================
|
||||
# Scoop packages (native ARM64 binaries)
|
||||
# ============================================================================
|
||||
|
||||
function Install-Git {
|
||||
Install-Scoop-Package git
|
||||
|
||||
# Git for Windows ships Unix tools (cat, head, tail, etc.) in usr\bin
|
||||
$gitUsrBin = "C:\Scoop\apps\git\current\usr\bin"
|
||||
if (Test-Path $gitUsrBin) {
|
||||
Add-To-Path $gitUsrBin
|
||||
}
|
||||
|
||||
if ($CI) {
|
||||
git config --system --add safe.directory "*"
|
||||
git config --system core.autocrlf false
|
||||
git config --system core.eol lf
|
||||
git config --system core.longpaths true
|
||||
}
|
||||
}
|
||||
|
||||
function Install-Common-Software {
|
||||
Install-Chocolatey
|
||||
Install-Pwsh
|
||||
Install-Git
|
||||
Install-Packages curl 7zip nssm
|
||||
Install-NodeJs
|
||||
Install-Bun
|
||||
Install-Cygwin
|
||||
if ($CI) {
|
||||
# FIXME: Installing tailscale causes the AWS metadata server to become unreachable
|
||||
# Install-Tailscale
|
||||
Install-Buildkite
|
||||
function Install-NodeJs {
|
||||
# Pin to match the ABI version Bun expects (NODE_MODULE_VERSION 137).
|
||||
# Latest Node (25.x) uses ABI 141 which breaks node-gyp tests.
|
||||
Install-Scoop-Package "nodejs@24.3.0" -Command node
|
||||
}
|
||||
|
||||
function Install-CMake {
|
||||
Install-Scoop-Package cmake
|
||||
}
|
||||
|
||||
function Install-Llvm {
|
||||
$LLVM_VERSION = "21.1.8"
|
||||
if (Which clang-cl) {
|
||||
return
|
||||
}
|
||||
if ($script:IsARM64) {
|
||||
Install-Scoop-Package "llvm-arm64@$LLVM_VERSION" -Command clang-cl
|
||||
} else {
|
||||
Install-Scoop-Package "llvm@$LLVM_VERSION" -Command clang-cl
|
||||
}
|
||||
}
|
||||
|
||||
function Install-Ninja {
|
||||
Install-Scoop-Package ninja
|
||||
}
|
||||
|
||||
function Install-Python {
|
||||
Install-Scoop-Package python
|
||||
}
|
||||
|
||||
function Install-Go {
|
||||
Install-Scoop-Package go
|
||||
}
|
||||
|
||||
function Install-Ruby {
|
||||
Install-Scoop-Package ruby
|
||||
}
|
||||
|
||||
function Install-7zip {
|
||||
Install-Scoop-Package 7zip -Command 7z
|
||||
}
|
||||
|
||||
function Install-Make {
|
||||
Install-Scoop-Package make
|
||||
}
|
||||
|
||||
function Install-Cygwin {
|
||||
# Cygwin's default mirror (mirrors.kernel.org) can be unreachable from Azure.
|
||||
# Make this non-fatal — the build will fail later if cygwin is actually needed.
|
||||
try {
|
||||
Install-Scoop-Package cygwin
|
||||
# Cygwin binaries are at <scoop>/apps/cygwin/current/root/bin
|
||||
$cygwinBin = "C:\Scoop\apps\cygwin\current\root\bin"
|
||||
if (Test-Path $cygwinBin) {
|
||||
Add-To-Path $cygwinBin # Machine scope (default) — survives Sysprep
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "Cygwin installation failed (non-fatal): $_"
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Manual installs (not available or not ideal via Scoop)
|
||||
# ============================================================================
|
||||
|
||||
function Install-Pwsh {
|
||||
Install-Package powershell-core -Command pwsh
|
||||
if (Which pwsh) {
|
||||
return
|
||||
}
|
||||
|
||||
$pwshArch = if ($script:IsARM64) { "arm64" } else { "x64" }
|
||||
Write-Output "Installing PowerShell Core ($pwshArch)..."
|
||||
$msi = Download-File "https://github.com/PowerShell/PowerShell/releases/download/v7.5.2/PowerShell-7.5.2-win-$pwshArch.msi" -Name "pwsh-$pwshArch.msi"
|
||||
$process = Start-Process msiexec -ArgumentList "/i `"$msi`" /quiet /norestart ADD_PATH=1" -Wait -PassThru -NoNewWindow
|
||||
if ($process.ExitCode -ne 0) {
|
||||
throw "Failed to install PowerShell: code $($process.ExitCode)"
|
||||
}
|
||||
Remove-Item $msi -ErrorAction SilentlyContinue
|
||||
Refresh-Path
|
||||
|
||||
if ($CI) {
|
||||
$shellPath = (Which pwsh -Required)
|
||||
@@ -228,34 +305,147 @@ function Install-Pwsh {
|
||||
}
|
||||
}
|
||||
|
||||
function Install-Git {
|
||||
Install-Packages git
|
||||
|
||||
if ($CI) {
|
||||
Execute-Command git config --system --add safe.directory "*"
|
||||
Execute-Command git config --system core.autocrlf false
|
||||
Execute-Command git config --system core.eol lf
|
||||
Execute-Command git config --system core.longpaths true
|
||||
function Install-Ccache {
|
||||
if (Which ccache) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function Install-NodeJs {
|
||||
Install-Package nodejs -Command node -Version "24.3.0"
|
||||
$version = "4.12.2"
|
||||
$archSuffix = if ($script:IsARM64) { "aarch64" } else { "x86_64" }
|
||||
Write-Output "Installing ccache $version ($archSuffix)..."
|
||||
$zip = Download-File "https://github.com/ccache/ccache/releases/download/v$version/ccache-$version-windows-$archSuffix.zip" -Name "ccache-$archSuffix.zip"
|
||||
$extractDir = "$env:TEMP\ccache-extract"
|
||||
Expand-Archive $zip $extractDir -Force
|
||||
$installDir = "$env:ProgramFiles\ccache"
|
||||
New-Item -Path $installDir -ItemType Directory -Force | Out-Null
|
||||
Copy-Item "$extractDir\ccache-$version-windows-$archSuffix\*" $installDir -Recurse -Force
|
||||
Remove-Item $zip -ErrorAction SilentlyContinue
|
||||
Remove-Item $extractDir -Recurse -ErrorAction SilentlyContinue
|
||||
Add-To-Path $installDir
|
||||
}
|
||||
|
||||
function Install-Bun {
|
||||
Install-Package bun -Version "1.3.1"
|
||||
if (Which bun) {
|
||||
return
|
||||
}
|
||||
|
||||
if ($script:IsARM64) {
|
||||
# No published ARM64 bun binary yet — download from our blob storage
|
||||
Write-Output "Installing Bun (ARM64 from blob storage)..."
|
||||
$zip = Download-File "https://buncistore.blob.core.windows.net/artifacts/bun-windows-aarch64.zip" -Name "bun-arm64.zip"
|
||||
$extractDir = "$env:TEMP\bun-arm64"
|
||||
Expand-Archive -Path $zip -DestinationPath $extractDir -Force
|
||||
$bunExe = Get-ChildItem $extractDir -Recurse -Filter "*.exe" | Where-Object { $_.Name -match "bun" } | Select-Object -First 1
|
||||
if ($bunExe) {
|
||||
Copy-Item $bunExe.FullName "C:\Windows\System32\bun.exe" -Force
|
||||
Write-Output "Bun ARM64 installed to C:\Windows\System32\bun.exe"
|
||||
} else {
|
||||
throw "Failed to find bun executable in ARM64 zip"
|
||||
}
|
||||
} else {
|
||||
Write-Output "Installing Bun..."
|
||||
$installScript = Download-File "https://bun.sh/install.ps1" -Name "bun-install.ps1"
|
||||
$pwsh = Which pwsh powershell -Required
|
||||
& $pwsh $installScript
|
||||
Refresh-Path
|
||||
# Copy to System32 so it survives Sysprep (user profile PATH is lost)
|
||||
$bunPath = Which bun
|
||||
if ($bunPath) {
|
||||
Copy-Item $bunPath "C:\Windows\System32\bun.exe" -Force
|
||||
Write-Output "Bun copied to C:\Windows\System32\bun.exe"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Install-Cygwin {
|
||||
Install-Package cygwin
|
||||
Add-To-Path "C:\tools\cygwin\bin"
|
||||
function Install-Rust {
|
||||
if (Which rustc) {
|
||||
return
|
||||
}
|
||||
|
||||
$rustPath = Join-Path $env:ProgramFiles "Rust"
|
||||
if (-not (Test-Path $rustPath)) {
|
||||
New-Item -Path $rustPath -ItemType Directory | Out-Null
|
||||
}
|
||||
|
||||
# Set install paths before running rustup so it installs directly
|
||||
# to Program Files (avoids issues with SYSTEM user profile path)
|
||||
$env:CARGO_HOME = "$rustPath\cargo"
|
||||
$env:RUSTUP_HOME = "$rustPath\rustup"
|
||||
|
||||
Write-Output "Installing Rustup..."
|
||||
$rustupInit = Download-File "https://win.rustup.rs/" -Name "rustup-init.exe"
|
||||
|
||||
Write-Output "Installing Rust..."
|
||||
& $rustupInit -y
|
||||
|
||||
Write-Output "Setting environment variables for Rust..."
|
||||
Set-Env "CARGO_HOME" "$rustPath\cargo"
|
||||
Set-Env "RUSTUP_HOME" "$rustPath\rustup"
|
||||
Add-To-Path "$rustPath\cargo\bin"
|
||||
}
|
||||
|
||||
function Install-Tailscale {
|
||||
Install-Package tailscale
|
||||
function Install-Visual-Studio {
|
||||
param (
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Edition = "community"
|
||||
)
|
||||
|
||||
Write-Output "Downloading Visual Studio installer..."
|
||||
$vsInstaller = Download-File "https://aka.ms/vs/17/release/vs_$Edition.exe"
|
||||
|
||||
Write-Output "Installing Visual Studio..."
|
||||
$vsInstallArgs = @(
|
||||
"--passive",
|
||||
"--norestart",
|
||||
"--wait",
|
||||
"--force",
|
||||
"--locale en-US",
|
||||
"--add Microsoft.VisualStudio.Workload.NativeDesktop",
|
||||
"--includeRecommended"
|
||||
)
|
||||
$process = Start-Process $vsInstaller -ArgumentList ($vsInstallArgs -join ' ') -Wait -PassThru -NoNewWindow
|
||||
# Exit code 3010 means "reboot required" which is not a real error
|
||||
if ($process.ExitCode -ne 0 -and $process.ExitCode -ne 3010) {
|
||||
throw "Failed to install Visual Studio: code $($process.ExitCode)"
|
||||
}
|
||||
}
|
||||
|
||||
function Install-PdbAddr2line {
|
||||
cargo install --examples "pdb-addr2line@0.11.2"
|
||||
# Also copy to System32 so it's always on PATH (like bun.exe)
|
||||
$src = Join-Path $env:CARGO_HOME "bin\pdb-addr2line.exe"
|
||||
if (Test-Path $src) {
|
||||
Copy-Item $src "C:\Windows\System32\pdb-addr2line.exe" -Force
|
||||
Write-Output "pdb-addr2line copied to C:\Windows\System32"
|
||||
}
|
||||
}
|
||||
|
||||
function Install-Nssm {
|
||||
if (Which nssm) {
|
||||
return
|
||||
}
|
||||
|
||||
# Try Scoop first, fall back to our mirror if nssm.cc is down (503 errors)
|
||||
Install-Scoop-Package nssm
|
||||
|
||||
if (-not (Which nssm)) {
|
||||
Write-Output "Scoop install of nssm failed, downloading from mirror..."
|
||||
$zip = Download-File "https://buncistore.blob.core.windows.net/artifacts/nssm-2.24-103-gdee49fc.zip" -Name "nssm.zip"
|
||||
Expand-Archive -Path $zip -DestinationPath "C:\Windows\Temp\nssm" -Force
|
||||
$nssm = Get-ChildItem "C:\Windows\Temp\nssm" -Recurse -Filter "nssm.exe" | Where-Object { $_.DirectoryName -like "*win64*" } | Select-Object -First 1
|
||||
if ($nssm) {
|
||||
Copy-Item $nssm.FullName "C:\Windows\System32\nssm.exe" -Force
|
||||
Write-Output "nssm installed to C:\Windows\System32\nssm.exe"
|
||||
} else {
|
||||
throw "Failed to install nssm"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Buildkite
|
||||
# ============================================================================
|
||||
|
||||
function Create-Buildkite-Environment-Hooks {
|
||||
param (
|
||||
[Parameter(Mandatory = $true)]
|
||||
@@ -288,7 +478,8 @@ function Install-Buildkite {
|
||||
Write-Output "Installing Buildkite agent..."
|
||||
$env:buildkiteAgentToken = "xxx"
|
||||
$installScript = Download-File "https://raw.githubusercontent.com/buildkite/agent/main/install.ps1"
|
||||
Execute-Script $installScript
|
||||
$pwsh = Which pwsh powershell -Required
|
||||
& $pwsh $installScript
|
||||
Refresh-Path
|
||||
|
||||
if ($CI) {
|
||||
@@ -300,96 +491,9 @@ function Install-Buildkite {
|
||||
}
|
||||
}
|
||||
|
||||
function Install-Build-Essentials {
|
||||
Install-Visual-Studio
|
||||
Install-Packages `
|
||||
cmake `
|
||||
make `
|
||||
ninja `
|
||||
python `
|
||||
golang `
|
||||
nasm `
|
||||
ruby `
|
||||
strawberryperl `
|
||||
mingw
|
||||
Install-Rust
|
||||
Install-Ccache
|
||||
# Needed to remap stack traces
|
||||
Install-PdbAddr2line
|
||||
Install-Llvm
|
||||
}
|
||||
|
||||
function Install-Visual-Studio {
|
||||
param (
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Edition = "community"
|
||||
)
|
||||
|
||||
Write-Output "Downloading Visual Studio installer..."
|
||||
$vsInstaller = Download-File "https://aka.ms/vs/17/release/vs_$Edition.exe"
|
||||
|
||||
Write-Output "Installing Visual Studio..."
|
||||
$vsInstallArgs = @(
|
||||
"--passive",
|
||||
"--norestart",
|
||||
"--wait",
|
||||
"--force",
|
||||
"--locale en-US",
|
||||
"--add Microsoft.VisualStudio.Workload.NativeDesktop",
|
||||
"--includeRecommended"
|
||||
)
|
||||
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$startInfo.FileName = $vsInstaller
|
||||
$startInfo.Arguments = $vsInstallArgs -join ' '
|
||||
$startInfo.CreateNoWindow = $true
|
||||
$process = New-Object System.Diagnostics.Process
|
||||
$process.StartInfo = $startInfo
|
||||
$process.Start()
|
||||
$process.WaitForExit()
|
||||
if ($process.ExitCode -ne 0) {
|
||||
throw "Failed to install Visual Studio: code $($process.ExitCode)"
|
||||
}
|
||||
}
|
||||
|
||||
function Install-Rust {
|
||||
if (Which rustc) {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Output "Installing Rustup..."
|
||||
$rustupInit = Download-File "https://win.rustup.rs/" -Name "rustup-init.exe"
|
||||
|
||||
Write-Output "Installing Rust..."
|
||||
Execute-Command $rustupInit -y
|
||||
|
||||
Write-Output "Moving Rust to $env:ProgramFiles..."
|
||||
$rustPath = Join-Path $env:ProgramFiles "Rust"
|
||||
if (-not (Test-Path $rustPath)) {
|
||||
New-Item -Path $rustPath -ItemType Directory
|
||||
}
|
||||
Move-Item "$env:UserProfile\.cargo" "$rustPath\cargo" -Force
|
||||
Move-Item "$env:UserProfile\.rustup" "$rustPath\rustup" -Force
|
||||
|
||||
Write-Output "Setting environment variables for Rust..."
|
||||
Set-Env "CARGO_HOME" "$rustPath\cargo"
|
||||
Set-Env "RUSTUP_HOME" "$rustPath\rustup"
|
||||
Add-To-Path "$rustPath\cargo\bin"
|
||||
}
|
||||
|
||||
function Install-Ccache {
|
||||
Install-Package ccache
|
||||
}
|
||||
|
||||
function Install-PdbAddr2line {
|
||||
Execute-Command cargo install --examples "pdb-addr2line@0.11.2"
|
||||
}
|
||||
|
||||
function Install-Llvm {
|
||||
Install-Package llvm `
|
||||
-Command clang-cl `
|
||||
-Version "21.1.8"
|
||||
Add-To-Path "$env:ProgramFiles\LLVM\bin"
|
||||
}
|
||||
# ============================================================================
|
||||
# System optimization
|
||||
# ============================================================================
|
||||
|
||||
function Optimize-System {
|
||||
Disable-Windows-Defender
|
||||
@@ -417,8 +521,11 @@ function Disable-Windows-Threat-Protection {
|
||||
}
|
||||
|
||||
function Uninstall-Windows-Defender {
|
||||
Write-Output "Uninstalling Windows Defender..."
|
||||
Uninstall-WindowsFeature -Name Windows-Defender
|
||||
# Requires a reboot — run before the windows-restart Packer provisioner.
|
||||
if (Get-Command Uninstall-WindowsFeature -ErrorAction SilentlyContinue) {
|
||||
Write-Output "Uninstalling Windows Defender..."
|
||||
Uninstall-WindowsFeature -Name Windows-Defender
|
||||
}
|
||||
}
|
||||
|
||||
function Disable-Windows-Services {
|
||||
@@ -432,8 +539,12 @@ function Disable-Windows-Services {
|
||||
)
|
||||
|
||||
foreach ($service in $services) {
|
||||
Stop-Service $service -Force
|
||||
Set-Service $service -StartupType Disabled
|
||||
try {
|
||||
Stop-Service $service -Force -ErrorAction SilentlyContinue
|
||||
Set-Service $service -StartupType Disabled -ErrorAction SilentlyContinue
|
||||
} catch {
|
||||
Write-Warning "Could not disable service: $service"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,13 +559,52 @@ function Disable-Power-Management {
|
||||
powercfg /change hibernate-timeout-dc 0
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Main
|
||||
# ============================================================================
|
||||
|
||||
if ($Optimize) {
|
||||
Optimize-System
|
||||
}
|
||||
|
||||
Install-Common-Software
|
||||
Install-Build-Essentials
|
||||
# Scoop package manager
|
||||
Install-Scoop
|
||||
|
||||
# Packages via Scoop (native ARM64 or x64 depending on architecture)
|
||||
# 7zip must be installed before git — git depends on 7zip via Scoop,
|
||||
# and 7zip's post_install has a cleanup error on ARM64 SYSTEM context.
|
||||
Install-7zip
|
||||
Install-Git
|
||||
Install-NodeJs
|
||||
Install-CMake
|
||||
Install-Ninja
|
||||
Install-Python
|
||||
Install-Go
|
||||
Install-Ruby
|
||||
Install-Make
|
||||
Install-Llvm
|
||||
Install-Cygwin
|
||||
Install-Nssm
|
||||
Install-Scoop-Package perl
|
||||
|
||||
# x64-only packages (not needed on ARM64)
|
||||
if (-not $script:IsARM64) {
|
||||
Install-Scoop-Package nasm
|
||||
Install-Scoop-Package mingw -Command gcc
|
||||
}
|
||||
|
||||
# Manual installs (not in Scoop or need special handling)
|
||||
Install-Pwsh
|
||||
Install-Bun
|
||||
Install-Ccache
|
||||
Install-Rust
|
||||
Install-Visual-Studio
|
||||
Install-PdbAddr2line
|
||||
|
||||
if ($CI) {
|
||||
Install-Buildkite
|
||||
}
|
||||
|
||||
if ($Optimize) {
|
||||
Optimize-System-Needs-Reboot
|
||||
}
|
||||
}
|
||||
@@ -14,14 +14,7 @@ import {
|
||||
startGroup,
|
||||
} from "./utils.mjs";
|
||||
|
||||
// Detect Windows ARM64 - bun may run under x64 emulation (WoW64), so check multiple indicators
|
||||
const isWindowsARM64 =
|
||||
isWindows &&
|
||||
(process.env.PROCESSOR_ARCHITECTURE === "ARM64" ||
|
||||
process.env.VSCMD_ARG_HOST_ARCH === "arm64" ||
|
||||
process.env.MSYSTEM_CARCH === "aarch64" ||
|
||||
(process.env.PROCESSOR_IDENTIFIER || "").includes("ARMv8") ||
|
||||
process.arch === "arm64");
|
||||
const isWindowsARM64 = isWindows && process.arch === "arm64";
|
||||
|
||||
if (globalThis.Bun) {
|
||||
await import("./glob-sources.mjs");
|
||||
@@ -57,11 +50,7 @@ async function build(args) {
|
||||
if (process.platform === "win32" && !process.env["VSINSTALLDIR"]) {
|
||||
const shellPath = join(import.meta.dirname, "vs-shell.ps1");
|
||||
const scriptPath = import.meta.filename;
|
||||
// When cross-compiling to ARM64, tell vs-shell.ps1 to set up the x64_arm64 VS environment
|
||||
const toolchainIdx = args.indexOf("--toolchain");
|
||||
const requestedVsArch = toolchainIdx !== -1 && args[toolchainIdx + 1] === "windows-aarch64" ? "arm64" : undefined;
|
||||
const env = requestedVsArch ? { ...process.env, BUN_VS_ARCH: requestedVsArch } : undefined;
|
||||
return spawn("pwsh", ["-NoProfile", "-NoLogo", "-File", shellPath, process.argv0, scriptPath, ...args], { env });
|
||||
return spawn("pwsh", ["-NoProfile", "-NoLogo", "-File", shellPath, process.argv0, scriptPath, ...args]);
|
||||
}
|
||||
|
||||
if (isCI) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { existsSync, mkdtempSync, readdirSync } from "node:fs";
|
||||
import { chmodSync, existsSync, mkdtempSync, readdirSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { basename, extname, join, relative, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { inspect, parseArgs } from "node:util";
|
||||
import { azure } from "./azure.mjs";
|
||||
import { docker } from "./docker.mjs";
|
||||
import { tart } from "./tart.mjs";
|
||||
import {
|
||||
@@ -35,7 +37,6 @@ import {
|
||||
spawnSshSafe,
|
||||
spawnSyncSafe,
|
||||
startGroup,
|
||||
tmpdir,
|
||||
waitForPort,
|
||||
which,
|
||||
writeFile,
|
||||
@@ -1047,16 +1048,14 @@ function getRdpFile(hostname, username) {
|
||||
* @property {(options: MachineOptions) => Promise<Machine>} createMachine
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Cloud}
|
||||
*/
|
||||
function getCloud(name) {
|
||||
switch (name) {
|
||||
case "docker":
|
||||
return docker;
|
||||
case "aws":
|
||||
return aws;
|
||||
case "azure":
|
||||
return azure;
|
||||
case "tart":
|
||||
return tart;
|
||||
}
|
||||
@@ -1127,6 +1126,173 @@ function getCloud(name) {
|
||||
* @property {SshKey[]} sshKeys
|
||||
*/
|
||||
|
||||
async function getAzureToken(tenantId, clientId, clientSecret) {
|
||||
const response = await fetch(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: `grant_type=client_credentials&client_id=${clientId}&client_secret=${encodeURIComponent(clientSecret)}&scope=https://management.azure.com/.default`,
|
||||
});
|
||||
if (!response.ok) throw new Error(`Azure auth failed: ${response.status}`);
|
||||
const data = await response.json();
|
||||
return data.access_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Windows image using Packer (Azure only).
|
||||
* Packer handles VM creation, bootstrap, sysprep, and gallery capture via WinRM.
|
||||
* This eliminates all the Azure Run Command issues (output truncation, x64 emulation,
|
||||
* PATH not refreshing, stderr false positives, quote escaping).
|
||||
*/
|
||||
async function buildWindowsImageWithPacker({ os, arch, release, command, ci, agentPath, bootstrapPath }) {
|
||||
const { getSecret } = await import("./utils.mjs");
|
||||
|
||||
// Determine Packer template
|
||||
const templateName = arch === "aarch64" ? "windows-arm64" : "windows-x64";
|
||||
const templateDir = resolve(import.meta.dirname, "packer");
|
||||
const templateFile = join(templateDir, `${templateName}.pkr.hcl`);
|
||||
|
||||
if (!existsSync(templateFile)) {
|
||||
throw new Error(`Packer template not found: ${templateFile}`);
|
||||
}
|
||||
|
||||
// Get Azure credentials from Buildkite secrets
|
||||
const clientId = await getSecret("AZURE_CLIENT_ID");
|
||||
const clientSecret = await getSecret("AZURE_CLIENT_SECRET");
|
||||
const subscriptionId = await getSecret("AZURE_SUBSCRIPTION_ID");
|
||||
const tenantId = await getSecret("AZURE_TENANT_ID");
|
||||
const resourceGroup = await getSecret("AZURE_RESOURCE_GROUP");
|
||||
const location = (await getSecret("AZURE_LOCATION")) || "eastus2";
|
||||
const galleryName = (await getSecret("AZURE_GALLERY_NAME")) || "bunCIGallery2";
|
||||
|
||||
// Image naming must match getImageName() in ci.mjs:
|
||||
// [publish images] / normal CI: "windows-x64-2019-v13"
|
||||
// [build images]: "windows-x64-2019-build-37194"
|
||||
const imageKey = arch === "aarch64" ? "windows-aarch64-11" : "windows-x64-2019";
|
||||
const imageDefName =
|
||||
command === "publish-image"
|
||||
? `${imageKey}-v${getBootstrapVersion(os)}`
|
||||
: ci
|
||||
? `${imageKey}-build-${getBuildNumber()}`
|
||||
: `${imageKey}-build-draft-${Date.now()}`;
|
||||
const galleryArch = arch === "aarch64" ? "Arm64" : "x64";
|
||||
console.log(`[packer] Ensuring gallery image definition: ${imageDefName}`);
|
||||
const galleryPath = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.Compute/galleries/${galleryName}/images/${imageDefName}`;
|
||||
const token = await getAzureToken(tenantId, clientId, clientSecret);
|
||||
const defResponse = await fetch(`https://management.azure.com${galleryPath}?api-version=2024-03-03`, {
|
||||
method: "PUT",
|
||||
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
location: location,
|
||||
properties: {
|
||||
osType: "Windows",
|
||||
osState: "Generalized",
|
||||
hyperVGeneration: "V2",
|
||||
architecture: galleryArch,
|
||||
identifier: { publisher: "bun", offer: `${os}-${arch}-ci`, sku: imageDefName },
|
||||
features: [
|
||||
{ name: "DiskControllerTypes", value: "SCSI, NVMe" },
|
||||
{ name: "SecurityType", value: "TrustedLaunch" },
|
||||
],
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!defResponse.ok && defResponse.status !== 409) {
|
||||
throw new Error(`Failed to create gallery image definition: ${defResponse.status} ${await defResponse.text()}`);
|
||||
}
|
||||
|
||||
// Install Packer if not available
|
||||
const packerBin = await ensurePacker();
|
||||
|
||||
// Initialize plugins
|
||||
console.log("[packer] Initializing plugins...");
|
||||
await spawnSafe([packerBin, "init", templateDir], { stdio: "inherit" });
|
||||
|
||||
// Build the image
|
||||
console.log(`[packer] Building ${templateName} image: ${imageDefName}`);
|
||||
const packerArgs = [
|
||||
packerBin,
|
||||
"build",
|
||||
"-only",
|
||||
`azure-arm.${templateName}`,
|
||||
"-var",
|
||||
`client_id=${clientId}`,
|
||||
"-var",
|
||||
`client_secret=${clientSecret}`,
|
||||
"-var",
|
||||
`subscription_id=${subscriptionId}`,
|
||||
"-var",
|
||||
`tenant_id=${tenantId}`,
|
||||
"-var",
|
||||
`resource_group=${resourceGroup}-EASTUS2`,
|
||||
"-var",
|
||||
`gallery_resource_group=${resourceGroup}`,
|
||||
"-var",
|
||||
`location=${location}`,
|
||||
"-var",
|
||||
`gallery_name=${galleryName}`,
|
||||
"-var",
|
||||
`image_name=${imageDefName}`,
|
||||
"-var",
|
||||
`bootstrap_script=${bootstrapPath}`,
|
||||
"-var",
|
||||
`agent_script=${agentPath}`,
|
||||
templateDir,
|
||||
];
|
||||
|
||||
await spawnSafe(packerArgs, {
|
||||
stdio: "inherit",
|
||||
env: {
|
||||
...process.env,
|
||||
// Packer also reads these env vars
|
||||
ARM_CLIENT_ID: clientId,
|
||||
ARM_CLIENT_SECRET: clientSecret,
|
||||
ARM_SUBSCRIPTION_ID: subscriptionId,
|
||||
ARM_TENANT_ID: tenantId,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`[packer] Image built successfully: ${imageDefName}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download and install Packer if not already available.
|
||||
*/
|
||||
async function ensurePacker() {
|
||||
// Check if packer is already in PATH
|
||||
const packerPath = which("packer");
|
||||
if (packerPath) {
|
||||
console.log("[packer] Found:", packerPath);
|
||||
return packerPath;
|
||||
}
|
||||
|
||||
// Check if we have a local copy
|
||||
const localPacker = join(tmpdir(), "packer");
|
||||
if (existsSync(localPacker)) {
|
||||
return localPacker;
|
||||
}
|
||||
|
||||
// Download Packer
|
||||
const version = "1.15.0";
|
||||
const platform = process.platform === "win32" ? "windows" : process.platform;
|
||||
const packerArch = process.arch === "arm64" ? "arm64" : "amd64";
|
||||
const url = `https://releases.hashicorp.com/packer/${version}/packer_${version}_${platform}_${packerArch}.zip`;
|
||||
|
||||
console.log(`[packer] Downloading Packer ${version}...`);
|
||||
const zipPath = join(tmpdir(), "packer.zip");
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error(`Failed to download Packer: ${response.status}`);
|
||||
const buffer = Buffer.from(await response.arrayBuffer());
|
||||
writeFileSync(zipPath, buffer);
|
||||
|
||||
// Extract
|
||||
await spawnSafe(["unzip", "-o", zipPath, "-d", tmpdir()], { stdio: "inherit" });
|
||||
chmodSync(localPacker, 0o755);
|
||||
|
||||
console.log(`[packer] Installed Packer ${version}`);
|
||||
return localPacker;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { positionals } = parseArgs({
|
||||
allowPositionals: true,
|
||||
@@ -1269,6 +1435,13 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Use Packer for Windows Azure image builds — it handles VM creation,
|
||||
// bootstrap, sysprep, and gallery capture via WinRM (no Run Command hacks).
|
||||
if (args["cloud"] === "azure" && os === "windows" && (command === "create-image" || command === "publish-image")) {
|
||||
await buildWindowsImageWithPacker({ os, arch, release, command, ci, agentPath, bootstrapPath });
|
||||
return;
|
||||
}
|
||||
|
||||
/** @type {Machine} */
|
||||
const machine = await startGroup("Creating machine...", async () => {
|
||||
console.log("Creating machine:");
|
||||
@@ -1342,7 +1515,7 @@ async function main() {
|
||||
});
|
||||
}
|
||||
|
||||
await startGroup("Connecting with SSH...", async () => {
|
||||
await startGroup(`Connecting${options.cloud === "azure" ? "" : " with SSH"}...`, async () => {
|
||||
const command = os === "windows" ? ["cmd", "/c", "ver"] : ["uname", "-a"];
|
||||
await machine.spawnSafe(command, { stdio: "inherit" });
|
||||
});
|
||||
@@ -1392,7 +1565,12 @@ async function main() {
|
||||
if (cloud.name === "docker" || features?.includes("docker")) {
|
||||
return;
|
||||
}
|
||||
await machine.spawnSafe(["node", remotePath, "install"], { stdio: "inherit" });
|
||||
// Refresh PATH from registry before running agent.mjs — bootstrap added
|
||||
// buildkite-agent to PATH but Azure Run Command sessions have stale PATH.
|
||||
const cmd = `$env:PATH = [Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' + [Environment]::GetEnvironmentVariable('PATH', 'User'); C:\\Scoop\\apps\\nodejs\\current\\node.exe ${remotePath} install`;
|
||||
await machine.spawnSafe(["powershell", "-NoProfile", "-Command", cmd], {
|
||||
stdio: "inherit",
|
||||
});
|
||||
});
|
||||
} else {
|
||||
const tmpPath = "/tmp/agent.mjs";
|
||||
|
||||
74
scripts/packer/variables.pkr.hcl
Normal file
74
scripts/packer/variables.pkr.hcl
Normal file
@@ -0,0 +1,74 @@
|
||||
packer {
|
||||
required_plugins {
|
||||
azure = {
|
||||
source = "github.com/hashicorp/azure"
|
||||
version = "= 2.5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shared variables for all Windows image builds
|
||||
|
||||
variable "client_id" {
|
||||
type = string
|
||||
default = env("AZURE_CLIENT_ID")
|
||||
}
|
||||
|
||||
variable "client_secret" {
|
||||
type = string
|
||||
sensitive = true
|
||||
default = env("AZURE_CLIENT_SECRET")
|
||||
}
|
||||
|
||||
variable "subscription_id" {
|
||||
type = string
|
||||
default = env("AZURE_SUBSCRIPTION_ID")
|
||||
}
|
||||
|
||||
variable "tenant_id" {
|
||||
type = string
|
||||
default = env("AZURE_TENANT_ID")
|
||||
}
|
||||
|
||||
variable "resource_group" {
|
||||
type = string
|
||||
default = env("AZURE_RESOURCE_GROUP")
|
||||
}
|
||||
|
||||
variable "location" {
|
||||
type = string
|
||||
default = "eastus2"
|
||||
}
|
||||
|
||||
variable "gallery_name" {
|
||||
type = string
|
||||
default = "bunCIGallery2"
|
||||
}
|
||||
|
||||
variable "build_number" {
|
||||
type = string
|
||||
default = "0"
|
||||
}
|
||||
|
||||
variable "image_name" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Gallery image definition name. If empty, derived from build_number."
|
||||
}
|
||||
|
||||
variable "bootstrap_script" {
|
||||
type = string
|
||||
default = "scripts/bootstrap.ps1"
|
||||
}
|
||||
|
||||
variable "agent_script" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Path to bundled agent.mjs. If empty, agent install is skipped."
|
||||
}
|
||||
|
||||
variable "gallery_resource_group" {
|
||||
type = string
|
||||
default = "BUN-CI"
|
||||
description = "Resource group containing the Compute Gallery (may differ from build RG)"
|
||||
}
|
||||
119
scripts/packer/windows-arm64.pkr.hcl
Normal file
119
scripts/packer/windows-arm64.pkr.hcl
Normal file
@@ -0,0 +1,119 @@
|
||||
source "azure-arm" "windows-arm64" {
|
||||
// Authentication
|
||||
client_id = var.client_id
|
||||
client_secret = var.client_secret
|
||||
subscription_id = var.subscription_id
|
||||
tenant_id = var.tenant_id
|
||||
|
||||
// Source image — Windows 11 ARM64 (no Windows Server ARM64 exists)
|
||||
os_type = "Windows"
|
||||
image_publisher = "MicrosoftWindowsDesktop"
|
||||
image_offer = "windows11preview-arm64"
|
||||
image_sku = "win11-24h2-pro"
|
||||
image_version = "latest"
|
||||
|
||||
// Build VM — only used during image creation, not for CI runners.
|
||||
// CI runner VM sizes are set in ci.mjs (azureVmSizes).
|
||||
vm_size = "Standard_D4ps_v6"
|
||||
|
||||
// Use existing resource group instead of creating a temp one
|
||||
build_resource_group_name = var.resource_group
|
||||
os_disk_size_gb = 150
|
||||
|
||||
// Security
|
||||
security_type = "TrustedLaunch"
|
||||
secure_boot_enabled = true
|
||||
vtpm_enabled = true
|
||||
|
||||
// Networking — Packer creates a temp VNet + public IP + NSG automatically.
|
||||
|
||||
// WinRM communicator
|
||||
communicator = "winrm"
|
||||
winrm_use_ssl = true
|
||||
winrm_insecure = true
|
||||
winrm_timeout = "15m"
|
||||
winrm_username = "packer"
|
||||
|
||||
// CRITICAL: No managed_image_name — ARM64 doesn't support Managed Images.
|
||||
// Packer publishes directly from the VM to the gallery (PR #242 feature).
|
||||
|
||||
shared_image_gallery_destination {
|
||||
subscription = var.subscription_id
|
||||
resource_group = var.gallery_resource_group
|
||||
gallery_name = var.gallery_name
|
||||
image_name = var.image_name != "" ? var.image_name : "windows-aarch64-11-build-${var.build_number}"
|
||||
image_version = "1.0.0"
|
||||
storage_account_type = "Standard_LRS"
|
||||
target_region {
|
||||
name = var.location
|
||||
}
|
||||
}
|
||||
|
||||
azure_tags = {
|
||||
os = "windows"
|
||||
arch = "aarch64"
|
||||
build = var.build_number
|
||||
}
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.azure-arm.windows-arm64"]
|
||||
|
||||
// Step 1: Run bootstrap — installs all build dependencies
|
||||
provisioner "powershell" {
|
||||
script = var.bootstrap_script
|
||||
valid_exit_codes = [0, 3010]
|
||||
environment_vars = ["CI=true"]
|
||||
}
|
||||
|
||||
// Step 2: Upload agent.mjs
|
||||
provisioner "file" {
|
||||
source = var.agent_script
|
||||
destination = "C:\\buildkite-agent\\agent.mjs"
|
||||
}
|
||||
|
||||
// Step 3: Install agent service via nssm
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
"C:\\Scoop\\apps\\nodejs\\current\\node.exe C:\\buildkite-agent\\agent.mjs install"
|
||||
]
|
||||
valid_exit_codes = [0]
|
||||
}
|
||||
|
||||
// Step 4: Reboot to clear pending updates (VS Build Tools, Windows Updates)
|
||||
provisioner "windows-restart" {
|
||||
restart_timeout = "10m"
|
||||
}
|
||||
|
||||
// Step 5: Sysprep — MUST be last provisioner
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
"Remove-Item -Recurse -Force C:\\Windows\\Panther -ErrorAction SilentlyContinue",
|
||||
"Write-Output '>>> Clearing pending reboot flags...'",
|
||||
"Remove-Item 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending' -Recurse -Force -ErrorAction SilentlyContinue",
|
||||
"Remove-ItemProperty 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update' -Name 'RebootRequired' -Force -ErrorAction SilentlyContinue",
|
||||
"Remove-Item 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update\\RebootRequired' -Recurse -Force -ErrorAction SilentlyContinue",
|
||||
"Remove-ItemProperty 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Session Manager' -Name 'PendingFileRenameOperations' -Force -ErrorAction SilentlyContinue",
|
||||
"Write-Output '>>> Waiting for Azure Guest Agent...'",
|
||||
"while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
|
||||
"while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
|
||||
"Write-Output '>>> Running Sysprep...'",
|
||||
"$global:LASTEXITCODE = 0",
|
||||
"& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm",
|
||||
"$timeout = 300; $elapsed = 0",
|
||||
"while ($true) {",
|
||||
" $imageState = (Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State).ImageState",
|
||||
" Write-Output \"ImageState: $imageState ($${elapsed}s)\"",
|
||||
" if ($imageState -eq 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { break }",
|
||||
" if ($elapsed -ge $timeout) {",
|
||||
" Write-Error \"Timed out after $${timeout}s -- stuck at $imageState\"",
|
||||
" Get-Content \"$env:SystemRoot\\System32\\Sysprep\\Panther\\setupact.log\" -Tail 100 -ErrorAction SilentlyContinue",
|
||||
" exit 1",
|
||||
" }",
|
||||
" Start-Sleep -s 10",
|
||||
" $elapsed += 10",
|
||||
"}",
|
||||
"Write-Output '>>> Sysprep complete.'"
|
||||
]
|
||||
}
|
||||
}
|
||||
120
scripts/packer/windows-x64.pkr.hcl
Normal file
120
scripts/packer/windows-x64.pkr.hcl
Normal file
@@ -0,0 +1,120 @@
|
||||
source "azure-arm" "windows-x64" {
|
||||
// Authentication (from env vars or -var flags)
|
||||
client_id = var.client_id
|
||||
client_secret = var.client_secret
|
||||
subscription_id = var.subscription_id
|
||||
tenant_id = var.tenant_id
|
||||
|
||||
// Source image — Windows Server 2019 Gen2
|
||||
os_type = "Windows"
|
||||
image_publisher = "MicrosoftWindowsServer"
|
||||
image_offer = "WindowsServer"
|
||||
image_sku = "2019-datacenter-gensecond"
|
||||
image_version = "latest"
|
||||
|
||||
// Build VM — only used during image creation, not for CI runners.
|
||||
// CI runner VM sizes are set in ci.mjs (azureVmSizes).
|
||||
vm_size = "Standard_D4ds_v6"
|
||||
|
||||
// Use existing resource group instead of creating a temp one
|
||||
build_resource_group_name = var.resource_group
|
||||
os_disk_size_gb = 150
|
||||
|
||||
// Security
|
||||
security_type = "TrustedLaunch"
|
||||
secure_boot_enabled = true
|
||||
vtpm_enabled = true
|
||||
|
||||
// Networking — Packer creates a temp VNet + public IP + NSG automatically.
|
||||
// WinRM needs the public IP to connect from CI runners.
|
||||
|
||||
// WinRM communicator — Packer auto-configures via temp Key Vault
|
||||
communicator = "winrm"
|
||||
winrm_use_ssl = true
|
||||
winrm_insecure = true
|
||||
winrm_timeout = "15m"
|
||||
winrm_username = "packer"
|
||||
|
||||
// Output — Managed Image (x64 supports this)
|
||||
|
||||
// Also publish to Compute Gallery
|
||||
shared_image_gallery_destination {
|
||||
subscription = var.subscription_id
|
||||
resource_group = var.gallery_resource_group
|
||||
gallery_name = var.gallery_name
|
||||
image_name = var.image_name != "" ? var.image_name : "windows-x64-2019-build-${var.build_number}"
|
||||
image_version = "1.0.0"
|
||||
storage_account_type = "Standard_LRS"
|
||||
target_region {
|
||||
name = var.location
|
||||
}
|
||||
}
|
||||
|
||||
azure_tags = {
|
||||
os = "windows"
|
||||
arch = "x64"
|
||||
build = var.build_number
|
||||
}
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.azure-arm.windows-x64"]
|
||||
|
||||
// Step 1: Run bootstrap — installs all build dependencies
|
||||
provisioner "powershell" {
|
||||
script = var.bootstrap_script
|
||||
valid_exit_codes = [0, 3010]
|
||||
environment_vars = ["CI=true"]
|
||||
}
|
||||
|
||||
// Step 2: Upload agent.mjs
|
||||
provisioner "file" {
|
||||
source = var.agent_script
|
||||
destination = "C:\\buildkite-agent\\agent.mjs"
|
||||
}
|
||||
|
||||
// Step 3: Install agent service via nssm
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
"C:\\Scoop\\apps\\nodejs\\current\\node.exe C:\\buildkite-agent\\agent.mjs install"
|
||||
]
|
||||
valid_exit_codes = [0]
|
||||
}
|
||||
|
||||
// Step 4: Reboot to clear pending updates (VS Build Tools, Windows Updates)
|
||||
provisioner "windows-restart" {
|
||||
restart_timeout = "10m"
|
||||
}
|
||||
|
||||
// Step 5: Sysprep — MUST be last provisioner
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
"Remove-Item -Recurse -Force C:\\Windows\\Panther -ErrorAction SilentlyContinue",
|
||||
"Write-Output '>>> Clearing pending reboot flags...'",
|
||||
"Remove-Item 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending' -Recurse -Force -ErrorAction SilentlyContinue",
|
||||
"Remove-ItemProperty 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update' -Name 'RebootRequired' -Force -ErrorAction SilentlyContinue",
|
||||
"Remove-Item 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update\\RebootRequired' -Recurse -Force -ErrorAction SilentlyContinue",
|
||||
"Remove-ItemProperty 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Session Manager' -Name 'PendingFileRenameOperations' -Force -ErrorAction SilentlyContinue",
|
||||
"Write-Output '>>> Waiting for Azure Guest Agent...'",
|
||||
"while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
|
||||
"while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
|
||||
"Write-Output '>>> Running Sysprep...'",
|
||||
"$global:LASTEXITCODE = 0",
|
||||
"& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm",
|
||||
"$timeout = 300; $elapsed = 0",
|
||||
"while ($true) {",
|
||||
" $imageState = (Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State).ImageState",
|
||||
" Write-Output \"ImageState: $imageState ($${elapsed}s)\"",
|
||||
" if ($imageState -eq 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { break }",
|
||||
" if ($elapsed -ge $timeout) {",
|
||||
" Write-Error \"Timed out after $${timeout}s -- stuck at $imageState\"",
|
||||
" Get-Content \"$env:SystemRoot\\System32\\Sysprep\\Panther\\setupact.log\" -Tail 100 -ErrorAction SilentlyContinue",
|
||||
" exit 1",
|
||||
" }",
|
||||
" Start-Sleep -s 10",
|
||||
" $elapsed += 10",
|
||||
"}",
|
||||
"Write-Output '>>> Sysprep complete.'"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -2043,7 +2043,7 @@ export function getShell() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {"aws" | "google"} Cloud
|
||||
* @typedef {"aws" | "google" | "azure"} Cloud
|
||||
*/
|
||||
|
||||
/** @type {Cloud | undefined} */
|
||||
@@ -2136,6 +2136,37 @@ export async function isGoogleCloud() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<boolean | undefined>}
|
||||
*/
|
||||
export async function isAzure() {
|
||||
if (typeof detectedCloud === "string") {
|
||||
return detectedCloud === "azure";
|
||||
}
|
||||
|
||||
async function detectAzure() {
|
||||
// Azure IMDS (Instance Metadata Service) — the official way to detect Azure VMs.
|
||||
// https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service
|
||||
const { error, body } = await curl("http://169.254.169.254/metadata/instance?api-version=2021-02-01", {
|
||||
headers: { "Metadata": "true" },
|
||||
retries: 1,
|
||||
});
|
||||
if (!error && body) {
|
||||
try {
|
||||
const metadata = JSON.parse(body);
|
||||
if (metadata?.compute?.azEnvironment) {
|
||||
return true;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
if (await detectAzure()) {
|
||||
detectedCloud = "azure";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<Cloud | undefined>}
|
||||
*/
|
||||
@@ -2151,6 +2182,10 @@ export async function getCloud() {
|
||||
if (await isGoogleCloud()) {
|
||||
return "google";
|
||||
}
|
||||
|
||||
if (await isAzure()) {
|
||||
return "azure";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2175,6 +2210,10 @@ export async function getCloudMetadata(name, cloud) {
|
||||
} else if (cloud === "google") {
|
||||
url = new URL(name, "http://metadata.google.internal/computeMetadata/v1/instance/");
|
||||
headers = { "Metadata-Flavor": "Google" };
|
||||
} else if (cloud === "azure") {
|
||||
// Azure IMDS uses a single JSON endpoint; individual fields are extracted by the caller.
|
||||
url = new URL("http://169.254.169.254/metadata/instance?api-version=2021-02-01");
|
||||
headers = { "Metadata": "true" };
|
||||
} else {
|
||||
throw new Error(`Unsupported cloud: ${inspect(cloud)}`);
|
||||
}
|
||||
@@ -2193,7 +2232,25 @@ export async function getCloudMetadata(name, cloud) {
|
||||
* @param {Cloud} [cloud]
|
||||
* @returns {Promise<string | undefined>}
|
||||
*/
|
||||
export function getCloudMetadataTag(tag, cloud) {
|
||||
export async function getCloudMetadataTag(tag, cloud) {
|
||||
cloud ??= await getCloud();
|
||||
|
||||
if (cloud === "azure") {
|
||||
// Azure IMDS returns all tags in a single JSON response.
|
||||
// Tags are in compute.tagsList as [{name, value}, ...].
|
||||
const body = await getCloudMetadata("", cloud);
|
||||
if (!body) return;
|
||||
try {
|
||||
const metadata = JSON.parse(body);
|
||||
const tags = metadata?.compute?.tagsList;
|
||||
if (Array.isArray(tags)) {
|
||||
const entry = tags.find(t => t.name === tag);
|
||||
return entry?.value;
|
||||
}
|
||||
} catch {}
|
||||
return;
|
||||
}
|
||||
|
||||
const metadata = {
|
||||
"aws": `tags/instance/${tag}`,
|
||||
"google": `labels/${tag.replace(":", "-")}`,
|
||||
|
||||
@@ -5,22 +5,7 @@ $ErrorActionPreference = "Stop"
|
||||
|
||||
# Detect system architecture
|
||||
$script:IsARM64 = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64
|
||||
|
||||
# Allow overriding the target arch (useful for cross-compiling on x64 -> ARM64)
|
||||
$script:VsArch = $null
|
||||
if ($env:BUN_VS_ARCH) {
|
||||
switch ($env:BUN_VS_ARCH.ToLowerInvariant()) {
|
||||
"arm64" { $script:VsArch = "arm64" }
|
||||
"aarch64" { $script:VsArch = "arm64" }
|
||||
"amd64" { $script:VsArch = "amd64" }
|
||||
"x64" { $script:VsArch = "amd64" }
|
||||
default { throw "Invalid BUN_VS_ARCH: $env:BUN_VS_ARCH (expected arm64|amd64)" }
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $script:VsArch) {
|
||||
$script:VsArch = if ($script:IsARM64) { "arm64" } else { "amd64" }
|
||||
}
|
||||
$script:VsArch = if ($script:IsARM64) { "arm64" } else { "amd64" }
|
||||
|
||||
if($env:VSINSTALLDIR -eq $null) {
|
||||
Write-Host "Loading Visual Studio environment, this may take a second..."
|
||||
@@ -51,10 +36,15 @@ if($env:VSINSTALLDIR -eq $null) {
|
||||
Push-Location $vsDir
|
||||
try {
|
||||
$vsShell = (Join-Path -Path $vsDir -ChildPath "Common7\Tools\Launch-VsDevShell.ps1")
|
||||
# Visual Studio's Launch-VsDevShell.ps1 only supports x86/amd64 for HostArch
|
||||
# For ARM64 builds, use amd64 as HostArch since it can cross-compile to ARM64
|
||||
# -HostArch only accepts "x86" or "amd64" — even on native ARM64, use "amd64"
|
||||
$hostArch = if ($script:VsArch -eq "arm64") { "amd64" } else { $script:VsArch }
|
||||
. $vsShell -Arch $script:VsArch -HostArch $hostArch
|
||||
|
||||
# VS dev shell with -HostArch amd64 sets PROCESSOR_ARCHITECTURE=AMD64,
|
||||
# which causes CMake to misdetect the system as x64. Restore it on ARM64.
|
||||
if ($script:IsARM64) {
|
||||
$env:PROCESSOR_ARCHITECTURE = "ARM64"
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
@@ -14,10 +14,11 @@ param(
|
||||
[Switch]$DownloadWithoutCurl = $false
|
||||
);
|
||||
|
||||
# filter out 32 bit + ARM
|
||||
if (-not ((Get-CimInstance Win32_ComputerSystem)).SystemType -match "x64-based") {
|
||||
# filter out 32-bit and unsupported architectures
|
||||
$SystemType = ((Get-CimInstance Win32_ComputerSystem)).SystemType
|
||||
if (-not ($SystemType -match "x64-based" -or $SystemType -match "ARM64-based")) {
|
||||
Write-Output "Install Failed:"
|
||||
Write-Output "Bun for Windows is currently only available for x86 64-bit Windows.`n"
|
||||
Write-Output "Bun for Windows is only available for x86 64-bit and ARM64 Windows.`n"
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -103,13 +104,17 @@ function Install-Bun {
|
||||
$Version = "bun-$Version"
|
||||
}
|
||||
|
||||
$Arch = "x64"
|
||||
$IsBaseline = $ForceBaseline
|
||||
if (!$IsBaseline) {
|
||||
$IsBaseline = !( `
|
||||
Add-Type -MemberDefinition '[DllImport("kernel32.dll")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);' `
|
||||
-Name 'Kernel32' -Namespace 'Win32' -PassThru `
|
||||
)::IsProcessorFeaturePresent(40);
|
||||
$IsARM64 = $SystemType -match "ARM64-based"
|
||||
$Arch = if ($IsARM64) { "aarch64" } else { "x64" }
|
||||
$IsBaseline = $false
|
||||
if (-not $IsARM64) {
|
||||
$IsBaseline = $ForceBaseline
|
||||
if (!$IsBaseline) {
|
||||
$IsBaseline = !( `
|
||||
Add-Type -MemberDefinition '[DllImport("kernel32.dll")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);' `
|
||||
-Name 'Kernel32' -Namespace 'Win32' -PassThru `
|
||||
)::IsProcessorFeaturePresent(40);
|
||||
}
|
||||
}
|
||||
|
||||
$BunRoot = if ($env:BUN_INSTALL) { $env:BUN_INSTALL } else { "${Home}\.bun" }
|
||||
@@ -219,7 +224,8 @@ function Install-Bun {
|
||||
# I want to keep this error message in for a few months to ensure that
|
||||
# if someone somehow runs into this, it can be reported.
|
||||
Write-Output "Install Failed - You are missing a DLL required to run bun.exe"
|
||||
Write-Output "This can be solved by installing the Visual C++ Redistributable from Microsoft:`nSee https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist`nDirect Download -> https://aka.ms/vs/17/release/vc_redist.x64.exe`n`n"
|
||||
$VCRedistUrl = if ($IsARM64) { "https://aka.ms/vs/17/release/vc_redist.arm64.exe" } else { "https://aka.ms/vs/17/release/vc_redist.x64.exe" }
|
||||
Write-Output "This can be solved by installing the Visual C++ Redistributable from Microsoft:`nSee https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist`nDirect Download -> ${VCRedistUrl}`n`n"
|
||||
Write-Output "The error above should be unreachable as Bun does not depend on this library. Please comment in https://github.com/oven-sh/bun/issues/8598 or open a new issue.`n`n"
|
||||
Write-Output "The command '${BunBin}\bun.exe --revision' exited with code ${LASTEXITCODE}`n"
|
||||
return 1
|
||||
|
||||
@@ -70,6 +70,9 @@ case $platform in
|
||||
'Linux aarch64' | 'Linux arm64')
|
||||
target=linux-aarch64
|
||||
;;
|
||||
'MINGW64'*'ARM64'* | 'MINGW64'*'aarch64'*)
|
||||
target=windows-aarch64
|
||||
;;
|
||||
'MINGW64'*)
|
||||
target=windows-x64
|
||||
;;
|
||||
|
||||
@@ -348,7 +348,7 @@ pub const LifecycleScriptSubprocess = struct {
|
||||
if (this.optional) {
|
||||
if (this.ctx) |ctx| {
|
||||
ctx.installer.store.entries.items(.step)[ctx.entry_id.get()].store(.done, .release);
|
||||
ctx.installer.onTaskComplete(ctx.entry_id, .fail);
|
||||
ctx.installer.onTaskComplete(ctx.entry_id, .skipped);
|
||||
}
|
||||
this.decrementPendingScriptTasks();
|
||||
this.deinitAndDeletePackage();
|
||||
@@ -454,7 +454,7 @@ pub const LifecycleScriptSubprocess = struct {
|
||||
if (this.optional) {
|
||||
if (this.ctx) |ctx| {
|
||||
ctx.installer.store.entries.items(.step)[ctx.entry_id.get()].store(.done, .release);
|
||||
ctx.installer.onTaskComplete(ctx.entry_id, .fail);
|
||||
ctx.installer.onTaskComplete(ctx.entry_id, .skipped);
|
||||
}
|
||||
this.decrementPendingScriptTasks();
|
||||
this.deinitAndDeletePackage();
|
||||
|
||||
102
test/bun.lock
102
test/bun.lock
@@ -10,13 +10,12 @@
|
||||
"@bufbuild/protobuf": "2.10.2",
|
||||
"@connectrpc/connect": "2.1.1",
|
||||
"@connectrpc/connect-node": "2.0.0",
|
||||
"@duckdb/node-api": "1.1.3-alpha.7",
|
||||
"@electric-sql/pglite": "0.2.17",
|
||||
"@fastify/websocket": "11.0.2",
|
||||
"@grpc/grpc-js": "1.12.0",
|
||||
"@grpc/proto-loader": "0.7.10",
|
||||
"@happy-dom/global-registrator": "17.0.3",
|
||||
"@napi-rs/canvas": "0.1.65",
|
||||
"@napi-rs/canvas": "0.1.91",
|
||||
"@nestjs/common": "11.0.3",
|
||||
"@nestjs/core": "11.0.3",
|
||||
"@prisma/client": "5.8.0",
|
||||
@@ -40,7 +39,6 @@
|
||||
"commander": "12.1.0",
|
||||
"detect-libc": "2.0.3",
|
||||
"devalue": "5.1.1",
|
||||
"duckdb": "1.3.1",
|
||||
"es-module-lexer": "1.3.0",
|
||||
"esbuild": "0.18.6",
|
||||
"express": "4.18.2",
|
||||
@@ -61,7 +59,6 @@
|
||||
"jws": "4.0.0",
|
||||
"lodash": "4.17.21",
|
||||
"mongodb": "6.0.0",
|
||||
"msgpackr-extract": "3.0.2",
|
||||
"msw": "2.3.0",
|
||||
"mysql2": "3.7.0",
|
||||
"node-gyp": "10.0.1",
|
||||
@@ -82,7 +79,7 @@
|
||||
"reflect-metadata": "0.2.2",
|
||||
"rollup": "4.4.1",
|
||||
"sass": "1.79.4",
|
||||
"sharp": "0.33.0",
|
||||
"sharp": "0.34.5",
|
||||
"sinon": "6.0.0",
|
||||
"socket.io": "4.7.1",
|
||||
"socket.io-adapter": "2.5.5",
|
||||
@@ -120,6 +117,11 @@
|
||||
"@types/utf-8-validate": "5.0.0",
|
||||
"@types/ws": "8.5.10",
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@duckdb/node-api": "1.1.3-alpha.7",
|
||||
"duckdb": "1.3.1",
|
||||
"msgpackr-extract": "3.0.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"overrides": {
|
||||
@@ -227,7 +229,7 @@
|
||||
|
||||
"@electric-sql/pglite": ["@electric-sql/pglite@0.2.17", "", {}, "sha512-qEpKRT2oUaWDH6tjRxLHjdzMqRUGYDnGZlKrnL4dJ77JVMcP2Hpo3NYnOSPKdZdeec57B6QPprCUFg0picx5Pw=="],
|
||||
|
||||
"@emnapi/runtime": ["@emnapi/runtime@0.44.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ZX/etZEZw8DR7zAB1eVQT40lNo0jeqpb6dCgOvctB6FIQ5PoXfMuNY8+ayQfu8tNQbAB8gQWSSJupR8NxeiZXw=="],
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ=="],
|
||||
|
||||
@@ -305,43 +307,55 @@
|
||||
|
||||
"@happy-dom/global-registrator": ["@happy-dom/global-registrator@17.0.3", "", { "dependencies": { "happy-dom": "^17.0.3" } }, "sha512-isCCWywZq8XPE3A5y7pRyFIsAgij+3eVXgQNCbexGRP00/+nctmf4SfQxC3vV3MmEaOXaNj7IiiSC0BtSHQZgg=="],
|
||||
|
||||
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.0", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-070tEheekI1LJWTGPC9WlQEa5UoKTXzzlORBHMX4TbfUxMiL336YHR8vBEUNsjse0RJCX8dZ4ZXwT595aEF1ug=="],
|
||||
"@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="],
|
||||
|
||||
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.0", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.0" }, "os": "darwin", "cpu": "x64" }, "sha512-pu/nvn152F3qbPeUkr+4e9zVvEhD3jhwzF473veQfMPkOYo9aoWXSfdZH/E6F+nYC3qvFjbxbvdDbUtEbghLqw=="],
|
||||
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="],
|
||||
|
||||
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.0.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VzYd6OwnUR81sInf3alj1wiokY50DjsHz5bvfnsFpxs5tqQxESoHtJO6xyksDs3RIkyhMWq2FufXo6GNSU9BMw=="],
|
||||
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="],
|
||||
|
||||
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.0.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-dD9OznTlHD6aovRswaPNEy8dKtSAmNo4++tO7uuR4o5VxbVAOoEQ1uSmN4iFAdQneTHws1lkTZeiXPrcCkh6IA=="],
|
||||
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="],
|
||||
|
||||
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.0.0", "", { "os": "linux", "cpu": "arm" }, "sha512-VwgD2eEikDJUk09Mn9Dzi1OW2OJFRQK+XlBTkUNmAWPrtj8Ly0yq05DFgu1VCMx2/DqCGQVi5A1dM9hTmxf3uw=="],
|
||||
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="],
|
||||
|
||||
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-xTYThiqEZEZc0PRU90yVtM3KE7lw1bKdnDQ9kCTHWbqWyHOe4NpPOtMGy27YnN51q0J5dqRrvicfPbALIOeAZA=="],
|
||||
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="],
|
||||
|
||||
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.0.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-o9E46WWBC6JsBlwU4QyU9578G77HBDT1NInd+aERfxeOPbk0qBZHgoDsQmA2v9TbqJRWzoBPx1aLOhprBMgPjw=="],
|
||||
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="],
|
||||
|
||||
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-naldaJy4hSVhWBgEjfdBY85CAa4UO+W1nx6a1sWStHZ7EUfNiuBTTN2KUYT5dH1+p/xij1t2QSXfCiFJoC5S/Q=="],
|
||||
"@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="],
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-OdorplCyvmSAPsoJLldtLh3nLxRrkAAAOHsGWGDYfN0kh730gifK+UZb3dWORRa6EusNqCTjfXV4GxvgJ/nPDQ=="],
|
||||
"@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="],
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-FW8iK6rJrg+X2jKD0Ajhjv6y74lToIBEvkZhl42nZt563FfxkCYacrXZtd+q/sRQDypQLzY5WdLkVTbJoPyqNg=="],
|
||||
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="],
|
||||
|
||||
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.33.0", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.0" }, "os": "linux", "cpu": "arm" }, "sha512-4horD3wMFd5a0ddbDY8/dXU9CaOgHjEHALAddXgafoR5oWq5s8X61PDgsSeh4Qupsdo6ycfPPSSNBrfVQnwwrg=="],
|
||||
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="],
|
||||
|
||||
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.33.0", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.0" }, "os": "linux", "cpu": "arm64" }, "sha512-dcomVSrtgF70SyOr8RCOCQ8XGVThXwe71A1d8MGA+mXEVRJ/J6/TrCbBEJh9ddcEIIsrnrkolaEvYSHqVhswQw=="],
|
||||
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="],
|
||||
|
||||
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.33.0", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.0" }, "os": "linux", "cpu": "s390x" }, "sha512-TiVJbx38J2rNVfA309ffSOB+3/7wOsZYQEOlKqOUdWD/nqkjNGrX+YQGz7nzcf5oy2lC+d37+w183iNXRZNngQ=="],
|
||||
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="],
|
||||
|
||||
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.33.0", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.0" }, "os": "linux", "cpu": "x64" }, "sha512-PaZM4Zi7/Ek71WgTdvR+KzTZpBqrQOFcPe7/8ZoPRlTYYRe43k6TWsf4GVH6XKRLMYeSp8J89RfAhBrSP4itNA=="],
|
||||
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="],
|
||||
|
||||
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.33.0", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.0" }, "os": "linux", "cpu": "arm64" }, "sha512-1QLbbN0zt+32eVrg7bb1lwtvEaZwlhEsY1OrijroMkwAqlHqFj6R33Y47s2XUv7P6Ie1PwCxK/uFnNqMnkd5kg=="],
|
||||
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="],
|
||||
|
||||
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.33.0", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.0" }, "os": "linux", "cpu": "x64" }, "sha512-CecqgB/CnkvCWFhmfN9ZhPGMLXaEBXl4o7WtA6U3Ztrlh/s7FUKX4vNxpMSYLIrWuuzjiaYdfU3+Tdqh1xaHfw=="],
|
||||
"@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="],
|
||||
|
||||
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.33.0", "", { "dependencies": { "@emnapi/runtime": "^0.44.0" }, "cpu": "none" }, "sha512-Hn4js32gUX9qkISlemZBUPuMs0k/xNJebUNl/L6djnU07B/HAA2KaxRVb3HvbU5fL242hLOcp0+tR+M8dvJUFw=="],
|
||||
"@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="],
|
||||
|
||||
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.33.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-5HfcsCZi3l5nPRF2q3bllMVMDXBqEWI3Q8KQONfzl0TferFE5lnsIG0A1YrntMAGqvkzdW6y1Ci1A2uTvxhfzg=="],
|
||||
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="],
|
||||
|
||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.0", "", { "os": "win32", "cpu": "x64" }, "sha512-i3DtP/2ce1yKFj4OzOnOYltOEL/+dp4dc4dJXJBv6god1AFTcmkaA99H/7SwOmkCOBQkbVvA3lCGm3/5nDtf9Q=="],
|
||||
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="],
|
||||
|
||||
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="],
|
||||
|
||||
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="],
|
||||
|
||||
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="],
|
||||
|
||||
"@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="],
|
||||
|
||||
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="],
|
||||
|
||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
|
||||
|
||||
"@inquirer/confirm": ["@inquirer/confirm@3.1.9", "", { "dependencies": { "@inquirer/core": "^8.2.2", "@inquirer/type": "^1.3.3" } }, "sha512-UF09aejxCi4Xqm6N/jJAiFXArXfi9al52AFaSD+2uIHnhZGtd1d6lIGTRMPouVSJxbGEi+HkOWSYaiEY/+szUw=="],
|
||||
|
||||
@@ -449,27 +463,29 @@
|
||||
|
||||
"@mswjs/interceptors": ["@mswjs/interceptors@0.29.1", "", { "dependencies": { "@open-draft/deferred-promise": "^2.2.0", "@open-draft/logger": "^0.3.0", "@open-draft/until": "^2.0.0", "is-node-process": "^1.2.0", "outvariant": "^1.2.1", "strict-event-emitter": "^0.5.1" } }, "sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw=="],
|
||||
|
||||
"@napi-rs/canvas": ["@napi-rs/canvas@0.1.65", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.65", "@napi-rs/canvas-darwin-arm64": "0.1.65", "@napi-rs/canvas-darwin-x64": "0.1.65", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.65", "@napi-rs/canvas-linux-arm64-gnu": "0.1.65", "@napi-rs/canvas-linux-arm64-musl": "0.1.65", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.65", "@napi-rs/canvas-linux-x64-gnu": "0.1.65", "@napi-rs/canvas-linux-x64-musl": "0.1.65", "@napi-rs/canvas-win32-x64-msvc": "0.1.65" } }, "sha512-YcFhXQcp+b2d38zFOJNbpyPHnIL7KAEkhJQ+UeeKI5IpE9B8Cpf/M6RiHPQXSsSqnYbrfFylnW49dyh2oeSblQ=="],
|
||||
"@napi-rs/canvas": ["@napi-rs/canvas@0.1.91", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.91", "@napi-rs/canvas-darwin-arm64": "0.1.91", "@napi-rs/canvas-darwin-x64": "0.1.91", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.91", "@napi-rs/canvas-linux-arm64-gnu": "0.1.91", "@napi-rs/canvas-linux-arm64-musl": "0.1.91", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.91", "@napi-rs/canvas-linux-x64-gnu": "0.1.91", "@napi-rs/canvas-linux-x64-musl": "0.1.91", "@napi-rs/canvas-win32-arm64-msvc": "0.1.91", "@napi-rs/canvas-win32-x64-msvc": "0.1.91" } }, "sha512-eeIe1GoB74P1B0Nkw6pV8BCQ3hfCfvyYr4BntzlCsnFXzVJiPMDnLeIx3gVB0xQMblHYnjK/0nCLvirEhOjr5g=="],
|
||||
|
||||
"@napi-rs/canvas-android-arm64": ["@napi-rs/canvas-android-arm64@0.1.65", "", { "os": "android", "cpu": "arm64" }, "sha512-ZYwqFYEKcT5Zr8lbiaJNJj/poLaeK2TncolY914r+gD2TJNeP7ZqvE7A2SX/1C9MB4E3DQEwm3YhL3WEf0x3MQ=="],
|
||||
"@napi-rs/canvas-android-arm64": ["@napi-rs/canvas-android-arm64@0.1.91", "", { "os": "android", "cpu": "arm64" }, "sha512-SLLzXXgSnfct4zy/BVAfweZQkYkPJsNsJ2e5DOE8DFEHC6PufyUrwb12yqeu2So2IOIDpWJJaDAxKY/xpy6MYQ=="],
|
||||
|
||||
"@napi-rs/canvas-darwin-arm64": ["@napi-rs/canvas-darwin-arm64@0.1.65", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Pg1pfiJEyDIsX+V0QaJPRWvXbw5zmWAk3bivFCvt/5pwZb37/sT6E/RqPHT9NnqpDyKW6SriwY9ypjljysUA1Q=="],
|
||||
"@napi-rs/canvas-darwin-arm64": ["@napi-rs/canvas-darwin-arm64@0.1.91", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bzdbCjIjw3iRuVFL+uxdSoMra/l09ydGNX9gsBxO/zg+5nlppscIpj6gg+nL6VNG85zwUarDleIrUJ+FWHvmuA=="],
|
||||
|
||||
"@napi-rs/canvas-darwin-x64": ["@napi-rs/canvas-darwin-x64@0.1.65", "", { "os": "darwin", "cpu": "x64" }, "sha512-3Tr+/HjdJN7Z/VKIcsxV2DvDIibZCExgfYTgljCkUSFuoI7iNkOE6Dc1Q6j212EB9PeO8KmfrViBqHYT6IwWkA=="],
|
||||
"@napi-rs/canvas-darwin-x64": ["@napi-rs/canvas-darwin-x64@0.1.91", "", { "os": "darwin", "cpu": "x64" }, "sha512-q3qpkpw0IsG9fAS/dmcGIhCVoNxj8ojbexZKWwz3HwxlEWsLncEQRl4arnxrwbpLc2nTNTyj4WwDn7QR5NDAaA=="],
|
||||
|
||||
"@napi-rs/canvas-linux-arm-gnueabihf": ["@napi-rs/canvas-linux-arm-gnueabihf@0.1.65", "", { "os": "linux", "cpu": "arm" }, "sha512-3KP+dYObH7CVkZMZWwk1WX9jRjL+EKdQtD43H8MOI+illf+dwqLlecdQ4d9bQRIxELKJ8dyPWY4fOp/Ngufrdg=="],
|
||||
"@napi-rs/canvas-linux-arm-gnueabihf": ["@napi-rs/canvas-linux-arm-gnueabihf@0.1.91", "", { "os": "linux", "cpu": "arm" }, "sha512-Io3g8wJZVhK8G+Fpg1363BE90pIPqg+ZbeehYNxPWDSzbgwU3xV0l8r/JBzODwC7XHi1RpFEk+xyUTMa2POj6w=="],
|
||||
|
||||
"@napi-rs/canvas-linux-arm64-gnu": ["@napi-rs/canvas-linux-arm64-gnu@0.1.65", "", { "os": "linux", "cpu": "arm64" }, "sha512-Ka3StKz7Dq7kjTF3nNJCq43UN/VlANS7qGE3dWkn1d+tQNsCRy/wRmyt1TUFzIjRqcTFMQNRbgYq84+53UBA0A=="],
|
||||
"@napi-rs/canvas-linux-arm64-gnu": ["@napi-rs/canvas-linux-arm64-gnu@0.1.91", "", { "os": "linux", "cpu": "arm64" }, "sha512-HBnto+0rxx1bQSl8bCWA9PyBKtlk2z/AI32r3cu4kcNO+M/5SD4b0v1MWBWZyqMQyxFjWgy3ECyDjDKMC6tY1A=="],
|
||||
|
||||
"@napi-rs/canvas-linux-arm64-musl": ["@napi-rs/canvas-linux-arm64-musl@0.1.65", "", { "os": "linux", "cpu": "arm64" }, "sha512-O4xMASm2JrmqYoiDyxVWi+z5C14H+oVEag2rZ5iIA67dhWqYZB+iO7wCFpBYRj31JPBR29FOsu6X9zL+DwBFdw=="],
|
||||
"@napi-rs/canvas-linux-arm64-musl": ["@napi-rs/canvas-linux-arm64-musl@0.1.91", "", { "os": "linux", "cpu": "arm64" }, "sha512-/eJtVe2Xw9A86I4kwXpxxoNagdGclu12/NSMsfoL8q05QmeRCbfjhg1PJS7ENAuAvaiUiALGrbVfeY1KU1gztQ=="],
|
||||
|
||||
"@napi-rs/canvas-linux-riscv64-gnu": ["@napi-rs/canvas-linux-riscv64-gnu@0.1.65", "", { "os": "linux", "cpu": "none" }, "sha512-dblWDaA59ZU8bPbkfM+riSke7sFbNZ70LEevUdI5rgiFEUzYUQlU34gSBzemTACj5rCWt1BYeu0GfkLSjNMBSw=="],
|
||||
"@napi-rs/canvas-linux-riscv64-gnu": ["@napi-rs/canvas-linux-riscv64-gnu@0.1.91", "", { "os": "linux", "cpu": "none" }, "sha512-floNK9wQuRWevUhhXRcuis7h0zirdytVxPgkonWO+kQlbvxV7gEUHGUFQyq4n55UHYFwgck1SAfJ1HuXv/+ppQ=="],
|
||||
|
||||
"@napi-rs/canvas-linux-x64-gnu": ["@napi-rs/canvas-linux-x64-gnu@0.1.65", "", { "os": "linux", "cpu": "x64" }, "sha512-wsp+atutw13OJXGU3DDkdngtBDoEg01IuK5xMe0L6VFPV8maGkh17CXze078OD5QJOc6kFyw3DDscMLOPF8+oA=="],
|
||||
"@napi-rs/canvas-linux-x64-gnu": ["@napi-rs/canvas-linux-x64-gnu@0.1.91", "", { "os": "linux", "cpu": "x64" }, "sha512-c3YDqBdf7KETuZy2AxsHFMsBBX1dWT43yFfWUq+j1IELdgesWtxf/6N7csi3VPf6VA3PmnT9EhMyb+M1wfGtqw=="],
|
||||
|
||||
"@napi-rs/canvas-linux-x64-musl": ["@napi-rs/canvas-linux-x64-musl@0.1.65", "", { "os": "linux", "cpu": "x64" }, "sha512-odX+nN+IozWzhdj31INcHz3Iy9+EckNw+VqsZcaUxZOTu7/3FmktRNI6aC1qe5minZNv1m05YOS1FVf7fvmjlA=="],
|
||||
"@napi-rs/canvas-linux-x64-musl": ["@napi-rs/canvas-linux-x64-musl@0.1.91", "", { "os": "linux", "cpu": "x64" }, "sha512-RpZ3RPIwgEcNBHSHSX98adm+4VP8SMT5FN6250s5jQbWpX/XNUX5aLMfAVJS/YnDjS1QlsCgQxFOPU0aCCWgag=="],
|
||||
|
||||
"@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.65", "", { "os": "win32", "cpu": "x64" }, "sha512-RZQX3luWnlNWgdMnLMQ1hyfQraeAn9lnxWWVCHuUM4tAWEV8UDdeb7cMwmJW7eyt8kAosmjeHt3cylQMHOxGFg=="],
|
||||
"@napi-rs/canvas-win32-arm64-msvc": ["@napi-rs/canvas-win32-arm64-msvc@0.1.91", "", { "os": "win32", "cpu": "arm64" }, "sha512-gF8MBp4X134AgVurxqlCdDA2qO0WaDdi9o6Sd5rWRVXRhWhYQ6wkdEzXNLIrmmros0Tsp2J0hQzx4ej/9O8trQ=="],
|
||||
|
||||
"@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.91", "", { "os": "win32", "cpu": "x64" }, "sha512-++gtW9EV/neKI8TshD8WFxzBYALSPag2kFRahIJV+LYsyt5kBn21b1dBhEUDHf7O+wiZmuFCeUa7QKGHnYRZBA=="],
|
||||
|
||||
"@nestjs/common": ["@nestjs/common@11.0.3", "", { "dependencies": { "iterare": "1.2.1", "tslib": "2.8.1", "uid": "2.0.2" }, "peerDependencies": { "class-transformer": "*", "class-validator": "*", "reflect-metadata": "^0.1.12 || ^0.2.0", "rxjs": "^7.1.0" }, "optionalPeers": ["class-transformer", "class-validator"] }, "sha512-fTkJWQ20+jvPKfrv3A+T3wsPwwYSJyoJ+pcBzyKtv5fCpK/yX/rJalFUIpw1CDmarfqIaMX9SdkplNyxtvH6RA=="],
|
||||
|
||||
@@ -1575,7 +1591,7 @@
|
||||
|
||||
"is-arguments": ["is-arguments@1.1.1", "", { "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" } }, "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA=="],
|
||||
|
||||
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
||||
"is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
|
||||
|
||||
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
||||
|
||||
@@ -2339,7 +2355,7 @@
|
||||
|
||||
"shallow-clone": ["shallow-clone@3.0.1", "", { "dependencies": { "kind-of": "^6.0.2" } }, "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA=="],
|
||||
|
||||
"sharp": ["sharp@0.33.0", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.2", "semver": "^7.5.4" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.0", "@img/sharp-darwin-x64": "0.33.0", "@img/sharp-libvips-darwin-arm64": "1.0.0", "@img/sharp-libvips-darwin-x64": "1.0.0", "@img/sharp-libvips-linux-arm": "1.0.0", "@img/sharp-libvips-linux-arm64": "1.0.0", "@img/sharp-libvips-linux-s390x": "1.0.0", "@img/sharp-libvips-linux-x64": "1.0.0", "@img/sharp-libvips-linuxmusl-arm64": "1.0.0", "@img/sharp-libvips-linuxmusl-x64": "1.0.0", "@img/sharp-linux-arm": "0.33.0", "@img/sharp-linux-arm64": "0.33.0", "@img/sharp-linux-s390x": "0.33.0", "@img/sharp-linux-x64": "0.33.0", "@img/sharp-linuxmusl-arm64": "0.33.0", "@img/sharp-linuxmusl-x64": "0.33.0", "@img/sharp-wasm32": "0.33.0", "@img/sharp-win32-ia32": "0.33.0", "@img/sharp-win32-x64": "0.33.0" } }, "sha512-99DZKudjm/Rmz+M0/26t4DKpXyywAOJaayGS9boEn7FvgtG0RYBi46uPE2c+obcJRtA3AZa0QwJot63gJQ1F0Q=="],
|
||||
"sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
@@ -2781,6 +2797,8 @@
|
||||
|
||||
"@cypress/request/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
|
||||
|
||||
"@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@fastify/ajv-compiler/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
||||
|
||||
"@fastify/proxy-addr/ipaddr.js": ["ipaddr.js@2.2.0", "", {}, "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA=="],
|
||||
@@ -3079,8 +3097,6 @@
|
||||
|
||||
"engine.io-client/ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="],
|
||||
|
||||
"error-ex/is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
|
||||
|
||||
"escodegen/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
|
||||
|
||||
"escodegen/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
@@ -3299,7 +3315,11 @@
|
||||
|
||||
"serve-static/send": ["send@0.18.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg=="],
|
||||
|
||||
"sharp/semver": ["semver@7.6.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w=="],
|
||||
"sharp/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||
|
||||
"sharp/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||
|
||||
"simple-swizzle/is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
||||
|
||||
"sinon/diff": ["diff@3.5.0", "", {}, "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="],
|
||||
|
||||
|
||||
@@ -203,13 +203,14 @@ console.log(utils());`,
|
||||
});
|
||||
expect(await exited).toBe(0);
|
||||
|
||||
const { stdout } = Bun.spawn({
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [path.join(baseDir, "exe.exe")],
|
||||
env: bunEnv,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
const text = await stdout.text();
|
||||
const text = await proc.stdout.text();
|
||||
await proc.exited;
|
||||
|
||||
expect(text).toContain(path.join(baseDir, "我") + "\n");
|
||||
expect(text).toContain(path.join(baseDir, "我", "我.ts") + "\n");
|
||||
|
||||
@@ -178,7 +178,7 @@ describe.skipIf(!isWindows).concurrent("Windows compile metadata", () => {
|
||||
entrypoints: [join(String(dir), "app.js")],
|
||||
outdir: String(dir),
|
||||
compile: {
|
||||
target: "bun-windows-x64",
|
||||
target: process.arch === "arm64" ? "bun-windows-aarch64" : "bun-windows-x64",
|
||||
outfile: "app-api.exe",
|
||||
windows: {
|
||||
title: "API App",
|
||||
@@ -225,7 +225,7 @@ describe.skipIf(!isWindows).concurrent("Windows compile metadata", () => {
|
||||
entrypoints: [join(String(dir), "app.js")],
|
||||
outdir: String(dir),
|
||||
compile: {
|
||||
target: "bun-windows-x64",
|
||||
target: process.arch === "arm64" ? "bun-windows-aarch64" : "bun-windows-x64",
|
||||
outfile: "partial-api.exe",
|
||||
windows: {
|
||||
title: "Partial App",
|
||||
@@ -262,7 +262,7 @@ describe.skipIf(!isWindows).concurrent("Windows compile metadata", () => {
|
||||
entrypoints: [join(String(dir), "app.js")],
|
||||
outdir: "./out",
|
||||
compile: {
|
||||
target: "bun-windows-x64",
|
||||
target: process.arch === "arm64" ? "bun-windows-aarch64" : "bun-windows-x64",
|
||||
outfile: "relative.exe",
|
||||
windows: {
|
||||
title: "Relative Path App",
|
||||
|
||||
@@ -5081,7 +5081,7 @@ describe.concurrent("bun-install", () => {
|
||||
stdout: "pipe",
|
||||
stdin: "ignore",
|
||||
stderr: "pipe",
|
||||
env: { ...env, "GIT_ASKPASS": "echo" },
|
||||
env: { ...env, "GIT_ASKPASS": "echo", "GIT_SSH_COMMAND": "ssh -o ConnectTimeout=5 -o BatchMode=yes" },
|
||||
});
|
||||
const err = await stderr.text();
|
||||
expect(err.split(/\r?\n/)).toContain('error: "git clone" for "private-install" failed');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe, isBroken, isCI, isIntelMacOS, isMacOS, isWindows, tempDirWithFiles } from "harness";
|
||||
import { bunEnv, bunExe, isArm64, isBroken, isCI, isIntelMacOS, isMacOS, isWindows, tempDirWithFiles } from "harness";
|
||||
import { join } from "path";
|
||||
|
||||
describe.concurrent("require.cache", () => {
|
||||
@@ -24,7 +24,8 @@ describe.concurrent("require.cache", () => {
|
||||
});
|
||||
|
||||
// https://github.com/oven-sh/bun/issues/5188
|
||||
test("require.cache does not include unevaluated modules", async () => {
|
||||
// msgpackr-extract has no prebuilt binary for win32-arm64, so it's unavailable there
|
||||
test.skipIf(isWindows && isArm64)("require.cache does not include unevaluated modules", async () => {
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [bunExe(), "run", join(import.meta.dir, "require-cache-bug-5188.js")],
|
||||
env: bunEnv,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
# Tests that are broken
|
||||
test/cli/create/create-jsx.test.ts [ FAIL ] # false > react spa (no tailwind) > build
|
||||
[ WINDOWS-AARCH64 ] test/js/node/test/parallel/test-repl-close.js [ FAIL ] # EPIPE on stdin.write to closed child process
|
||||
test/bundler/native-plugin.test.ts [ FAIL ] # prints name when plugin crashes
|
||||
test/cli/run/run-crash-handler.test.ts [ FAIL ] # automatic crash reporter > segfault should report
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { spawn } from "bun";
|
||||
import { beforeAll, describe, expect, setDefaultTimeout, test } from "bun:test";
|
||||
import { cp, rm, writeFile } from "fs/promises";
|
||||
import { bunExe, bunEnv as env, tempDir } from "harness";
|
||||
import { bunExe, bunEnv as env, isArm64, isWindows, tempDir } from "harness";
|
||||
import { join } from "path";
|
||||
|
||||
// esbuild@0.19.8 does not support win32-arm64 at runtime
|
||||
const isWindowsArm64 = isWindows && isArm64;
|
||||
|
||||
beforeAll(() => {
|
||||
setDefaultTimeout(1000 * 60 * 5);
|
||||
});
|
||||
@@ -49,7 +52,7 @@ describe.concurrent("esbuild integration test", () => {
|
||||
expect(await exited).toBe(0);
|
||||
});
|
||||
|
||||
test("install and use estrella", async () => {
|
||||
test.skipIf(isWindowsArm64)("install and use estrella", async () => {
|
||||
using dir = tempDir("esbuild-estrella-test", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "bun-esbuild-estrella-test",
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { cc, CString, ptr, type FFIFunction, type Library } from "bun:ffi";
|
||||
import { afterAll, beforeAll, describe, expect, it } from "bun:test";
|
||||
import { promises as fs } from "fs";
|
||||
import { bunEnv, bunExe, isASAN, isWindows, tempDirWithFiles } from "harness";
|
||||
import { bunEnv, bunExe, isArm64, isASAN, isWindows, tempDirWithFiles } from "harness";
|
||||
import path from "path";
|
||||
|
||||
// TinyCC (and all of bun:ffi) is disabled on Windows ARM64
|
||||
const isFFIUnavailable = isWindows && isArm64;
|
||||
|
||||
// TODO: we need to install build-essential and Apple SDK in CI.
|
||||
// It can't find includes. It can on machines with that enabled.
|
||||
// TinyCC's setjmp/longjmp error handling conflicts with ASan.
|
||||
it.todoIf(isWindows || isASAN)("can run a .c file", () => {
|
||||
it.todoIf(isWindows || isASAN || isFFIUnavailable)("can run a .c file", () => {
|
||||
const result = Bun.spawnSync({
|
||||
cmd: [bunExe(), path.join(__dirname, "cc-fixture.js")],
|
||||
cwd: __dirname,
|
||||
@@ -19,7 +22,8 @@ it.todoIf(isWindows || isASAN)("can run a .c file", () => {
|
||||
});
|
||||
|
||||
// TinyCC's setjmp/longjmp error handling conflicts with ASan.
|
||||
describe.skipIf(isASAN)("given an add(a, b) function", () => {
|
||||
// TinyCC is disabled on Windows ARM64.
|
||||
describe.skipIf(isASAN || isFFIUnavailable)("given an add(a, b) function", () => {
|
||||
const source = /* c */ `
|
||||
int add(int a, int b) {
|
||||
return a + b;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { dlopen, linkSymbols } from "bun:ffi";
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { isMusl } from "harness";
|
||||
import { isArm64, isMusl, isWindows } from "harness";
|
||||
|
||||
describe("FFI error messages", () => {
|
||||
// TinyCC (and all of bun:ffi) is disabled on Windows ARM64
|
||||
const isFFIUnavailable = isWindows && isArm64;
|
||||
|
||||
describe.skipIf(isFFIUnavailable)("FFI error messages", () => {
|
||||
test("dlopen shows library name when library cannot be opened", () => {
|
||||
// Try to open a non-existent library
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe, tempDir } from "harness";
|
||||
import { bunEnv, bunExe, isWindows, tempDir } from "harness";
|
||||
|
||||
// Regression test for use-after-poison in builtin OutputTask callbacks
|
||||
// inside command substitution $().
|
||||
@@ -14,7 +14,7 @@ import { bunEnv, bunExe, tempDir } from "harness";
|
||||
// alongside non-existent paths reliably triggers the ASAN
|
||||
// use-after-poison.
|
||||
|
||||
describe("builtins in command substitution with errors should not crash", () => {
|
||||
describe.skipIf(isWindows)("builtins in command substitution with errors should not crash", () => {
|
||||
test("ls with errors in command substitution", async () => {
|
||||
// Create a temp directory with many files to produce output,
|
||||
// and include non-existent paths to produce errors.
|
||||
|
||||
@@ -14,6 +14,10 @@ if (libcFamily == "musl") {
|
||||
// @duckdb/node-bindings does not distribute musl binaries, so we skip this test on musl to avoid CI noise
|
||||
process.exit(0);
|
||||
}
|
||||
if (process.platform === "win32" && process.arch === "arm64") {
|
||||
// @duckdb/node-bindings does not distribute win32-arm64 binaries
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
import { describe, test } from "bun:test";
|
||||
import assert from "node:assert";
|
||||
|
||||
@@ -3,6 +3,10 @@ if (libcFamily == "musl") {
|
||||
// duckdb does not distribute musl binaries, so we skip this test on musl to avoid CI noise
|
||||
process.exit(0);
|
||||
}
|
||||
if (process.platform === "win32" && process.arch === "arm64") {
|
||||
// duckdb does not distribute win32-arm64 binaries
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
import { describe, expect, test } from "bun:test";
|
||||
// Must be CJS require so that the above code can exit before we attempt to import DuckDB
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { spawnSync } from "bun";
|
||||
import { cc, dlopen } from "bun:ffi";
|
||||
import { beforeAll, describe, expect, it } from "bun:test";
|
||||
import { bunEnv, bunExe, isASAN, isWindows } from "harness";
|
||||
import { bunEnv, bunExe, isArm64, isASAN, isWindows } from "harness";
|
||||
import { join } from "path";
|
||||
|
||||
import source from "./napi-app/ffi_addon_1.c" with { type: "file" };
|
||||
|
||||
// TinyCC (and all of bun:ffi) is disabled on Windows ARM64
|
||||
const isFFIUnavailable = isWindows && isArm64;
|
||||
|
||||
const symbols = {
|
||||
set_instance_data: {
|
||||
args: ["napi_env", "int"],
|
||||
@@ -24,6 +27,8 @@ const symbols = {
|
||||
let addon1, addon2, cc1, cc2;
|
||||
|
||||
beforeAll(() => {
|
||||
if (isFFIUnavailable) return;
|
||||
|
||||
// build gyp
|
||||
const install = spawnSync({
|
||||
cmd: [bunExe(), "install", "--verbose"],
|
||||
@@ -59,7 +64,7 @@ beforeAll(() => {
|
||||
}
|
||||
});
|
||||
|
||||
describe("ffi napi integration", () => {
|
||||
describe.skipIf(isFFIUnavailable)("ffi napi integration", () => {
|
||||
it("has a different napi_env for each ffi library", () => {
|
||||
addon1.set_instance_data(undefined, 5);
|
||||
addon2.set_instance_data(undefined, 6);
|
||||
@@ -75,7 +80,7 @@ describe("ffi napi integration", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("cc napi integration", () => {
|
||||
describe.skipIf(isFFIUnavailable)("cc napi integration", () => {
|
||||
// fails on windows as TCC can't link the napi_ functions
|
||||
// TinyCC's setjmp/longjmp error handling conflicts with ASan.
|
||||
it.todoIf(isWindows || isASAN)("has a different napi_env for each cc invocation", () => {
|
||||
|
||||
@@ -14,13 +14,12 @@
|
||||
"@bufbuild/protobuf": "2.10.2",
|
||||
"@connectrpc/connect": "2.1.1",
|
||||
"@connectrpc/connect-node": "2.0.0",
|
||||
"@duckdb/node-api": "1.1.3-alpha.7",
|
||||
"@electric-sql/pglite": "0.2.17",
|
||||
"@fastify/websocket": "11.0.2",
|
||||
"@grpc/grpc-js": "1.12.0",
|
||||
"@grpc/proto-loader": "0.7.10",
|
||||
"@happy-dom/global-registrator": "17.0.3",
|
||||
"@napi-rs/canvas": "0.1.65",
|
||||
"@napi-rs/canvas": "0.1.91",
|
||||
"@nestjs/common": "11.0.3",
|
||||
"@nestjs/core": "11.0.3",
|
||||
"@prisma/client": "5.8.0",
|
||||
@@ -44,7 +43,6 @@
|
||||
"commander": "12.1.0",
|
||||
"detect-libc": "2.0.3",
|
||||
"devalue": "5.1.1",
|
||||
"duckdb": "1.3.1",
|
||||
"es-module-lexer": "1.3.0",
|
||||
"esbuild": "0.18.6",
|
||||
"express": "4.18.2",
|
||||
@@ -65,7 +63,6 @@
|
||||
"jws": "4.0.0",
|
||||
"lodash": "4.17.21",
|
||||
"mongodb": "6.0.0",
|
||||
"msgpackr-extract": "3.0.2",
|
||||
"msw": "2.3.0",
|
||||
"mysql2": "3.7.0",
|
||||
"node-gyp": "10.0.1",
|
||||
@@ -86,7 +83,7 @@
|
||||
"reflect-metadata": "0.2.2",
|
||||
"rollup": "4.4.1",
|
||||
"sass": "1.79.4",
|
||||
"sharp": "0.33.0",
|
||||
"sharp": "0.34.5",
|
||||
"sinon": "6.0.0",
|
||||
"socket.io": "4.7.1",
|
||||
"socket.io-adapter": "2.5.5",
|
||||
@@ -122,6 +119,11 @@
|
||||
"bd:v": "(bun run --silent --cwd=../ build:debug &> /tmp/bun.debug.build.log || (cat /tmp/bun.debug.build.log && rm -rf /tmp/bun.debug.build.log && exit 1)) && rm -f /tmp/bun.debug.build.log && ../build/debug/bun-debug",
|
||||
"bd": "BUN_DEBUG_QUIET_LOGS=1 bun --silent bd:v"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"duckdb": "1.3.1",
|
||||
"@duckdb/node-api": "1.1.3-alpha.7",
|
||||
"msgpackr-extract": "3.0.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"react": "../node_modules/react",
|
||||
"@types/node": "25.0.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from "bun:test";
|
||||
import { readFileSync, unlinkSync } from "fs";
|
||||
import { bunEnv, bunExe, isWindows, tempDirWithFiles } from "harness";
|
||||
import { bunEnv, bunExe, isArm64, isWindows, tempDirWithFiles } from "harness";
|
||||
import { join } from "path";
|
||||
|
||||
describe.if(isWindows)("PE codesigning integrity", () => {
|
||||
@@ -215,7 +215,7 @@ console.log("Test data:", JSON.stringify(data));
|
||||
|
||||
// Validate PE header
|
||||
expect(validation.pe.signature).toBe(0x00004550); // "PE\0\0"
|
||||
expect(validation.pe.machine).toBe(0x8664); // x64
|
||||
expect(validation.pe.machine).toBe(isArm64 ? 0xaa64 : 0x8664); // arm64 or x64
|
||||
expect(validation.pe.numberOfSections).toBeGreaterThan(0);
|
||||
|
||||
// Validate optional header
|
||||
|
||||
Reference in New Issue
Block a user