Compare commits

...

14 Commits

Author SHA1 Message Date
Ashcon Partovi
0d34fae201 Fix 2024-12-20 18:02:07 -08:00
Ashcon Partovi
e2d7077efc Fix multiple agents on same machine 2024-12-20 18:02:07 -08:00
Ashcon Partovi
f713ac9da3 Testing 2024-12-20 18:02:07 -08:00
Ashcon Partovi
866edeb5f5 Testing 2024-12-20 18:02:07 -08:00
Ashcon Partovi
1de7c87557 Script to create a macOS CI agent 2024-12-20 18:02:07 -08:00
Ashcon Partovi
316b408438 Fix incorect macro checks for cross-compiling 2024-12-20 18:02:07 -08:00
Ashcon Partovi
648b01ba92 Re-enable platforms 2024-12-20 18:02:07 -08:00
Ashcon Partovi
545cafc08c Fix typo 2024-12-20 18:02:07 -08:00
Ashcon Partovi
a34b49b2a7 Fix 2024-12-20 18:02:07 -08:00
Ashcon Partovi
3f888f4284 Fix 2024-12-20 18:02:07 -08:00
Ashcon Partovi
835c8dc04b Try this 2024-12-20 18:02:07 -08:00
Ashcon Partovi
e4b1887ea6 Try this 2024-12-20 18:02:06 -08:00
Ashcon Partovi
f743c54864 Try this 2024-12-20 18:02:06 -08:00
Ashcon Partovi
8adb26f856 ci: Test cross-compile darwin x64 2024-12-20 18:02:06 -08:00
37 changed files with 1251 additions and 1221 deletions

View File

@@ -322,7 +322,6 @@ function getCppAgent(platform, options) {
* @returns {Agent}
*/
function getZigAgent(platform, options) {
const { arch } = platform;
return {
queue: "build-zig",
};
@@ -334,13 +333,14 @@ function getZigAgent(platform, options) {
* @returns {Agent}
*/
function getTestAgent(platform, options) {
const { os, arch } = platform;
const { os, arch, release } = platform;
if (os === "darwin") {
return {
queue: `test-${os}`,
os,
arch,
release,
};
}

View File

@@ -1,84 +0,0 @@
# CI
This directory contains scripts for building CI images for Bun.
## Building
### `macOS`
On macOS, images are built using [`tart`](https://tart.run/), a tool that abstracts over the [`Virtualization.Framework`](https://developer.apple.com/documentation/virtualization) APIs, to run macOS VMs.
To install the dependencies required, run:
```sh
$ cd ci
$ bun run bootstrap
```
To build a vanilla macOS VM, run:
```sh
$ bun run build:darwin-aarch64-vanilla
```
This builds a vanilla macOS VM with the current macOS release on your machine. It runs scripts to disable things like spotlight and siri, but it does not install any software.
> Note: The image size is 50GB, so make sure you have enough disk space.
If you want to build a specific macOS release, you can run:
```sh
$ bun run build:darwin-aarch64-vanilla-15
```
> Note: You cannot build a newer release of macOS on an older macOS machine.
To build a macOS VM with software installed to build and test Bun, run:
```sh
$ bun run build:darwin-aarch64
```
## Running
### `macOS`
## How To
### Support a new macOS release
1. Visit [`ipsw.me`](https://ipsw.me/VirtualMac2,1) and find the IPSW of the macOS release you want to build.
2. Add an entry to [`ci/darwin/variables.pkr.hcl`](/ci/darwin/variables.pkr.hcl) with the following format:
```hcl
sonoma = {
distro = "sonoma"
release = "15"
ipsw = "https://updates.cdn-apple.com/..."
}
```
3. Add matching scripts to [`ci/package.json`](/ci/package.json) to build the image, then test it:
```sh
$ bun run build:darwin-aarch64-vanilla-15
```
> Note: If you need to troubleshoot the build, you can remove the `headless = true` property from [`ci/darwin/image-vanilla.pkr.hcl`](/ci/darwin/image-vanilla.pkr.hcl) and the VM's screen will be displayed.
4. Test and build the non-vanilla image:
```sh
$ bun run build:darwin-aarch64-15
```
This will use the vanilla image and run the [`scripts/bootstrap.sh`](/scripts/bootstrap.sh) script to install the required software to build and test Bun.
5. Publish the images:
```sh
$ bun run login
$ bun run publish:darwin-aarch64-vanilla-15
$ bun run publish:darwin-aarch64-15
```

View File

@@ -1,22 +0,0 @@
FROM alpine:edge AS build
ARG GIT_SHA
ENV GIT_SHA=${GIT_SHA}
WORKDIR /app/bun
ENV HOME=/root
COPY . .
RUN touch $HOME/.bashrc
RUN ./scripts/bootstrap.sh
RUN . $HOME/.bashrc && bun run build:release
RUN apk add file
RUN file ./build/release/bun
RUN ldd ./build/release/bun
RUN ./build/release/bun
RUN cp -R /app/bun/build/* /output
FROM scratch AS artifact
COPY --from=build /output /
# docker build -f ./ci/alpine/build.Dockerfile --progress=plain --build-arg GIT_SHA="$(git rev-parse HEAD)" --target=artifact --output type=local,dest=./build-alpine .

View File

@@ -1,20 +0,0 @@
FROM alpine:edge
ENV HOME=/root
WORKDIR /root
COPY ./build-alpine/release/bun .
COPY ./test ./test
COPY ./scripts ./scripts
COPY ./package.json ./package.json
COPY ./packages ./packages
RUN apk update
RUN apk add nodejs lsb-release-minimal git python3 npm make g++
RUN apk add file
RUN file /root/bun
RUN ldd /root/bun
RUN /root/bun
RUN ./scripts/runner.node.mjs --exec-path /root/bun
# docker build -f ./ci/alpine/test.Dockerfile --progress=plain .

View File

@@ -1,46 +0,0 @@
# Generates a vanilla macOS VM with optimized settings for virtualized environments.
# See login.sh and optimize.sh for details.
data "external-raw" "boot-script" {
program = ["sh", "-c", templatefile("scripts/boot-image.sh", var)]
}
source "tart-cli" "bun-darwin-aarch64-vanilla" {
vm_name = "bun-darwin-aarch64-vanilla-${local.release.distro}-${local.release.release}"
from_ipsw = local.release.ipsw
cpu_count = local.cpu_count
memory_gb = local.memory_gb
disk_size_gb = local.disk_size_gb
ssh_username = local.username
ssh_password = local.password
ssh_timeout = "120s"
create_grace_time = "30s"
boot_command = split("\n", data.external-raw.boot-script.result)
headless = true # Disable if you need to debug why the boot_command is not working
}
build {
sources = ["source.tart-cli.bun-darwin-aarch64-vanilla"]
provisioner "file" {
content = file("scripts/setup-login.sh")
destination = "/tmp/setup-login.sh"
}
provisioner "shell" {
inline = ["echo \"${local.password}\" | sudo -S sh -c 'sh /tmp/setup-login.sh \"${local.username}\" \"${local.password}\"'"]
}
provisioner "file" {
content = file("scripts/optimize-machine.sh")
destination = "/tmp/optimize-machine.sh"
}
provisioner "shell" {
inline = ["sudo sh /tmp/optimize-machine.sh"]
}
provisioner "shell" {
inline = ["sudo rm -rf /tmp/*"]
}
}

View File

@@ -1,44 +0,0 @@
# Generates a macOS VM with software installed to build and test Bun.
source "tart-cli" "bun-darwin-aarch64" {
vm_name = "bun-darwin-aarch64-${local.release.distro}-${local.release.release}"
vm_base_name = "bun-darwin-aarch64-vanilla-${local.release.distro}-${local.release.release}"
cpu_count = local.cpu_count
memory_gb = local.memory_gb
disk_size_gb = local.disk_size_gb
ssh_username = local.username
ssh_password = local.password
ssh_timeout = "120s"
headless = true
}
build {
sources = ["source.tart-cli.bun-darwin-aarch64"]
provisioner "file" {
content = file("../../scripts/bootstrap.sh")
destination = "/tmp/bootstrap.sh"
}
provisioner "shell" {
inline = ["CI=true sh /tmp/bootstrap.sh"]
}
provisioner "file" {
source = "darwin/plists/"
destination = "/tmp/"
}
provisioner "shell" {
inline = [
"sudo ls /tmp/",
"sudo mv /tmp/*.plist /Library/LaunchDaemons/",
"sudo chown root:wheel /Library/LaunchDaemons/*.plist",
"sudo chmod 644 /Library/LaunchDaemons/*.plist",
]
}
provisioner "shell" {
inline = ["sudo rm -rf /tmp/*"]
}
}

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.buildkite.buildkite-agent</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/buildkite-agent</string>
<string>start</string>
</array>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false />
</dict>
<key>RunAtLoad</key>
<true />
<key>StandardOutPath</key>
<string>/var/buildkite-agent/logs/buildkite-agent.log</string>
<key>StandardErrorPath</key>
<string>/var/buildkite-agent/logs/buildkite-agent.log</string>
<key>EnvironmentVariables</key>
<dict>
<key>BUILDKITE_AGENT_CONFIG</key>
<string>/etc/buildkite-agent/buildkite-agent.cfg</string>
</dict>
<key>LimitLoadToSessionType</key>
<array>
<string>Aqua</string>
<string>LoginWindow</string>
<string>Background</string>
<string>StandardIO</string>
<string>System</string>
</array>
</dict>
</plist>

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.tailscale.tailscaled</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/tailscale</string>
<string>up</string>
<string>--ssh</string>
<string>--authkey</string>
<string>${TAILSCALE_AUTHKEY}</string>
</array>
<key>RunAtLoad</key>
<true />
</dict>
</plist>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.tailscale.tailscaled</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/tailscaled</string>
</array>
<key>RunAtLoad</key>
<true />
</dict>
</plist>

View File

@@ -1,124 +0,0 @@
#!/bin/sh
# This script generates the boot commands for the macOS installer GUI.
# It is run on your local machine, not inside the VM.
# Sources:
# - https://github.com/cirruslabs/macos-image-templates/blob/master/templates/vanilla-sequoia.pkr.hcl
if ! [ "${release}" ] || ! [ "${username}" ] || ! [ "${password}" ]; then
echo "Script must be run with variables: release, username, and password" >&2
exit 1
fi
# Hello, hola, bonjour, etc.
echo "<wait120s><spacebar>"
# Select Your Country and Region
echo "<wait30s>italiano<esc>english<enter>"
echo "<wait30s>united states<leftShiftOn><tab><leftShiftOff><spacebar>"
# Written and Spoken Languages
echo "<wait30s><leftShiftOn><tab><leftShiftOff><spacebar>"
# Accessibility
echo "<wait30s><leftShiftOn><tab><leftShiftOff><spacebar>"
# Data & Privacy
echo "<wait30s><leftShiftOn><tab><leftShiftOff><spacebar>"
# Migration Assistant
echo "<wait30s><tab><tab><tab><spacebar>"
# Sign In with Your Apple ID
echo "<wait30s><leftShiftOn><tab><leftShiftOff><leftShiftOn><tab><leftShiftOff><spacebar>"
# Are you sure you want to skip signing in with an Apple ID?
echo "<wait30s><tab><spacebar>"
# Terms and Conditions
echo "<wait30s><leftShiftOn><tab><leftShiftOff><spacebar>"
# I have read and agree to the macOS Software License Agreement
echo "<wait30s><tab><spacebar>"
# Create a Computer Account
echo "<wait30s>${username}<tab><tab>${password}<tab>${password}<tab><tab><tab><spacebar>"
# Enable Location Services
echo "<wait60s><leftShiftOn><tab><leftShiftOff><spacebar>"
# Are you sure you don't want to use Location Services?
echo "<wait30s><tab><spacebar>"
# Select Your Time Zone
echo "<wait30s><tab>UTC<enter><leftShiftOn><tab><leftShiftOff><spacebar>"
# Analytics
echo "<wait30s><leftShiftOn><tab><leftShiftOff><spacebar>"
# Screen Time
echo "<wait30s><tab><spacebar>"
# Siri
echo "<wait30s><tab><spacebar><leftShiftOn><tab><leftShiftOff><spacebar>"
# Choose Your Look
echo "<wait30s><leftShiftOn><tab><leftShiftOff><spacebar>"
if [ "${release}" = "13" ] || [ "${release}" = "14" ]; then
# Enable Voice Over
echo "<wait30s><leftAltOn><f5><leftAltOff><wait5s>v"
else
# Welcome to Mac
echo "<wait30s><spacebar>"
# Enable Keyboard navigation
echo "<wait30s><leftAltOn><spacebar><leftAltOff>Terminal<enter>"
echo "<wait30s>defaults write NSGlobalDomain AppleKeyboardUIMode -int 3<enter>"
echo "<wait30s><leftAltOn>q<leftAltOff>"
fi
# Now that the installation is done, open "System Settings"
echo "<wait30s><leftAltOn><spacebar><leftAltOff>System Settings<enter>"
# Navigate to "Sharing"
echo "<wait30s><leftAltOn>f<leftAltOff>sharing<enter>"
if [ "${release}" = "13" ]; then
# Navigate to "Screen Sharing" and enable it
echo "<wait30s><tab><down><spacebar>"
# Navigate to "Remote Login" and enable it
echo "<wait30s><tab><tab><tab><tab><tab><tab><spacebar>"
# Open "Remote Login" details
echo "<wait30s><tab><spacebar>"
# Enable "Full Disk Access"
echo "<wait30s><tab><spacebar>"
# Click "Done"
echo "<wait30s><leftShiftOn><tab><leftShiftOff><leftShiftOn><tab><leftShiftOff><spacebar>"
# Disable Voice Over
echo "<leftAltOn><f5><leftAltOff>"
elif [ "${release}" = "14" ]; then
# Navigate to "Screen Sharing" and enable it
echo "<wait30s><tab><tab><tab><tab><tab><spacebar>"
# Navigate to "Remote Login" and enable it
echo "<wait30s><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><spacebar>"
# Disable Voice Over
echo "<wait30s><leftAltOn><f5><leftAltOff>"
elif [ "${release}" = "15" ]; then
# Navigate to "Screen Sharing" and enable it
echo "<wait30s><tab><tab><tab><tab><tab><spacebar>"
# Navigate to "Remote Login" and enable it
echo "<wait30s><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><spacebar>"
fi
# Quit System Settings
echo "<wait30s><leftAltOn>q<leftAltOff>"

View File

@@ -1,122 +0,0 @@
#!/bin/sh
# This script optimizes macOS for virtualized environments.
# It disables things like spotlight, screen saver, and sleep.
# Sources:
# - https://github.com/sickcodes/osx-optimizer
# - https://github.com/koding88/MacBook-Optimization-Script
# - https://www.macstadium.com/blog/simple-optimizations-for-macos-and-ios-build-agents
if [ "$(id -u)" != "0" ]; then
echo "This script must be run using sudo." >&2
exit 1
fi
execute() {
echo "$ $@" >&2
if ! "$@"; then
echo "Command failed: $@" >&2
exit 1
fi
}
disable_software_update() {
execute softwareupdate --schedule off
execute defaults write com.apple.SoftwareUpdate AutomaticDownload -bool false
execute defaults write com.apple.SoftwareUpdate AutomaticCheckEnabled -bool false
execute defaults write com.apple.SoftwareUpdate ConfigDataInstall -int 0
execute defaults write com.apple.SoftwareUpdate CriticalUpdateInstall -int 0
execute defaults write com.apple.SoftwareUpdate ScheduleFrequency -int 0
execute defaults write com.apple.SoftwareUpdate AutomaticDownload -int 0
execute defaults write com.apple.commerce AutoUpdate -bool false
execute defaults write com.apple.commerce AutoUpdateRestartRequired -bool false
}
disable_spotlight() {
execute mdutil -i off -a
execute mdutil -E /
}
disable_siri() {
execute launchctl unload -w /System/Library/LaunchAgents/com.apple.Siri.agent.plist
execute defaults write com.apple.Siri StatusMenuVisible -bool false
execute defaults write com.apple.Siri UserHasDeclinedEnable -bool true
execute defaults write com.apple.assistant.support "Assistant Enabled" 0
}
disable_sleep() {
execute systemsetup -setsleep Never
execute systemsetup -setcomputersleep Never
execute systemsetup -setdisplaysleep Never
execute systemsetup -setharddisksleep Never
}
disable_screen_saver() {
execute defaults write com.apple.screensaver loginWindowIdleTime 0
execute defaults write com.apple.screensaver idleTime 0
}
disable_screen_lock() {
execute defaults write com.apple.loginwindow DisableScreenLock -bool true
}
disable_wallpaper() {
execute defaults write com.apple.loginwindow DesktopPicture ""
}
disable_application_state() {
execute defaults write com.apple.loginwindow TALLogoutSavesState -bool false
}
disable_accessibility() {
execute defaults write com.apple.Accessibility DifferentiateWithoutColor -int 1
execute defaults write com.apple.Accessibility ReduceMotionEnabled -int 1
execute defaults write com.apple.universalaccess reduceMotion -int 1
execute defaults write com.apple.universalaccess reduceTransparency -int 1
}
disable_dashboard() {
execute defaults write com.apple.dashboard mcx-disabled -boolean YES
execute killall Dock
}
disable_animations() {
execute defaults write NSGlobalDomain NSAutomaticWindowAnimationsEnabled -bool false
execute defaults write -g QLPanelAnimationDuration -float 0
execute defaults write com.apple.finder DisableAllAnimations -bool true
}
disable_time_machine() {
execute tmutil disable
}
enable_performance_mode() {
# https://support.apple.com/en-us/101992
if ! [ $(nvram boot-args 2>/dev/null | grep -q serverperfmode) ]; then
execute nvram boot-args="serverperfmode=1 $(nvram boot-args 2>/dev/null | cut -f 2-)"
fi
}
add_terminal_to_desktop() {
execute ln -sf /System/Applications/Utilities/Terminal.app ~/Desktop/Terminal
}
main() {
disable_software_update
disable_spotlight
disable_siri
disable_sleep
disable_screen_saver
disable_screen_lock
disable_wallpaper
disable_application_state
disable_accessibility
disable_dashboard
disable_animations
disable_time_machine
enable_performance_mode
add_terminal_to_desktop
}
main

View File

@@ -1,78 +0,0 @@
#!/bin/sh
# This script generates a /etc/kcpassword file to enable auto-login on macOS.
# Yes, this stores your password in plain text. Do NOT do this on your local machine.
# Sources:
# - https://github.com/xfreebird/kcpassword/blob/master/kcpassword
if [ "$(id -u)" != "0" ]; then
echo "This script must be run using sudo." >&2
exit 1
fi
execute() {
echo "$ $@" >&2
if ! "$@"; then
echo "Command failed: $@" >&2
exit 1
fi
}
kcpassword() {
passwd="$1"
key="7d 89 52 23 d2 bc dd ea a3 b9 1f"
passwd_hex=$(printf "%s" "$passwd" | xxd -p | tr -d '\n')
key_len=33
passwd_len=${#passwd_hex}
remainder=$((passwd_len % key_len))
if [ $remainder -ne 0 ]; then
padding=$((key_len - remainder))
passwd_hex="${passwd_hex}$(printf '%0*x' $((padding / 2)) 0)"
fi
result=""
i=0
while [ $i -lt ${#passwd_hex} ]; do
for byte in $key; do
[ $i -ge ${#passwd_hex} ] && break
p="${passwd_hex:$i:2}"
r=$(printf '%02x' $((0x$p ^ 0x$byte)))
result="${result}${r}"
i=$((i + 2))
done
done
echo "$result"
}
login() {
username="$1"
password="$2"
enable_passwordless_sudo() {
execute mkdir -p /etc/sudoers.d/
echo "${username} ALL=(ALL) NOPASSWD: ALL" | EDITOR=tee execute visudo "/etc/sudoers.d/${username}-nopasswd"
}
enable_auto_login() {
echo "00000000: 1ced 3f4a bcbc ba2c caca 4e82" | execute xxd -r - /etc/kcpassword
execute defaults write /Library/Preferences/com.apple.loginwindow autoLoginUser "${username}"
}
disable_screen_lock() {
execute sysadminctl -screenLock off -password "${password}"
}
enable_passwordless_sudo
enable_auto_login
disable_screen_lock
}
if [ $# -ne 2 ]; then
echo "Usage: $0 <username> <password>" >&2
exit 1
fi
login "$@"

View File

@@ -1,78 +0,0 @@
packer {
required_plugins {
tart = {
version = ">= 1.12.0"
source = "github.com/cirruslabs/tart"
}
external = {
version = ">= 0.0.2"
source = "github.com/joomcode/external"
}
}
}
variable "release" {
type = number
default = 13
}
variable "username" {
type = string
default = "admin"
}
variable "password" {
type = string
default = "admin"
}
variable "cpu_count" {
type = number
default = 2
}
variable "memory_gb" {
type = number
default = 4
}
variable "disk_size_gb" {
type = number
default = 50
}
locals {
sequoia = {
tier = 1
distro = "sequoia"
release = "15"
ipsw = "https://updates.cdn-apple.com/2024FallFCS/fullrestores/062-78489/BDA44327-C79E-4608-A7E0-455A7E91911F/UniversalMac_15.0_24A335_Restore.ipsw"
}
sonoma = {
tier = 2
distro = "sonoma"
release = "14"
ipsw = "https://updates.cdn-apple.com/2023FallFCS/fullrestores/042-54934/0E101AD6-3117-4B63-9BF1-143B6DB9270A/UniversalMac_14.0_23A344_Restore.ipsw"
}
ventura = {
tier = 2
distro = "ventura"
release = "13"
ipsw = "https://updates.cdn-apple.com/2022FallFCS/fullrestores/012-92188/2C38BCD1-2BFF-4A10-B358-94E8E28BE805/UniversalMac_13.0_22A380_Restore.ipsw"
}
releases = {
15 = local.sequoia
14 = local.sonoma
13 = local.ventura
}
release = local.releases[var.release]
username = var.username
password = var.password
cpu_count = var.cpu_count
memory_gb = var.memory_gb
disk_size_gb = var.disk_size_gb
}

View File

@@ -1,18 +0,0 @@
ARG IMAGE=debian:11
FROM $IMAGE
COPY ./scripts/bootstrap.sh /tmp/bootstrap.sh
ENV CI=true
RUN sh /tmp/bootstrap.sh && rm -rf /tmp/*
WORKDIR /workspace/bun
COPY bunfig.toml bunfig.toml
COPY package.json package.json
COPY CMakeLists.txt CMakeLists.txt
COPY cmake/ cmake/
COPY scripts/ scripts/
COPY patches/ patches/
COPY *.zig ./
COPY src/ src/
COPY packages/ packages/
COPY test/ test/
RUN bun i
RUN bun run build:ci

View File

@@ -1,27 +0,0 @@
#!/bin/sh
# This script sets the hostname of the current machine.
execute() {
echo "$ $@" >&2
if ! "$@"; then
echo "Command failed: $@" >&2
exit 1
fi
}
main() {
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <hostname>" >&2
exit 1
fi
if [ -f "$(which hostnamectl)" ]; then
execute hostnamectl set-hostname "$1"
else
echo "Error: hostnamectl is not installed." >&2
exit 1
fi
}
main "$@"

View File

@@ -1,22 +0,0 @@
#!/bin/sh
# This script starts tailscale on the current machine.
execute() {
echo "$ $@" >&2
if ! "$@"; then
echo "Command failed: $@" >&2
exit 1
fi
}
main() {
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <auth-key>" >&2
exit 1
fi
execute tailscale up --reset --ssh --accept-risk=lose-ssh --auth-key="$1"
}
main "$@"

View File

@@ -1,27 +0,0 @@
{
"private": true,
"scripts": {
"bootstrap": "brew install gh jq cirruslabs/cli/tart cirruslabs/cli/sshpass hashicorp/tap/packer && packer init darwin",
"login": "token=$(gh auth token); username=$(gh api user --jq .login); echo \"Login as $username...\"; echo \"$token\" | tart login ghcr.io --username \"$username\" --password-stdin; echo \"$token\" | docker login ghcr.io --username \"$username\" --password-stdin",
"fetch:image-name": "echo ghcr.io/oven-sh/bun-vm",
"fetch:darwin-version": "echo 1",
"fetch:macos-version": "sw_vers -productVersion | cut -d. -f1",
"fetch:script-version": "cat ../scripts/bootstrap.sh | grep 'v=' | sed 's/v=\"//;s/\"//' | head -n 1",
"build:darwin-aarch64-vanilla": "packer build '-only=*.bun-darwin-aarch64-vanilla' -var release=$(bun fetch:macos-version) darwin/",
"build:darwin-aarch64-vanilla-15": "packer build '-only=*.bun-darwin-aarch64-vanilla' -var release=15 darwin/",
"build:darwin-aarch64-vanilla-14": "packer build '-only=*.bun-darwin-aarch64-vanilla' -var release=14 darwin/",
"build:darwin-aarch64-vanilla-13": "packer build '-only=*.bun-darwin-aarch64-vanilla' -var release=13 darwin/",
"build:darwin-aarch64": "packer build '-only=*.bun-darwin-aarch64' -var release=$(bun fetch:macos-version) darwin/",
"build:darwin-aarch64-15": "packer build '-only=*.bun-darwin-aarch64' -var release=15 darwin/",
"build:darwin-aarch64-14": "packer build '-only=*.bun-darwin-aarch64' -var release=14 darwin/",
"build:darwin-aarch64-13": "packer build '-only=*.bun-darwin-aarch64' -var release=13 darwin/",
"publish:darwin-aarch64-vanilla": "image=$(tart list --format json | jq -r \".[] | select(.Name | test(\\\"^bun-darwin-aarch64-vanilla-.*-$(bun fetch:macos-version)$\\\")) | .Name\" | head -n 1 | sed 's/bun-//'); tart push \"bun-$image\" \"ghcr.io/oven-sh/bun-vm:$image-v$(bun fetch:darwin-version)\"",
"publish:darwin-aarch64-vanilla-15": "tart push bun-darwin-aarch64-vanilla-sequoia-15 \"$(bun fetch:image-name):darwin-aarch64-vanilla-sequoia-15-v$(bun fetch:darwin-version)\"",
"publish:darwin-aarch64-vanilla-14": "tart push bun-darwin-aarch64-vanilla-sonoma-14 \"$(bun fetch:image-name):darwin-aarch64-vanilla-sonoma-14-v$(bun fetch:darwin-version)\"",
"publish:darwin-aarch64-vanilla-13": "tart push bun-darwin-aarch64-vanilla-ventura-13 \"$(bun fetch:image-name):darwin-aarch64-vanilla-ventura-13-v$(bun fetch:darwin-version)\"",
"publish:darwin-aarch64": "image=$(tart list --format json | jq -r \".[] | select(.Name | test(\\\"^bun-darwin-aarch64-.*-$(bun fetch:macos-version)$\\\")) | .Name\" | head -n 1 | sed 's/bun-//'); tart push \"bun-$image\" \"ghcr.io/oven-sh/bun-vm:$image-v$(bun fetch:script-version)\"",
"publish:darwin-aarch64-15": "tart push bun-darwin-aarch64-sequoia-15 \"$(bun fetch:image-name):darwin-aarch64-sequoia-15-v$(bun fetch:script-version)\"",
"publish:darwin-aarch64-14": "tart push bun-darwin-aarch64-sonoma-14 \"$(bun fetch:image-name):darwin-aarch64-sonoma-14-v$(bun fetch:script-version)\"",
"publish:darwin-aarch64-13": "tart push bun-darwin-aarch64-ventura-13 \"$(bun fetch:image-name):darwin-aarch64-ventura-13-v$(bun fetch:script-version)\""
}
}

View File

@@ -743,6 +743,10 @@ function(register_cmake_command)
list(APPEND MAKE_EFFECTIVE_ARGS --fresh)
endif()
if(CMAKE_TOOLCHAIN_FILE)
list(APPEND MAKE_EFFECTIVE_ARGS "--toolchain=${CMAKE_TOOLCHAIN_FILE}")
endif()
register_command(
COMMENT "Configuring ${MAKE_TARGET}"
TARGET configure-${MAKE_TARGET}

View File

@@ -330,7 +330,6 @@ register_command(
${BUN_BAKE_RUNTIME_CODEGEN_SOURCES}
${BUN_BAKE_RUNTIME_CODEGEN_SCRIPT}
OUTPUTS
${CODEGEN_PATH}/bake_empty_file
${BUN_BAKE_RUNTIME_OUTPUTS}
)
@@ -507,9 +506,7 @@ set(BUN_ZIG_GENERATED_SOURCES
)
# In debug builds, these are not embedded, but rather referenced at runtime.
if (DEBUG)
list(APPEND BUN_ZIG_GENERATED_SOURCES ${CODEGEN_PATH}/bake_empty_file)
else()
if(NOT DEBUG)
list(APPEND BUN_ZIG_GENERATED_SOURCES ${BUN_BAKE_RUNTIME_OUTPUTS})
endif()

View File

@@ -1,5 +1,4 @@
set(CMAKE_SYSTEM_NAME Darwin)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)

View File

@@ -1,6 +1,5 @@
set(CMAKE_SYSTEM_NAME Darwin)
set(CMAKE_SYSTEM_PROCESSOR x64)
set(CMAKE_OSX_ARCHITECTURES x86_64)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)

View File

@@ -1,6 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(ABI musl)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)

View File

@@ -1,6 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(ABI gnu)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)

View File

@@ -2,6 +2,5 @@ set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR x64)
set(ENABLE_BASELINE ON)
set(ABI gnu)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)

View File

@@ -2,6 +2,5 @@ set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR x64)
set(ENABLE_BASELINE ON)
set(ABI musl)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)

View File

@@ -1,6 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR x64)
set(ABI musl)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)

View File

@@ -1,6 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR x64)
set(ABI gnu)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)

View File

@@ -1,6 +1,5 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x64)
set(ENABLE_BASELINE ON)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)

View File

@@ -1,5 +1,4 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x64)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)

File diff suppressed because it is too large Load Diff

View File

@@ -19,9 +19,7 @@ print() {
error() {
print "error: $@" >&2
if ! [ "$$" = "$pid" ]; then
kill -s TERM "$pid"
fi
kill -s TERM "$pid"
exit 1
}
@@ -59,14 +57,14 @@ execute_as_user() {
}
grant_to_user() {
path="$1"
if ! [ -f "$path" ] && ! [ -d "$path" ]; then
error "Could not find file or directory: \"$path\""
grant_path="$1"
if ! [ -f "$grant_path" ] && ! [ -d "$grant_path" ]; then
error "Could not find file or directory: \"$grant_path\""
fi
chown="$(require chown)"
execute_sudo "$chown" -R "$user:$group" "$path"
execute_sudo chmod -R 777 "$path"
execute_sudo "$chown" -R "$user:$group" "$grant_path"
execute_sudo chmod -R 777 "$grant_path"
}
which() {
@@ -74,11 +72,11 @@ which() {
}
require() {
path="$(which "$1")"
if ! [ -f "$path" ]; then
exe_path="$(which "$1")"
if ! [ -f "$exe_path" ]; then
error "Command \"$1\" is required, but is not installed."
fi
print "$path"
print "$exe_path"
}
fetch() {
@@ -106,79 +104,79 @@ compare_version() {
}
create_directory() {
path="$1"
path_dir="$path"
while ! [ -d "$path_dir" ]; do
path_dir="$(dirname "$path_dir")"
dir_path="$1"
dir_parent_path="$dir_path"
while ! [ -d "$dir_parent_path" ]; do
dir_parent_path="$(dirname "$dir_parent_path")"
done
path_needs_sudo="0"
if ! [ -r "$path_dir" ] || ! [ -w "$path_dir" ]; then
path_needs_sudo="1"
dir_needs_sudo="0"
if ! [ -r "$dir_parent_path" ] || ! [ -w "$dir_parent_path" ]; then
dir_needs_sudo="1"
fi
mkdir="$(require mkdir)"
if [ "$path_needs_sudo" = "1" ]; then
execute_sudo "$mkdir" -p "$path"
if [ "$dir_needs_sudo" = "1" ]; then
execute_sudo "$mkdir" -p "$dir_path"
else
execute "$mkdir" -p "$path"
execute "$mkdir" -p "$dir_path"
fi
grant_to_user "$path"
grant_to_user "$dir_path"
}
create_tmp_directory() {
mktemp="$(require mktemp)"
path="$(execute "$mktemp" -d)"
grant_to_user "$path"
print "$path"
tmp_path="$(execute "$mktemp" -d)"
grant_to_user "$tmp_path"
print "$tmp_path"
}
create_file() {
path="$1"
path_dir="$(dirname "$path")"
if ! [ -d "$path_dir" ]; then
create_directory "$path_dir"
file_path="$1"
file_parent_path="$(dirname "$file_path")"
if ! [ -d "$file_parent_path" ]; then
create_directory "$file_parent_path"
fi
path_needs_sudo="0"
if ! [ -r "$path" ] || ! [ -w "$path" ]; then
path_needs_sudo="1"
file_needs_sudo="0"
if ! [ -r "$file_path" ] || ! [ -w "$file_path" ]; then
file_needs_sudo="1"
fi
if [ "$path_needs_sudo" = "1" ]; then
execute_sudo touch "$path"
if [ "$file_needs_sudo" = "1" ]; then
execute_sudo touch "$file_path"
else
execute touch "$path"
execute touch "$file_path"
fi
content="$2"
if [ -n "$content" ]; then
append_file "$path" "$content"
file_content="$2"
if [ -n "$file_content" ]; then
append_file "$file_path" "$file_content"
fi
grant_to_user "$path"
grant_to_user "$file_path"
}
append_file() {
path="$1"
if ! [ -f "$path" ]; then
create_file "$path"
file_path="$1"
if ! [ -f "$file_path" ]; then
create_file "$file_path"
fi
path_needs_sudo="0"
if ! [ -r "$path" ] || ! [ -w "$path" ]; then
path_needs_sudo="1"
file_needs_sudo="0"
if ! [ -r "$file_path" ] || ! [ -w "$file_path" ]; then
file_needs_sudo="1"
fi
content="$2"
print "$content" | while read -r line; do
if ! grep -q "$line" "$path"; then
if ! grep -q "$line" "$file_path"; then
sh="$(require sh)"
if [ "$path_needs_sudo" = "1" ]; then
execute_sudo "$sh" -c "echo '$line' >> '$path'"
if [ "$file_needs_sudo" = "1" ]; then
execute_sudo "$sh" -c "echo '$line' >> '$file_path'"
else
execute "$sh" -c "echo '$line' >> '$path'"
execute "$sh" -c "echo '$line' >> '$file_path'"
fi
fi
done
@@ -197,7 +195,7 @@ download_file() {
append_to_profile() {
content="$1"
profiles=".profile .zprofile .bash_profile .bashrc .zshrc"
profiles=".profile .zprofile .bash_profile .bashrc .zshrc .zshenv"
for profile in $profiles; do
for profile_path in "$current_home/$profile" "$home/$profile"; do
if [ "$ci" = "1" ] || [ -f "$profile_path" ]; then
@@ -208,13 +206,13 @@ append_to_profile() {
}
append_to_path() {
path="$1"
if ! [ -d "$path" ]; then
error "Could not find directory: \"$path\""
bin_path="$1"
if ! [ -d "$bin_path" ]; then
error "Could not find directory: \"$bin_path\""
fi
append_to_profile "export PATH=\"$path:\$PATH\""
export PATH="$path:$PATH"
append_to_profile "export PATH=\"$bin_path:\$PATH\""
export PATH="$bin_path:$PATH"
}
move_to_bin() {
@@ -231,6 +229,13 @@ move_to_bin() {
done
grant_to_user "$exe_path"
if ! [ -d "$usr_path" ]; then
execute_sudo mkdir -p "$usr_path"
grant_to_user "$usr_path"
fi
append_to_path "$usr_path"
execute_sudo mv -f "$exe_path" "$usr_path/$(basename "$exe_path")"
}
@@ -430,17 +435,18 @@ check_package_manager() {
check_user() {
print "Checking user..."
id="$(require id)"
if [ -n "$SUDO_USER" ]; then
user="$SUDO_USER"
else
id="$(require id)"
user="$("$id" -un)"
group="$("$id" -gn)"
fi
if [ -z "$user" ]; then
error "Could not determine user"
fi
print "User: $user"
group="$("$id" -gn "$user")"
print "Group: $group"
home="$(execute_as_user echo '~')"
@@ -449,13 +455,14 @@ check_user() {
fi
print "Home: $home"
id="$(which id)"
if [ -f "$id" ] && [ "$($id -u)" = "0" ]; then
sudo=1
print "Sudo: enabled"
elif [ -f "$(which sudo)" ] && [ "$(sudo -n echo 1 2>/dev/null)" = "1" ]; then
can_sudo=1
print "Sudo: can be used"
if [ -f "$(which sudo)" ] && [ -f "$(which id)" ]; then
if [ "$(id -u)" = "0" ]; then
sudo=1
print "Sudo: enabled"
elif [ "$(sudo -n echo 1 2>/dev/null)" = "1" ]; then
can_sudo=1
print "Sudo: can be used"
fi
fi
current_user="$user"
@@ -639,7 +646,7 @@ install_brew() {
bash="$(require bash)"
script=$(download_file "https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh")
execute_as_user "$bash" -lc "NONINTERACTIVE=1 $script"
execute_as_user "$bash" -lc "$script"
case "$arch" in
x64)
@@ -793,7 +800,7 @@ install_bun() {
bun_zip="$(download_file "$bun_download_url")"
bun_tmpdir="$(dirname "$bun_zip")"
execute "$unzip" -o "$bun_zip" -d "$bun_tmpdir"
move_to_bin "$bun_tmpdir/$bun_triplet/bun"
bun_path="$(require bun)"
execute_sudo ln -sf "$bun_path" "$(dirname "$bun_path")/bunx"
@@ -1021,7 +1028,7 @@ install_rust() {
sh="$(require sh)"
rustup_script=$(download_file "https://sh.rustup.rs")
execute "$sh" -lc "$rustup_script -y --no-modify-path"
execute "$sh" -lc "CARGO_HOME=$rust_home RUSTUP_HOME=$rust_home $rustup_script -y --no-modify-path"
append_to_path "$rust_home/bin"
;;
esac
@@ -1065,7 +1072,7 @@ install_docker() {
fi
getent="$(which getent)"
if [ -n "$("$getent" group docker)" ]; then
if [ -f "$getent" ] && [ -n "$("$getent" group docker)" ]; then
usermod="$(which usermod)"
if [ -f "$usermod" ]; then
execute_sudo "$usermod" -aG docker "$user"
@@ -1128,6 +1135,10 @@ install_tailscale() {
install_packages go
execute_as_user go install tailscale.com/cmd/tailscale{,d}@latest
append_to_path "$home/go/bin"
tailscaled_path="$(which tailscaled)"
if [ -f "$tailscaled_path" ]; then
execute_sudo "$tailscaled_path" install-system-daemon
fi
;;
esac
}
@@ -1312,6 +1323,112 @@ clean_system() {
done
}
optimize_system() {
if ! [ "$ci" = "1" ]; then
return
fi
case "$os" in
darwin)
optimize_system_darwin
;;
esac
}
optimize_system_darwin() {
print "Optimizing macOS system..."
disable_software_update() {
execute_sudo softwareupdate --schedule off
execute_sudo defaults write com.apple.SoftwareUpdate AutomaticDownload -bool false
execute_sudo defaults write com.apple.SoftwareUpdate AutomaticCheckEnabled -bool false
execute_sudo defaults write com.apple.SoftwareUpdate ConfigDataInstall -int 0
execute_sudo defaults write com.apple.SoftwareUpdate CriticalUpdateInstall -int 0
execute_sudo defaults write com.apple.SoftwareUpdate ScheduleFrequency -int 0
execute_sudo defaults write com.apple.SoftwareUpdate AutomaticDownload -int 0
execute_sudo defaults write com.apple.commerce AutoUpdate -bool false
execute_sudo defaults write com.apple.commerce AutoUpdateRestartRequired -bool false
}
disable_spotlight() {
execute_sudo mdutil -i off -a
execute_sudo mdutil -E /
}
disable_siri() {
execute_sudo launchctl unload -w /System/Library/LaunchAgents/com.apple.Siri.agent.plist
execute_sudo defaults write com.apple.Siri StatusMenuVisible -bool false
execute_sudo defaults write com.apple.Siri UserHasDeclinedEnable -bool true
execute_sudo defaults write com.apple.assistant.support "Assistant Enabled" 0
}
disable_sleep() {
execute_sudo systemsetup -setsleep Never
execute_sudo systemsetup -setcomputersleep Never
execute_sudo systemsetup -setdisplaysleep Never
execute_sudo systemsetup -setharddisksleep Never
}
disable_screen_saver() {
execute_sudo defaults write com.apple.screensaver loginWindowIdleTime 0
execute_sudo defaults write com.apple.screensaver idleTime 0
}
disable_screen_lock() {
execute_sudo defaults write com.apple.loginwindow DisableScreenLock -bool true
}
disable_wallpaper() {
execute_sudo defaults write com.apple.loginwindow DesktopPicture ""
}
disable_application_state() {
execute_sudo defaults write com.apple.loginwindow TALLogoutSavesState -bool false
}
disable_accessibility() {
execute_sudo defaults write com.apple.Accessibility DifferentiateWithoutColor -int 1
execute_sudo defaults write com.apple.Accessibility ReduceMotionEnabled -int 1
execute_sudo defaults write com.apple.universalaccess reduceMotion -int 1
execute_sudo defaults write com.apple.universalaccess reduceTransparency -int 1
}
disable_dashboard() {
execute_sudo defaults write com.apple.dashboard mcx-disabled -boolean YES
}
disable_animations() {
execute_sudo defaults write NSGlobalDomain NSAutomaticWindowAnimationsEnabled -bool false
execute_sudo defaults write -g QLPanelAnimationDuration -float 0
execute_sudo defaults write com.apple.finder DisableAllAnimations -bool true
}
disable_time_machine() {
execute_sudo tmutil disable
}
enable_performance_mode() {
# https://support.apple.com/en-us/101992
if ! [ $(nvram boot-args 2>/dev/null | grep -q serverperfmode) ]; then
execute_sudo nvram boot-args="serverperfmode=1 $(nvram boot-args 2>/dev/null | cut -f 2-)"
fi
}
disable_software_update
disable_spotlight
disable_siri
disable_sleep
disable_screen_saver
disable_screen_lock
disable_wallpaper
disable_application_state
disable_accessibility
disable_dashboard
disable_animations
disable_time_machine
enable_performance_mode
}
main() {
check_features "$@"
check_operating_system
@@ -1324,6 +1441,7 @@ main() {
install_build_essentials
install_chromium
clean_system
optimize_system
}
main "$@"

View File

@@ -59,10 +59,16 @@ async function build(args) {
generateOptions["-S"] = process.cwd();
}
const toolchain = generateOptions["--toolchain"];
if (toolchain) {
const toolchainPath = resolve(import.meta.dirname, "..", "cmake", "toolchains", `${toolchain}.cmake`);
generateOptions["--toolchain"] = toolchainPath;
}
const cacheRead = isCacheReadEnabled();
const cacheWrite = isCacheWriteEnabled();
if (cacheRead || cacheWrite) {
const cachePath = getCachePath();
const cachePath = getCachePath(undefined);
if (cacheRead && !existsSync(cachePath)) {
const mainCachePath = getCachePath(getDefaultBranch());
if (existsSync(mainCachePath)) {
@@ -98,12 +104,6 @@ async function build(args) {
}
}
const toolchain = generateOptions["--toolchain"];
if (toolchain) {
const toolchainPath = resolve(import.meta.dirname, "..", "cmake", "toolchains", `${toolchain}.cmake`);
generateOptions["--toolchain"] = toolchainPath;
}
const generateArgs = Object.entries(generateOptions).flatMap(([flag, value]) =>
flag.startsWith("-D") ? [`${flag}=${value}`] : [flag, value],
);
@@ -132,7 +132,7 @@ function cmakePath(path) {
return path.replace(/\\/g, "/");
}
function getCachePath(branch) {
function getCachePath(branch, toolchain) {
const buildPath = process.env.BUILDKITE_BUILD_PATH;
const repository = process.env.BUILDKITE_REPO;
const fork = process.env.BUILDKITE_PULL_REQUEST_REPO;

View File

@@ -16,8 +16,8 @@ import {
startGroup,
spawnSshSafe,
spawnSsh,
spawnScp,
tmpdir,
waitForPort,
which,
escapePowershell,
getGithubUrl,
@@ -33,7 +33,6 @@ import {
isWindows,
setupUserData,
sha256,
isPrivileged,
getUsernameForDistro,
} from "./utils.mjs";
import { basename, extname, join, relative, resolve } from "node:path";
@@ -908,74 +907,6 @@ async function getGithubOrgSshKeys(organization) {
return sshKeys.flat();
}
/**
* @typedef SshOptions
* @property {string} hostname
* @property {number} [port]
* @property {string} [username]
* @property {string} [password]
* @property {string[]} [command]
* @property {string[]} [identityPaths]
* @property {number} [retries]
*/
/**
* @typedef ScpOptions
* @property {string} hostname
* @property {string} source
* @property {string} destination
* @property {string[]} [identityPaths]
* @property {string} [port]
* @property {string} [username]
* @property {number} [retries]
*/
/**
* @param {ScpOptions} options
* @returns {Promise<void>}
*/
async function spawnScp(options) {
const { hostname, port, username, identityPaths, password, source, destination, retries = 10 } = options;
await waitForPort({ hostname, port: port || 22 });
const command = ["scp", "-o", "StrictHostKeyChecking=no"];
if (!password) {
command.push("-o", "BatchMode=yes");
}
if (port) {
command.push("-P", port);
}
if (password) {
const sshPass = which("sshpass", { required: true });
command.unshift(sshPass, "-p", password);
} else if (identityPaths) {
command.push(...identityPaths.flatMap(path => ["-i", path]));
}
command.push(resolve(source));
if (username) {
command.push(`${username}@${hostname}:${destination}`);
} else {
command.push(`${hostname}:${destination}`);
}
let cause;
for (let i = 0; i < retries; i++) {
const result = await spawn(command, { stdio: "inherit" });
const { exitCode, stderr } = result;
if (exitCode === 0) {
return;
}
cause = stderr.trim() || undefined;
if (/(bad configuration option)|(no such file or directory)/i.test(stderr)) {
break;
}
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
}
throw new Error(`SCP failed: ${source} -> ${username}@${hostname}:${destination}`, { cause });
}
/**
* @param {string} passwordData
* @param {string} privateKeyPath

View File

@@ -6,6 +6,7 @@ import { createHash } from "node:crypto";
import {
appendFileSync,
chmodSync,
chownSync,
copyFileSync,
existsSync,
mkdirSync,
@@ -936,6 +937,13 @@ export function readFile(filename, options = {}) {
return content;
}
/**
* @typedef {object} FileOptions
* @property {number} [mode]
* @property {number} [uid]
* @property {number} [gid]
*/
/**
* @param {string} path
* @param {number} mode
@@ -945,11 +953,20 @@ export function chmod(path, mode) {
chmodSync(path, mode);
}
/**
* @param {string} path
* @param {number | string} [uid]
* @param {number | string} [gid]
*/
export function chown(path, uid, gid) {
debugLog("$", "chown", path, uid, gid);
chownSync(path, uid, gid);
}
/**
* @param {string} filename
* @param {string | Buffer} content
* @param {object} [options]
* @param {number} [options.mode]
* @param {FileOptions} [options]
*/
export function writeFile(filename, content, options) {
mkdir(dirname(filename));
@@ -959,14 +976,15 @@ export function writeFile(filename, content, options) {
if (options?.mode) {
chmod(filename, options.mode);
} else if (options?.uid || options?.gid) {
chown(filename, options.uid, options.gid);
}
}
/**
* @param {string} source
* @param {string} destination
* @param {object} [options]
* @param {number} [options.mode]
* @param {FileOptions} [options]
*/
export function copyFile(source, destination, options) {
mkdir(dirname(destination));
@@ -976,21 +994,26 @@ export function copyFile(source, destination, options) {
if (options?.mode) {
chmod(destination, options.mode);
} else if (options?.uid || options?.gid) {
chown(destination, options.uid, options.gid);
}
}
/**
* @param {string} path
* @param {object} [options]
* @param {number} [options.mode]
* @param {FileOptions} [options]
*/
export function mkdir(path, options = {}) {
if (existsSync(path)) {
return;
if (!existsSync(path)) {
debugLog("$", "mkdir", path);
mkdirSync(path, { ...options, recursive: true });
}
debugLog("$", "mkdir", path);
mkdirSync(path, { ...options, recursive: true });
if (options?.mode) {
chmod(path, options.mode);
} else if (options?.uid || options?.gid) {
chown(path, options.uid, options.gid);
}
}
/**
@@ -1853,14 +1876,63 @@ export function getHostname() {
return hostname();
}
/**
* @returns {number}
*/
export function getUid() {
const originalUid = getEnv("SUDO_UID", false);
if (originalUid) {
return parseInt(originalUid);
}
const { uid } = userInfo();
return uid;
}
/**
* @returns {string}
*/
export function getUsername() {
const originalUsername = getEnv("SUDO_USER", false);
if (originalUsername) {
return originalUsername;
}
const { username } = userInfo();
return username;
}
/**
* @returns {number}
*/
export function getGid() {
const originalGid = getEnv("SUDO_GID", false);
if (originalGid) {
return parseInt(originalGid);
}
const { gid } = userInfo();
return gid;
}
/**
* @typedef {object} User
* @property {string} username
* @property {number} uid
* @property {number} gid
*/
/**
* @returns {User}
*/
export function getUser() {
return {
username: getUsername(),
uid: getUid(),
gid: getGid(),
};
}
/**
* @param {string} distro
* @returns {string}
@@ -1889,30 +1961,6 @@ export function getUsernameForDistro(distro) {
throw new Error(`Unsupported distro: ${distro}`);
}
/**
* @typedef {object} User
* @property {string} username
* @property {number} uid
* @property {number} gid
*/
/**
* @param {string} username
* @returns {Promise<User>}
*/
export async function getUser(username) {
if (isWindows) {
throw new Error("TODO: Windows");
}
const [uid, gid] = await Promise.all([
spawnSafe(["id", "-u", username]).then(({ stdout }) => parseInt(stdout.trim())),
spawnSafe(["id", "-g", username]).then(({ stdout }) => parseInt(stdout.trim())),
]);
return { username, uid, gid };
}
/**
* @returns {string | undefined}
*/
@@ -2026,19 +2074,19 @@ let detectedCloud;
/**
* @returns {Promise<boolean | undefined>}
*/
export async function isAws() {
export function isAws() {
if (typeof detectedCloud === "string") {
return detectedCloud === "aws";
}
async function checkAws() {
function checkAws() {
if (isLinux) {
const kernel = release();
if (kernel.endsWith("-aws")) {
return true;
}
const { error: systemdError, stdout } = await spawn(["systemd-detect-virt"]);
const { error: systemdError, stdout } = spawnSync(["systemd-detect-virt"]);
if (!systemdError) {
if (stdout.includes("amazon")) {
return true;
@@ -2047,7 +2095,7 @@ export async function isAws() {
const dmiPath = "/sys/devices/virtual/dmi/id/board_asset_tag";
if (existsSync(dmiPath)) {
const dmiFile = readFileSync(dmiPath, { encoding: "utf-8" });
const dmiFile = readFile(dmiPath);
if (dmiFile.startsWith("i-")) {
return true;
}
@@ -2060,7 +2108,7 @@ export async function isAws() {
return true;
}
const { error: powershellError, stdout } = await spawn([
const { error: powershellError, stdout } = spawnSync([
"powershell",
"-Command",
"Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object Manufacturer",
@@ -2071,7 +2119,7 @@ export async function isAws() {
}
}
if (await checkAws()) {
if (checkAws()) {
detectedCloud = "aws";
return true;
}
@@ -2080,12 +2128,12 @@ export async function isAws() {
/**
* @returns {Promise<boolean | undefined>}
*/
export async function isGoogleCloud() {
export function isGoogleCloud() {
if (typeof detectedCloud === "string") {
return detectedCloud === "google";
}
async function detectGoogleCloud() {
function detectGoogleCloud() {
if (isLinux) {
const vendorPaths = [
"/sys/class/dmi/id/sys_vendor",
@@ -2095,7 +2143,7 @@ export async function isGoogleCloud() {
for (const vendorPath of vendorPaths) {
if (existsSync(vendorPath)) {
const vendorFile = readFileSync(vendorPath, { encoding: "utf-8" });
const vendorFile = readFile(vendorPath);
if (vendorFile.includes("Google")) {
return true;
}
@@ -2104,25 +2152,25 @@ export async function isGoogleCloud() {
}
}
if (await detectGoogleCloud()) {
if (detectGoogleCloud()) {
detectedCloud = "google";
return true;
}
}
/**
* @returns {Promise<Cloud | undefined>}
* @returns {Cloud | undefined}
*/
export async function getCloud() {
export function getCloud() {
if (typeof detectedCloud === "string") {
return detectedCloud;
}
if (await isAws()) {
if (isAws()) {
return "aws";
}
if (await isGoogleCloud()) {
if (isGoogleCloud()) {
return "google";
}
}
@@ -2133,7 +2181,7 @@ export async function getCloud() {
* @returns {Promise<string | undefined>}
*/
export async function getCloudMetadata(name, cloud) {
cloud ??= await getCloud();
cloud ??= getCloud();
if (!cloud) {
return;
}
@@ -2802,10 +2850,21 @@ export function getBuildkiteEmoji(emoji) {
return name ? `:${name}:` : "";
}
/**
* @typedef SshOptions
* @property {string} hostname
* @property {number} [port]
* @property {string} [username]
* @property {string} [password]
* @property {string[]} [command]
* @property {string[]} [identityPaths]
* @property {number} [retries]
*/
/**
* @param {SshOptions} options
* @param {import("./utils.mjs").SpawnOptions} [spawnOptions]
* @returns {Promise<import("./utils.mjs").SpawnResult>}
* @param {SpawnOptions} [spawnOptions]
* @returns {Promise<SpawnResult>}
*/
export async function spawnSshSafe(options, spawnOptions = {}) {
return spawnSsh(options, { throwOnError: true, ...spawnOptions });
@@ -2813,8 +2872,8 @@ export async function spawnSshSafe(options, spawnOptions = {}) {
/**
* @param {SshOptions} options
* @param {import("./utils.mjs").SpawnOptions} [spawnOptions]
* @returns {Promise<import("./utils.mjs").SpawnResult>}
* @param {SpawnOptions} [spawnOptions]
* @returns {Promise<SpawnResult>}
*/
export async function spawnSsh(options, spawnOptions = {}) {
const { hostname, port, username, identityPaths, password, retries = 10, command: spawnCommand } = options;
@@ -2845,10 +2904,10 @@ export async function spawnSsh(options, spawnOptions = {}) {
}
const stdio = spawnCommand ? "pipe" : "inherit";
if (spawnCommand) {
command.push(...spawnCommand);
command.push(...spawnCommand.map(arg => (arg.includes(" ") ? JSON.stringify(arg) : arg)));
}
/** @type {import("./utils.mjs").SpawnResult} */
/** @type {SpawnResult} */
let result;
for (let i = 0; i < retries; i++) {
result = await spawn(command, { stdio, ...spawnOptions, throwOnError: undefined });
@@ -2876,6 +2935,63 @@ export async function spawnSsh(options, spawnOptions = {}) {
return result;
}
/**
* @typedef ScpOptions
* @property {string} hostname
* @property {string} source
* @property {string} destination
* @property {string[]} [identityPaths]
* @property {string} [port]
* @property {string} [username]
* @property {number} [retries]
*/
/**
* @param {ScpOptions} options
* @returns {Promise<void>}
*/
export async function spawnScp(options) {
const { hostname, port, username, identityPaths, password, source, destination, retries = 10 } = options;
await waitForPort({ hostname, port: port || 22 });
const command = ["scp", "-o", "StrictHostKeyChecking=no"];
if (!password) {
command.push("-o", "BatchMode=yes");
}
if (port) {
command.push("-P", port);
}
if (password) {
const sshPass = which("sshpass", { required: true });
command.unshift(sshPass, "-p", password);
} else if (identityPaths) {
command.push(...identityPaths.flatMap(path => ["-i", path]));
}
command.push(resolve(source));
if (username) {
command.push(`${username}@${hostname}:${destination}`);
} else {
command.push(`${hostname}:${destination}`);
}
let cause;
for (let i = 0; i < retries; i++) {
const result = await spawn(command, { stdio: "inherit" });
const { exitCode, stderr } = result;
if (exitCode === 0) {
return;
}
cause = stderr.trim() || undefined;
if (/(bad configuration option)|(no such file or directory)/i.test(stderr)) {
break;
}
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
}
throw new Error(`SCP failed: ${source} -> ${username}@${hostname}:${destination}`, { cause });
}
/**
* @param {MachineOptions} options
* @returns {Promise<Machine>}

View File

@@ -135,9 +135,9 @@ extern "C" void Process__emitErrorEvent(Zig::GlobalObject* global, EncodedJSValu
static JSValue constructArch(VM& vm, JSObject* processObject)
{
#if CPU(X86_64)
#if defined(__x86_64__)
return JSC::jsString(vm, makeAtomString("x64"_s));
#elif CPU(ARM64)
#elif defined(__aarch64__)
return JSC::jsString(vm, makeAtomString("arm64"_s));
#else
#error "Unknown architecture"

View File

@@ -17,7 +17,7 @@ enum class AArch64CPUFeature : uint8_t {
sve = 6,
};
#if CPU(X86_64)
#if defined(__x86_64__)
#if OS(WINDOWS)
@@ -66,7 +66,7 @@ static uint8_t x86_cpu_features()
#endif
#if CPU(ARM64)
#if defined(__aarch64__)
static uint8_t aarch64_cpu_features()
{
@@ -100,9 +100,9 @@ static uint8_t aarch64_cpu_features()
extern "C" uint8_t bun_cpu_features()
{
#if CPU(X86_64)
#if defined(__x86_64__)
return x86_cpu_features();
#elif CPU(ARM64)
#elif defined(__aarch64__)
return aarch64_cpu_features();
#else
return 0;

View File

@@ -22,7 +22,7 @@
#endif // !OS(WINDOWS)
#include <lshpack.h>
#if CPU(X86_64) && !OS(WINDOWS)
#if defined(__x86_64__) && !OS(WINDOWS)
extern "C" void bun_warn_avx_missing(const char* url)
{
__builtin_cpu_init();