mirror of
https://github.com/oven-sh/bun
synced 2026-02-12 03:48:56 +00:00
Refactor Linux SFX to native zero-dependency executables
This commit is contained in:
109
.github/workflows/release.yml
vendored
109
.github/workflows/release.yml
vendored
@@ -331,115 +331,6 @@ jobs:
|
||||
AWS_ENDPOINT: ${{ secrets.AWS_ENDPOINT }}
|
||||
AWS_BUCKET: bun
|
||||
|
||||
macos-sfx:
|
||||
name: Generate macOS SFX Archives
|
||||
runs-on: macos-latest
|
||||
needs: sign
|
||||
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.use-sfx == 'true') }}
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: aarch64
|
||||
display: arm64
|
||||
- arch: x64
|
||||
display: x64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Environment
|
||||
run: |
|
||||
echo "Creating working directory..."
|
||||
mkdir -p sfx-build
|
||||
- name: Download Bun Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Download the zip file from GitHub releases
|
||||
echo "Downloading bun-darwin-${{ matrix.arch }}.zip..."
|
||||
|
||||
if [[ "${{ env.BUN_VERSION }}" == "canary" ]]; then
|
||||
DOWNLOAD_URL="https://github.com/oven-sh/bun/releases/download/canary/bun-darwin-${{ matrix.arch }}.zip"
|
||||
else
|
||||
DOWNLOAD_URL="https://github.com/oven-sh/bun/releases/download/${{ env.BUN_VERSION }}/bun-darwin-${{ matrix.arch }}.zip"
|
||||
fi
|
||||
|
||||
curl -L -o "bun-darwin-${{ matrix.arch }}.zip" "$DOWNLOAD_URL"
|
||||
|
||||
# Extract the zip file
|
||||
unzip -q "bun-darwin-${{ matrix.arch }}.zip"
|
||||
|
||||
# Find the bun executable
|
||||
BUN_EXEC=$(find . -name "bun" -type f | head -n 1)
|
||||
if [[ -z "$BUN_EXEC" ]]; then
|
||||
echo "Error: Could not find bun executable in the archive"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Move it to a known location
|
||||
mv "$BUN_EXEC" "./bun"
|
||||
chmod +x ./bun
|
||||
|
||||
# Clean up
|
||||
rm -rf bun-darwin-${{ matrix.arch }}
|
||||
- name: Create Self-Extracting Archive
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Create the self-extracting script header
|
||||
cat > extract-header.sh << 'SCRIPT_EOF'
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
DEFAULT_INSTALL_DIR="$HOME/.bun/bin"
|
||||
INSTALL_DIR="${BUN_INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"
|
||||
ARCH="$(uname -m)"
|
||||
EXPECTED_ARCH="ARCH_PLACEHOLDER"
|
||||
if [[ "$ARCH" == "x86_64" ]]; then
|
||||
ARCH="x64"
|
||||
elif [[ "$ARCH" == "arm64" ]]; then
|
||||
ARCH="arm64"
|
||||
fi
|
||||
if [[ "$ARCH" != "$EXPECTED_ARCH" ]]; then
|
||||
echo "Warning: This installer is for $EXPECTED_ARCH but you're running on $ARCH"
|
||||
fi
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
PAYLOAD_LINE=$(awk '/^__PAYLOAD_BEGINS__/ { print NR + 1; exit 0; }' "$0")
|
||||
echo "Extracting Bun to $INSTALL_DIR..."
|
||||
tail -n +"$PAYLOAD_LINE" "$0" | base64 -D | tar -xzf - -C "$INSTALL_DIR"
|
||||
chmod +x "$INSTALL_DIR/bun"
|
||||
echo "Bun has been installed to $INSTALL_DIR/bun"
|
||||
echo "Run 'export PATH=\"\$PATH:$INSTALL_DIR\"' to add it to your PATH"
|
||||
exit 0
|
||||
__PAYLOAD_BEGINS__
|
||||
SCRIPT_EOF
|
||||
|
||||
# Replace the architecture placeholder
|
||||
sed -i '' "s/ARCH_PLACEHOLDER/${{ matrix.display }}/g" extract-header.sh
|
||||
|
||||
# Create the SFX archive
|
||||
tar -czf bun.tar.gz bun
|
||||
base64 < bun.tar.gz > bun.tar.gz.b64
|
||||
cat extract-header.sh bun.tar.gz.b64 > "bun-darwin-${{ matrix.arch }}-sfx.sh"
|
||||
chmod +x "bun-darwin-${{ matrix.arch }}-sfx.sh"
|
||||
|
||||
# Generate checksum
|
||||
shasum -a 256 "bun-darwin-${{ matrix.arch }}-sfx.sh" > "bun-darwin-${{ matrix.arch }}-sfx.sh.sha256"
|
||||
- name: Upload to Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Upload the SFX to the release
|
||||
gh release upload "${{ env.BUN_VERSION }}" \
|
||||
"bun-darwin-${{ matrix.arch }}-sfx.sh" \
|
||||
"bun-darwin-${{ matrix.arch }}-sfx.sh.sha256" \
|
||||
--clobber \
|
||||
--repo "${{ github.repository }}"
|
||||
|
||||
linux-sfx:
|
||||
name: Generate Linux SFX Archives
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
498
.github/workflows/sfx-linux.yml
vendored
498
.github/workflows/sfx-linux.yml
vendored
@@ -32,20 +32,47 @@ jobs:
|
||||
- arch: x64
|
||||
zip_name: bun-linux-x64
|
||||
display: x64
|
||||
gcc_arch: x86-64
|
||||
- arch: x64
|
||||
zip_name: bun-linux-x64-baseline
|
||||
display: x64-baseline
|
||||
baseline: true
|
||||
gcc_arch: x86-64
|
||||
- arch: aarch64
|
||||
zip_name: bun-linux-aarch64
|
||||
display: aarch64
|
||||
gcc_arch: aarch64
|
||||
- arch: x64
|
||||
zip_name: bun-linux-x64-musl
|
||||
display: x64-musl
|
||||
musl: true
|
||||
gcc_arch: x86-64
|
||||
- arch: x64
|
||||
zip_name: bun-linux-x64-musl-baseline
|
||||
display: x64-musl-baseline
|
||||
baseline: true
|
||||
musl: true
|
||||
gcc_arch: x86-64
|
||||
- arch: aarch64
|
||||
zip_name: bun-linux-aarch64-musl
|
||||
display: aarch64-musl
|
||||
musl: true
|
||||
gcc_arch: aarch64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Environment
|
||||
- name: Setup Build Environment
|
||||
run: |
|
||||
echo "Creating working directory..."
|
||||
echo "Installing build dependencies..."
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc make xxd upx-ucl
|
||||
|
||||
# Install cross-compilation toolchain for aarch64
|
||||
if [[ "${{ matrix.arch }}" == "aarch64" ]]; then
|
||||
sudo apt-get install -y gcc-aarch64-linux-gnu
|
||||
fi
|
||||
|
||||
mkdir -p sfx-build
|
||||
cd sfx-build
|
||||
|
||||
@@ -55,7 +82,6 @@ jobs:
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Download the zip file from GitHub releases
|
||||
echo "Downloading ${{ matrix.zip_name }}.zip..."
|
||||
|
||||
if [[ "${{ env.BUN_VERSION }}" == "canary" ]]; then
|
||||
@@ -66,7 +92,7 @@ jobs:
|
||||
|
||||
curl -L -o "${{ matrix.zip_name }}.zip" "$DOWNLOAD_URL"
|
||||
|
||||
# Extract the zip file using unzip (available on GitHub runners)
|
||||
# Extract the zip file
|
||||
unzip -q "${{ matrix.zip_name }}.zip"
|
||||
|
||||
# Find the bun executable
|
||||
@@ -80,189 +106,292 @@ jobs:
|
||||
mv "$BUN_EXEC" "./bun"
|
||||
chmod +x ./bun
|
||||
|
||||
# Compress the binary
|
||||
echo "Compressing bun binary..."
|
||||
gzip -9 -k ./bun
|
||||
|
||||
# Clean up
|
||||
rm -rf bun-linux-*/ ${{ matrix.zip_name }}.zip
|
||||
|
||||
- name: Create SFX Script
|
||||
- name: Create SFX Source Code
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Create the self-extracting script
|
||||
cat > extract-header.sh << 'SCRIPT_EOF'
|
||||
#!/bin/sh
|
||||
# Bun Self-Extracting Archive for Linux
|
||||
# This is a self-extracting archive. Run it to install Bun.
|
||||
# No external dependencies required (no unzip needed!)
|
||||
# Create the self-extracting executable source
|
||||
cat > sfx.c << 'EOF'
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <zlib.h>
|
||||
|
||||
set -e
|
||||
// Terminal colors
|
||||
#define COLOR_RED "\033[0;31m"
|
||||
#define COLOR_GREEN "\033[0;32m"
|
||||
#define COLOR_YELLOW "\033[1;33m"
|
||||
#define COLOR_RESET "\033[0m"
|
||||
|
||||
# Default installation directory
|
||||
DEFAULT_INSTALL_DIR="$HOME/.bun/bin"
|
||||
INSTALL_DIR="${BUN_INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"
|
||||
// Embedded compressed binary data
|
||||
static const unsigned char compressed_data[] = {
|
||||
#include "bun_data.h"
|
||||
};
|
||||
static const size_t compressed_size = sizeof(compressed_data);
|
||||
|
||||
# ANSI color codes (only if terminal supports it)
|
||||
if [ -t 1 ] && [ -n "${TERM-}" ] && [ "${TERM-}" != "dumb" ]; then
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
else
|
||||
RED=''
|
||||
GREEN=''
|
||||
YELLOW=''
|
||||
NC=''
|
||||
fi
|
||||
// Installation configuration
|
||||
#ifndef DEFAULT_INSTALL_DIR
|
||||
#define DEFAULT_INSTALL_DIR "/.bun/bin"
|
||||
#endif
|
||||
|
||||
error() {
|
||||
printf "${RED}error: %s${NC}\n" "$1" >&2
|
||||
exit 1
|
||||
#ifndef BUN_ARCH
|
||||
#define BUN_ARCH "unknown"
|
||||
#endif
|
||||
|
||||
void print_error(const char* msg) {
|
||||
if (isatty(STDERR_FILENO)) {
|
||||
fprintf(stderr, COLOR_RED "error: " COLOR_RESET "%s\n", msg);
|
||||
} else {
|
||||
fprintf(stderr, "error: %s\n", msg);
|
||||
}
|
||||
}
|
||||
|
||||
info() {
|
||||
printf "${GREEN}%s${NC}\n" "$1"
|
||||
void print_success(const char* msg) {
|
||||
if (isatty(STDOUT_FILENO)) {
|
||||
printf(COLOR_GREEN "%s" COLOR_RESET "\n", msg);
|
||||
} else {
|
||||
printf("%s\n", msg);
|
||||
}
|
||||
}
|
||||
|
||||
warn() {
|
||||
printf "${YELLOW}warning: %s${NC}\n" "$1"
|
||||
void print_info(const char* msg) {
|
||||
printf("%s\n", msg);
|
||||
}
|
||||
|
||||
# Check if running on Linux
|
||||
if [ "$(uname -s)" != "Linux" ]; then
|
||||
error "This installer is for Linux only. Please download the correct version for your platform."
|
||||
fi
|
||||
int ensure_directory(const char* path) {
|
||||
struct stat st = {0};
|
||||
if (stat(path, &st) == -1) {
|
||||
if (mkdir(path, 0755) == -1 && errno != EEXIST) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Check architecture
|
||||
ARCH="$(uname -m)"
|
||||
EXPECTED_ARCH="ARCH_PLACEHOLDER"
|
||||
EXPECTED_DISPLAY="DISPLAY_PLACEHOLDER"
|
||||
int create_directory_tree(const char* path) {
|
||||
char tmp[1024];
|
||||
char *p = NULL;
|
||||
size_t len;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%s", path);
|
||||
len = strlen(tmp);
|
||||
if (tmp[len - 1] == '/')
|
||||
tmp[len - 1] = 0;
|
||||
|
||||
for (p = tmp + 1; *p; p++) {
|
||||
if (*p == '/') {
|
||||
*p = 0;
|
||||
if (ensure_directory(tmp) == -1) {
|
||||
return -1;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
|
||||
if (ensure_directory(tmp) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case "$ARCH" in
|
||||
x86_64)
|
||||
ARCH_NORM="x64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
ARCH_NORM="aarch64"
|
||||
;;
|
||||
*)
|
||||
ARCH_NORM="$ARCH"
|
||||
;;
|
||||
esac
|
||||
int decompress_to_file(const char* output_path) {
|
||||
FILE* outfile = fopen(output_path, "wb");
|
||||
if (!outfile) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Decompress using zlib
|
||||
z_stream stream = {0};
|
||||
stream.next_in = (Bytef*)compressed_data;
|
||||
stream.avail_in = compressed_size;
|
||||
|
||||
if (inflateInit2(&stream, 16 + MAX_WBITS) != Z_OK) {
|
||||
fclose(outfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char buffer[8192];
|
||||
int ret;
|
||||
|
||||
do {
|
||||
stream.next_out = buffer;
|
||||
stream.avail_out = sizeof(buffer);
|
||||
|
||||
ret = inflate(&stream, Z_NO_FLUSH);
|
||||
if (ret == Z_STREAM_ERROR) {
|
||||
inflateEnd(&stream);
|
||||
fclose(outfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t have = sizeof(buffer) - stream.avail_out;
|
||||
if (fwrite(buffer, 1, have, outfile) != have) {
|
||||
inflateEnd(&stream);
|
||||
fclose(outfile);
|
||||
return -1;
|
||||
}
|
||||
} while (ret != Z_STREAM_END);
|
||||
|
||||
inflateEnd(&stream);
|
||||
fclose(outfile);
|
||||
|
||||
// Make executable
|
||||
if (chmod(output_path, 0755) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Check if architecture matches (allow x64 baseline on x64)
|
||||
ARCH_MISMATCH=0
|
||||
case "$EXPECTED_ARCH" in
|
||||
x64)
|
||||
if [ "$ARCH_NORM" != "x64" ]; then
|
||||
ARCH_MISMATCH=1
|
||||
fi
|
||||
;;
|
||||
aarch64)
|
||||
if [ "$ARCH_NORM" != "aarch64" ]; then
|
||||
ARCH_MISMATCH=1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
int main(int argc, char* argv[]) {
|
||||
printf("Bun Self-Extracting Archive for Linux %s\n", BUN_ARCH);
|
||||
printf("=====================================\n\n");
|
||||
|
||||
// Determine installation directory
|
||||
const char* install_dir_env = getenv("BUN_INSTALL_DIR");
|
||||
char install_dir[1024];
|
||||
|
||||
if (install_dir_env && install_dir_env[0] != '\0') {
|
||||
snprintf(install_dir, sizeof(install_dir), "%s", install_dir_env);
|
||||
} else {
|
||||
const char* home = getenv("HOME");
|
||||
if (!home) {
|
||||
print_error("Could not determine home directory");
|
||||
return 1;
|
||||
}
|
||||
snprintf(install_dir, sizeof(install_dir), "%s%s", home, DEFAULT_INSTALL_DIR);
|
||||
}
|
||||
|
||||
printf("Installation directory: %s\n", install_dir);
|
||||
|
||||
// Create installation directory
|
||||
if (create_directory_tree(install_dir) == -1) {
|
||||
char error_msg[1024];
|
||||
snprintf(error_msg, sizeof(error_msg), "Failed to create directory: %s", install_dir);
|
||||
print_error(error_msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Extract bun executable
|
||||
char bun_path[1024];
|
||||
snprintf(bun_path, sizeof(bun_path), "%s/bun", install_dir);
|
||||
|
||||
printf("Extracting bun...\n");
|
||||
if (decompress_to_file(bun_path) == -1) {
|
||||
print_error("Failed to extract bun executable");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Verify installation
|
||||
char version_cmd[1024];
|
||||
snprintf(version_cmd, sizeof(version_cmd), "%s --version 2>/dev/null", bun_path);
|
||||
FILE* fp = popen(version_cmd, "r");
|
||||
if (fp) {
|
||||
char version[128];
|
||||
if (fgets(version, sizeof(version), fp) != NULL) {
|
||||
// Remove newline
|
||||
size_t len = strlen(version);
|
||||
if (len > 0 && version[len-1] == '\n') {
|
||||
version[len-1] = '\0';
|
||||
}
|
||||
char success_msg[256];
|
||||
snprintf(success_msg, sizeof(success_msg), "✓ Bun %s has been installed to %s", version, bun_path);
|
||||
print_success(success_msg);
|
||||
}
|
||||
pclose(fp);
|
||||
}
|
||||
|
||||
// Check if in PATH
|
||||
const char* path_env = getenv("PATH");
|
||||
if (path_env && !strstr(path_env, install_dir)) {
|
||||
printf("\n");
|
||||
print_info("To get started, add Bun to your PATH:");
|
||||
printf(" export PATH=\"$PATH:%s\"\n", install_dir);
|
||||
printf("\n");
|
||||
print_info("To make this permanent, add it to your shell configuration file:");
|
||||
|
||||
const char* shell = getenv("SHELL");
|
||||
if (shell) {
|
||||
if (strstr(shell, "bash")) {
|
||||
printf(" echo 'export PATH=\"$PATH:%s\"' >> ~/.bashrc\n", install_dir);
|
||||
} else if (strstr(shell, "zsh")) {
|
||||
printf(" echo 'export PATH=\"$PATH:%s\"' >> ~/.zshrc\n", install_dir);
|
||||
} else if (strstr(shell, "fish")) {
|
||||
printf(" echo 'set -gx PATH $PATH %s' >> ~/.config/fish/config.fish\n", install_dir);
|
||||
} else {
|
||||
printf(" echo 'export PATH=\"$PATH:%s\"' >> ~/.profile\n", install_dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
if [ "$ARCH_MISMATCH" = "1" ]; then
|
||||
warn "This installer is for $EXPECTED_DISPLAY but you're running on $ARCH"
|
||||
if [ -t 0 ]; then
|
||||
printf "Continue anyway? [y/N] "
|
||||
read -r REPLY
|
||||
case "$REPLY" in
|
||||
[Yy]*)
|
||||
;;
|
||||
*)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
error "Architecture mismatch and no TTY to confirm"
|
||||
fi
|
||||
fi
|
||||
# Convert the compressed binary to a C header file
|
||||
echo "Converting binary to C array..."
|
||||
xxd -i bun.gz | sed 's/unsigned char bun_gz\[\]//' | sed 's/unsigned int bun_gz_len = .*//' > bun_data.h
|
||||
|
||||
# Create installation directory
|
||||
mkdir -p "$INSTALL_DIR" || error "Failed to create installation directory: $INSTALL_DIR"
|
||||
|
||||
# Find where the payload starts
|
||||
ARCHIVE_MARKER="__ARCHIVE_BELOW__"
|
||||
ARCHIVE_LINE=$(awk "/$ARCHIVE_MARKER/ { print NR + 1; exit }" "$0")
|
||||
|
||||
if [ -z "$ARCHIVE_LINE" ]; then
|
||||
error "Could not find archive marker"
|
||||
fi
|
||||
|
||||
# Extract the payload
|
||||
info "Extracting Bun to $INSTALL_DIR..."
|
||||
|
||||
# Use tail to skip the script part, then decode and extract
|
||||
# We use base64 to ensure binary safety across all systems
|
||||
if ! tail -n +"$ARCHIVE_LINE" "$0" | base64 -d | tar -xzf - -C "$INSTALL_DIR" 2>/dev/null; then
|
||||
error "Failed to extract Bun. The archive may be corrupted."
|
||||
fi
|
||||
|
||||
# Make it executable
|
||||
chmod +x "$INSTALL_DIR/bun" || error "Failed to make bun executable"
|
||||
|
||||
# Verify installation
|
||||
if [ -x "$INSTALL_DIR/bun" ]; then
|
||||
BUN_VERSION=$("$INSTALL_DIR/bun" --version 2>/dev/null || echo "unknown")
|
||||
info "✓ Bun $BUN_VERSION has been installed to $INSTALL_DIR/bun"
|
||||
else
|
||||
error "Installation verification failed"
|
||||
fi
|
||||
|
||||
# Check if bun is in PATH
|
||||
if ! echo "$PATH" | grep -q "$INSTALL_DIR"; then
|
||||
info ""
|
||||
info "To get started, add Bun to your PATH:"
|
||||
info " export PATH=\"\$PATH:$INSTALL_DIR\""
|
||||
info ""
|
||||
info "To make this permanent, add it to your shell configuration file:"
|
||||
case "${SHELL##*/}" in
|
||||
bash)
|
||||
info " echo 'export PATH=\"\$PATH:$INSTALL_DIR\"' >> ~/.bashrc"
|
||||
;;
|
||||
zsh)
|
||||
info " echo 'export PATH=\"\$PATH:$INSTALL_DIR\"' >> ~/.zshrc"
|
||||
;;
|
||||
fish)
|
||||
info " echo 'set -gx PATH \$PATH $INSTALL_DIR' >> ~/.config/fish/config.fish"
|
||||
;;
|
||||
*)
|
||||
info " echo 'export PATH=\"\$PATH:$INSTALL_DIR\"' >> ~/.profile"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
exit 0
|
||||
# DO NOT REMOVE THE FOLLOWING LINE
|
||||
__ARCHIVE_BELOW__
|
||||
SCRIPT_EOF
|
||||
|
||||
# Replace placeholders
|
||||
sed -i "s/ARCH_PLACEHOLDER/${{ matrix.arch }}/g" extract-header.sh
|
||||
sed -i "s/DISPLAY_PLACEHOLDER/${{ matrix.display }}/g" extract-header.sh
|
||||
|
||||
- name: Create Self-Extracting Archive
|
||||
- name: Build Self-Extracting Executable
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Create a tar.gz of the bun executable
|
||||
tar -czf bun.tar.gz bun
|
||||
# Select compiler based on architecture and libc
|
||||
if [[ "${{ matrix.musl }}" == "true" ]]; then
|
||||
# For musl builds, we need musl-gcc
|
||||
sudo apt-get install -y musl-tools
|
||||
if [[ "${{ matrix.arch }}" == "aarch64" ]]; then
|
||||
# Cross-compile for aarch64 musl - this is more complex
|
||||
# For now, skip cross-compilation for musl
|
||||
echo "Warning: Cross-compilation for aarch64-musl not yet supported"
|
||||
exit 0
|
||||
else
|
||||
CC=musl-gcc
|
||||
fi
|
||||
elif [[ "${{ matrix.arch }}" == "aarch64" ]]; then
|
||||
CC=aarch64-linux-gnu-gcc
|
||||
else
|
||||
CC=gcc
|
||||
fi
|
||||
|
||||
# Encode it as base64 (for binary safety)
|
||||
base64 < bun.tar.gz > bun.tar.gz.b64
|
||||
# Compile the self-extracting executable
|
||||
echo "Building self-extracting executable..."
|
||||
$CC -static -O3 -s \
|
||||
-DBUN_ARCH="\"${{ matrix.display }}\"" \
|
||||
sfx.c -o "${{ matrix.zip_name }}" \
|
||||
-lz
|
||||
|
||||
# Combine header and payload
|
||||
cat extract-header.sh bun.tar.gz.b64 > "${{ matrix.zip_name }}-sfx.sh"
|
||||
# Compress the executable with UPX for smaller size
|
||||
echo "Compressing executable with UPX..."
|
||||
upx --best --lzma "${{ matrix.zip_name }}" || true
|
||||
|
||||
# Make it executable
|
||||
chmod +x "${{ matrix.zip_name }}-sfx.sh"
|
||||
chmod +x "${{ matrix.zip_name }}"
|
||||
|
||||
# Show final size
|
||||
echo "Final executable size:"
|
||||
ls -lh "${{ matrix.zip_name }}"
|
||||
|
||||
- name: Test Self-Extracting Archive
|
||||
if: ${{ matrix.arch != 'aarch64' && matrix.musl != 'true' }} # Can't test aarch64 or musl on x64 runner
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Test the SFX
|
||||
echo "Testing self-extraction..."
|
||||
TEST_DIR="$(mktemp -d)"
|
||||
BUN_INSTALL_DIR="$TEST_DIR" ./${{ matrix.zip_name }}-sfx.sh
|
||||
BUN_INSTALL_DIR="$TEST_DIR" ./${{ matrix.zip_name }}
|
||||
|
||||
if [ -x "$TEST_DIR/bun" ]; then
|
||||
echo "✓ Self-extraction test passed"
|
||||
@@ -273,64 +402,23 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Create Quick Install Script
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Also create a simple download-and-run script
|
||||
cat > "${{ matrix.zip_name }}-install.sh" << 'INSTALLER_EOF'
|
||||
#!/bin/sh
|
||||
# Quick installer script for Bun on Linux
|
||||
|
||||
set -e
|
||||
|
||||
VERSION="VERSION_PLACEHOLDER"
|
||||
ARCHIVE_NAME="ARCHIVE_PLACEHOLDER"
|
||||
|
||||
echo "Downloading Bun $VERSION for Linux..."
|
||||
|
||||
if [ "$VERSION" = "canary" ]; then
|
||||
URL="https://github.com/oven-sh/bun/releases/download/canary/${ARCHIVE_NAME}-sfx.sh"
|
||||
else
|
||||
URL="https://github.com/oven-sh/bun/releases/download/$VERSION/${ARCHIVE_NAME}-sfx.sh"
|
||||
fi
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$URL" | sh
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO- "$URL" | sh
|
||||
else
|
||||
echo "Error: Neither curl nor wget found. Please install one of them."
|
||||
exit 1
|
||||
fi
|
||||
INSTALLER_EOF
|
||||
|
||||
# Replace placeholders
|
||||
sed -i "s/VERSION_PLACEHOLDER/${{ env.BUN_VERSION }}/g" "${{ matrix.zip_name }}-install.sh"
|
||||
sed -i "s/ARCHIVE_PLACEHOLDER/${{ matrix.zip_name }}/g" "${{ matrix.zip_name }}-install.sh"
|
||||
|
||||
chmod +x "${{ matrix.zip_name }}-install.sh"
|
||||
|
||||
- name: Generate Checksums
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Generate SHA256 checksums
|
||||
sha256sum "${{ matrix.zip_name }}-sfx.sh" > "${{ matrix.zip_name }}-sfx.sh.sha256"
|
||||
sha256sum "${{ matrix.zip_name }}-install.sh" > "${{ matrix.zip_name }}-install.sh.sha256"
|
||||
sha256sum "${{ matrix.zip_name }}" > "${{ matrix.zip_name }}.sha256"
|
||||
|
||||
echo "Generated files:"
|
||||
ls -la *.sh *.sha256
|
||||
ls -la ${{ matrix.zip_name }}*
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.zip_name }}-sfx
|
||||
path: |
|
||||
sfx-build/${{ matrix.zip_name }}-sfx.sh
|
||||
sfx-build/${{ matrix.zip_name }}-sfx.sh.sha256
|
||||
sfx-build/${{ matrix.zip_name }}-install.sh
|
||||
sfx-build/${{ matrix.zip_name }}-install.sh.sha256
|
||||
sfx-build/${{ matrix.zip_name }}
|
||||
sfx-build/${{ matrix.zip_name }}.sha256
|
||||
|
||||
- name: Upload to Release
|
||||
if: ${{ (github.event_name == 'release' || github.event.inputs.upload-to-release == 'true') && env.BUN_VERSION != 'canary' }}
|
||||
@@ -339,12 +427,10 @@ jobs:
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Upload the SFX and installer scripts to the release
|
||||
# Upload the SFX to the release
|
||||
gh release upload "${{ env.BUN_VERSION }}" \
|
||||
"${{ matrix.zip_name }}-sfx.sh" \
|
||||
"${{ matrix.zip_name }}-sfx.sh.sha256" \
|
||||
"${{ matrix.zip_name }}-install.sh" \
|
||||
"${{ matrix.zip_name }}-install.sh.sha256" \
|
||||
"${{ matrix.zip_name }}" \
|
||||
"${{ matrix.zip_name }}.sha256" \
|
||||
--clobber \
|
||||
--repo "${{ github.repository }}"
|
||||
|
||||
|
||||
379
.github/workflows/sfx-macos.yml
vendored
379
.github/workflows/sfx-macos.yml
vendored
@@ -1,379 +0,0 @@
|
||||
name: Generate macOS SFX Archives
|
||||
concurrency: sfx-macos
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag (e.g., "bun-v1.0.2", "canary")'
|
||||
required: true
|
||||
default: "canary"
|
||||
upload-to-release:
|
||||
description: "Upload SFX files to the release?"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
env:
|
||||
BUN_VERSION: ${{ github.event.inputs.tag || github.event.release.tag_name || 'canary' }}
|
||||
|
||||
jobs:
|
||||
create-macos-sfx:
|
||||
name: Create macOS Self-Extracting Archives
|
||||
runs-on: macos-latest
|
||||
if: ${{ github.repository_owner == 'oven-sh' }}
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: aarch64
|
||||
display: arm64
|
||||
- arch: x64
|
||||
display: x64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Environment
|
||||
run: |
|
||||
echo "Creating working directory..."
|
||||
mkdir -p sfx-build
|
||||
cd sfx-build
|
||||
|
||||
- name: Download Bun Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Download the zip file from GitHub releases
|
||||
echo "Downloading bun-darwin-${{ matrix.arch }}.zip..."
|
||||
|
||||
if [[ "${{ env.BUN_VERSION }}" == "canary" ]]; then
|
||||
DOWNLOAD_URL="https://github.com/oven-sh/bun/releases/download/canary/bun-darwin-${{ matrix.arch }}.zip"
|
||||
else
|
||||
DOWNLOAD_URL="https://github.com/oven-sh/bun/releases/download/${{ env.BUN_VERSION }}/bun-darwin-${{ matrix.arch }}.zip"
|
||||
fi
|
||||
|
||||
curl -L -o "bun-darwin-${{ matrix.arch }}.zip" "$DOWNLOAD_URL"
|
||||
|
||||
# Extract the zip file
|
||||
unzip -q "bun-darwin-${{ matrix.arch }}.zip"
|
||||
|
||||
# Find the bun executable
|
||||
BUN_EXEC=$(find . -name "bun" -type f | head -n 1)
|
||||
if [[ -z "$BUN_EXEC" ]]; then
|
||||
echo "Error: Could not find bun executable in the archive"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Move it to a known location
|
||||
mv "$BUN_EXEC" "./bun"
|
||||
chmod +x ./bun
|
||||
|
||||
# Clean up
|
||||
rm -rf bun-darwin-${{ matrix.arch }}
|
||||
|
||||
- name: Create SFX Script
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Create the self-extracting script
|
||||
cat > extract-header.sh << 'SCRIPT_EOF'
|
||||
#!/bin/bash
|
||||
# Bun Self-Extracting Archive for macOS
|
||||
# This is a self-extracting archive. Run it to install Bun.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Default installation directory
|
||||
DEFAULT_INSTALL_DIR="$HOME/.bun/bin"
|
||||
INSTALL_DIR="${BUN_INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Detect if stdout is a terminal
|
||||
if [[ -t 1 ]]; then
|
||||
INTERACTIVE=1
|
||||
else
|
||||
INTERACTIVE=0
|
||||
fi
|
||||
|
||||
print_color() {
|
||||
if [[ $INTERACTIVE -eq 1 ]]; then
|
||||
printf "%b%s%b\n" "$1" "$2" "$NC"
|
||||
else
|
||||
echo "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
error() {
|
||||
print_color "$RED" "error: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
info() {
|
||||
print_color "$GREEN" "$1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
print_color "$YELLOW" "warning: $1"
|
||||
}
|
||||
|
||||
# Check if running on macOS
|
||||
if [[ "$(uname -s)" != "Darwin" ]]; then
|
||||
error "This installer is for macOS only. Please download the correct version for your platform."
|
||||
fi
|
||||
|
||||
# Check architecture
|
||||
ARCH="$(uname -m)"
|
||||
EXPECTED_ARCH="ARCH_PLACEHOLDER"
|
||||
|
||||
if [[ "$ARCH" == "x86_64" ]]; then
|
||||
ARCH="x64"
|
||||
elif [[ "$ARCH" == "arm64" ]]; then
|
||||
ARCH="arm64"
|
||||
fi
|
||||
|
||||
if [[ "$ARCH" != "$EXPECTED_ARCH" ]]; then
|
||||
warn "This installer is for $EXPECTED_ARCH but you're running on $ARCH"
|
||||
if [[ $INTERACTIVE -eq 1 ]]; then
|
||||
read -p "Continue anyway? [y/N] " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create installation directory
|
||||
mkdir -p "$INSTALL_DIR" || error "Failed to create installation directory: $INSTALL_DIR"
|
||||
|
||||
# Find the payload offset
|
||||
PAYLOAD_LINE=$(awk '/^__PAYLOAD_BEGINS__/ { print NR + 1; exit 0; }' "$0")
|
||||
if [[ -z "$PAYLOAD_LINE" ]]; then
|
||||
error "Could not find payload marker"
|
||||
fi
|
||||
|
||||
# Extract and decompress the payload
|
||||
info "Extracting Bun to $INSTALL_DIR..."
|
||||
tail -n +"$PAYLOAD_LINE" "$0" | base64 -D | tar -xzf - -C "$INSTALL_DIR" || error "Failed to extract Bun"
|
||||
|
||||
# Make it executable
|
||||
chmod +x "$INSTALL_DIR/bun" || error "Failed to make bun executable"
|
||||
|
||||
# Verify installation
|
||||
if [[ -x "$INSTALL_DIR/bun" ]]; then
|
||||
BUN_VERSION="$("$INSTALL_DIR/bun" --version 2>/dev/null || echo "unknown")"
|
||||
info "✓ Bun $BUN_VERSION has been installed to $INSTALL_DIR/bun"
|
||||
else
|
||||
error "Installation verification failed"
|
||||
fi
|
||||
|
||||
# Add to PATH if needed
|
||||
if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then
|
||||
info ""
|
||||
info "To use Bun, add this to your shell configuration file (.bashrc, .zshrc, etc.):"
|
||||
info " export PATH=\"\$PATH:$INSTALL_DIR\""
|
||||
info ""
|
||||
info "Or run this command to use Bun in the current session:"
|
||||
info " export PATH=\"\$PATH:$INSTALL_DIR\""
|
||||
fi
|
||||
|
||||
exit 0
|
||||
__PAYLOAD_BEGINS__
|
||||
SCRIPT_EOF
|
||||
|
||||
# Replace the architecture placeholder
|
||||
sed -i '' "s/ARCH_PLACEHOLDER/${{ matrix.display }}/g" extract-header.sh
|
||||
|
||||
- name: Create Self-Extracting Archive
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Create a tar.gz of the bun executable
|
||||
tar -czf bun.tar.gz bun
|
||||
|
||||
# Encode it as base64
|
||||
base64 < bun.tar.gz > bun.tar.gz.b64
|
||||
|
||||
# Combine header and payload
|
||||
cat extract-header.sh bun.tar.gz.b64 > "bun-darwin-${{ matrix.arch }}-sfx.sh"
|
||||
|
||||
# Make it executable
|
||||
chmod +x "bun-darwin-${{ matrix.arch }}-sfx.sh"
|
||||
|
||||
# Test the SFX
|
||||
echo "Testing self-extraction..."
|
||||
TEST_DIR="$(mktemp -d)"
|
||||
BUN_INSTALL_DIR="$TEST_DIR" ./bun-darwin-${{ matrix.arch }}-sfx.sh
|
||||
|
||||
if [[ -x "$TEST_DIR/bun" ]]; then
|
||||
echo "✓ Self-extraction test passed"
|
||||
"$TEST_DIR/bun" --version
|
||||
rm -rf "$TEST_DIR"
|
||||
else
|
||||
echo "✗ Self-extraction test failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Create Download Script
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Create installer script
|
||||
cat > "bun-darwin-${{ matrix.arch }}-installer.sh" << 'INSTALLER_EOF'
|
||||
#!/bin/bash
|
||||
# Quick installer script for Bun on macOS
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ARCH="ARCH_PLACEHOLDER"
|
||||
VERSION="VERSION_PLACEHOLDER"
|
||||
|
||||
if [[ "$ARCH" == "arm64" ]]; then
|
||||
SFX_ARCH="aarch64"
|
||||
else
|
||||
SFX_ARCH="x64"
|
||||
fi
|
||||
|
||||
echo "Downloading Bun $VERSION for macOS $ARCH..."
|
||||
|
||||
if [[ "$VERSION" == "canary" ]]; then
|
||||
URL="https://github.com/oven-sh/bun/releases/download/canary/bun-darwin-${SFX_ARCH}-sfx.sh"
|
||||
else
|
||||
URL="https://github.com/oven-sh/bun/releases/download/$VERSION/bun-darwin-${SFX_ARCH}-sfx.sh"
|
||||
fi
|
||||
|
||||
curl -fsSL "$URL" | bash
|
||||
INSTALLER_EOF
|
||||
|
||||
# Replace placeholders
|
||||
sed -i '' "s/ARCH_PLACEHOLDER/${{ matrix.display }}/g" "bun-darwin-${{ matrix.arch }}-installer.sh"
|
||||
sed -i '' "s/VERSION_PLACEHOLDER/${{ env.BUN_VERSION }}/g" "bun-darwin-${{ matrix.arch }}-installer.sh"
|
||||
|
||||
chmod +x "bun-darwin-${{ matrix.arch }}-installer.sh"
|
||||
|
||||
- name: Generate Checksums
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Generate SHA256 checksums
|
||||
shasum -a 256 "bun-darwin-${{ matrix.arch }}-sfx.sh" > "bun-darwin-${{ matrix.arch }}-sfx.sh.sha256"
|
||||
shasum -a 256 "bun-darwin-${{ matrix.arch }}-installer.sh" > "bun-darwin-${{ matrix.arch }}-installer.sh.sha256"
|
||||
|
||||
echo "Generated files:"
|
||||
ls -la *.sh *.sha256
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-darwin-${{ matrix.arch }}-sfx
|
||||
path: |
|
||||
sfx-build/bun-darwin-${{ matrix.arch }}-sfx.sh
|
||||
sfx-build/bun-darwin-${{ matrix.arch }}-sfx.sh.sha256
|
||||
sfx-build/bun-darwin-${{ matrix.arch }}-installer.sh
|
||||
sfx-build/bun-darwin-${{ matrix.arch }}-installer.sh.sha256
|
||||
|
||||
- name: Upload to Release
|
||||
if: ${{ (github.event_name == 'release' || github.event.inputs.upload-to-release == 'true') && env.BUN_VERSION != 'canary' }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Upload the SFX and installer scripts to the release
|
||||
gh release upload "${{ env.BUN_VERSION }}" \
|
||||
"bun-darwin-${{ matrix.arch }}-sfx.sh" \
|
||||
"bun-darwin-${{ matrix.arch }}-sfx.sh.sha256" \
|
||||
"bun-darwin-${{ matrix.arch }}-installer.sh" \
|
||||
"bun-darwin-${{ matrix.arch }}-installer.sh.sha256" \
|
||||
--clobber \
|
||||
--repo "${{ github.repository }}"
|
||||
|
||||
create-universal-installer:
|
||||
name: Create Universal macOS Installer
|
||||
runs-on: macos-latest
|
||||
needs: create-macos-sfx
|
||||
if: ${{ github.repository_owner == 'oven-sh' }}
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download SFX Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: bun-darwin-*-sfx
|
||||
merge-multiple: true
|
||||
path: sfx-files
|
||||
|
||||
- name: Create Universal Installer
|
||||
run: |
|
||||
cd sfx-files
|
||||
|
||||
# Create universal installer script
|
||||
cat > bun-darwin-universal-installer.sh << 'UNIVERSAL_EOF'
|
||||
#!/bin/bash
|
||||
# Universal Bun installer for macOS (detects architecture automatically)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
VERSION="VERSION_PLACEHOLDER"
|
||||
|
||||
# Detect architecture
|
||||
ARCH="$(uname -m)"
|
||||
if [[ "$ARCH" == "x86_64" ]]; then
|
||||
SFX_ARCH="x64"
|
||||
elif [[ "$ARCH" == "arm64" ]]; then
|
||||
SFX_ARCH="aarch64"
|
||||
else
|
||||
echo "Error: Unsupported architecture: $ARCH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Detected architecture: $ARCH"
|
||||
echo "Downloading Bun $VERSION for macOS..."
|
||||
|
||||
if [[ "$VERSION" == "canary" ]]; then
|
||||
URL="https://github.com/oven-sh/bun/releases/download/canary/bun-darwin-${SFX_ARCH}-sfx.sh"
|
||||
else
|
||||
URL="https://github.com/oven-sh/bun/releases/download/$VERSION/bun-darwin-${SFX_ARCH}-sfx.sh"
|
||||
fi
|
||||
|
||||
curl -fsSL "$URL" | bash
|
||||
UNIVERSAL_EOF
|
||||
|
||||
# Replace version placeholder
|
||||
sed -i '' "s/VERSION_PLACEHOLDER/${{ env.BUN_VERSION }}/g" bun-darwin-universal-installer.sh
|
||||
|
||||
chmod +x bun-darwin-universal-installer.sh
|
||||
|
||||
# Generate checksum
|
||||
shasum -a 256 bun-darwin-universal-installer.sh > bun-darwin-universal-installer.sh.sha256
|
||||
|
||||
- name: Upload Universal Installer
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-darwin-universal-sfx
|
||||
path: |
|
||||
sfx-files/bun-darwin-universal-installer.sh
|
||||
sfx-files/bun-darwin-universal-installer.sh.sha256
|
||||
|
||||
- name: Upload to Release
|
||||
if: ${{ (github.event_name == 'release' || github.event.inputs.upload-to-release == 'true') && env.BUN_VERSION != 'canary' }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
cd sfx-files
|
||||
|
||||
gh release upload "${{ env.BUN_VERSION }}" \
|
||||
"bun-darwin-universal-installer.sh" \
|
||||
"bun-darwin-universal-installer.sh.sha256" \
|
||||
--clobber \
|
||||
--repo "${{ github.repository }}"
|
||||
@@ -1,52 +1,35 @@
|
||||
# Self-Extracting Archives (SFX) for Bun
|
||||
# Self-Extracting Executables for Bun
|
||||
|
||||
Self-extracting archives provide a convenient way to install Bun without requiring external tools like `unzip`. These are shell scripts that contain the Bun binary embedded within them.
|
||||
Bun provides true self-extracting executables for Linux that require **zero dependencies** - not even a shell. These are native binaries that contain the Bun executable embedded within them.
|
||||
|
||||
## Linux
|
||||
|
||||
### Quick Install
|
||||
### Download and Run
|
||||
|
||||
For automatic architecture detection:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://github.com/oven-sh/bun/releases/latest/download/bun-linux-install.sh | sh
|
||||
```
|
||||
|
||||
### Manual Installation
|
||||
|
||||
Choose the appropriate version for your system:
|
||||
Download the appropriate executable for your system and run it directly:
|
||||
|
||||
**x64 (with AVX2 support):**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64-sfx.sh | sh
|
||||
curl -LO https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64
|
||||
chmod +x bun-linux-x64
|
||||
./bun-linux-x64
|
||||
```
|
||||
|
||||
**x64 (baseline - no AVX2):**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64-baseline-sfx.sh | sh
|
||||
curl -LO https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64-baseline
|
||||
chmod +x bun-linux-x64-baseline
|
||||
./bun-linux-x64-baseline
|
||||
```
|
||||
|
||||
**ARM64/AArch64:**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://github.com/oven-sh/bun/releases/latest/download/bun-linux-aarch64-sfx.sh | sh
|
||||
```
|
||||
|
||||
### Download and Run Later
|
||||
|
||||
You can also download the SFX file and run it later:
|
||||
|
||||
```bash
|
||||
# Download
|
||||
curl -LO https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64-sfx.sh
|
||||
|
||||
# Make executable
|
||||
chmod +x bun-linux-x64-sfx.sh
|
||||
|
||||
# Run
|
||||
./bun-linux-x64-sfx.sh
|
||||
curl -LO https://github.com/oven-sh/bun/releases/latest/download/bun-linux-aarch64
|
||||
chmod +x bun-linux-aarch64
|
||||
./bun-linux-aarch64
|
||||
```
|
||||
|
||||
### Custom Installation Directory
|
||||
@@ -54,40 +37,33 @@ chmod +x bun-linux-x64-sfx.sh
|
||||
By default, Bun installs to `$HOME/.bun/bin`. You can override this:
|
||||
|
||||
```bash
|
||||
BUN_INSTALL_DIR=/usr/local/bin ./bun-linux-x64-sfx.sh
|
||||
BUN_INSTALL_DIR=/usr/local/bin ./bun-linux-x64
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
The self-extracting archives are shell scripts with these components:
|
||||
The self-extracting executables are true native binaries:
|
||||
|
||||
1. **Shell Script Header**: A POSIX-compliant shell script that:
|
||||
1. **Native Binary**: Written in C and compiled to a static executable
|
||||
2. **Embedded Bun**: The Bun executable is compressed and embedded directly in the binary
|
||||
3. **Zero Dependencies**: Statically linked - requires absolutely nothing to run
|
||||
4. **Small Size**: Uses UPX compression to minimize file size
|
||||
|
||||
- Checks system compatibility
|
||||
- Creates the installation directory
|
||||
- Extracts the embedded binary
|
||||
- Sets proper permissions
|
||||
- Provides PATH setup instructions
|
||||
When you run the executable, it:
|
||||
|
||||
2. **Embedded Binary**: The Bun executable is:
|
||||
|
||||
- Compressed with gzip
|
||||
- Encoded in base64 for text safety
|
||||
- Appended to the shell script
|
||||
|
||||
3. **No External Dependencies**: Only uses standard POSIX tools:
|
||||
- `sh` (POSIX shell)
|
||||
- `tar`, `gzip` (for extraction)
|
||||
- `base64` (for decoding)
|
||||
- `awk`, `tail` (for payload extraction)
|
||||
1. Creates the installation directory
|
||||
2. Decompresses the embedded Bun binary
|
||||
3. Writes it to disk with proper permissions
|
||||
4. Verifies the installation
|
||||
5. Provides PATH setup instructions
|
||||
|
||||
## Advantages
|
||||
|
||||
- **No `unzip` Required**: Works on minimal Linux systems
|
||||
- **Single File**: Everything in one downloadable script
|
||||
- **Zero Dependencies**: No shell, no tar, no gzip, no base64 - nothing required
|
||||
- **Single File**: One self-contained executable
|
||||
- **Secure**: Checksums provided for verification
|
||||
- **Portable**: POSIX-compliant, works on most Linux distributions
|
||||
- **Architecture Detection**: Universal installer automatically selects the right binary
|
||||
- **Universal**: Works on any Linux system with the matching architecture
|
||||
- **Fast**: Native code extraction is faster than shell scripts
|
||||
|
||||
## Verification
|
||||
|
||||
@@ -95,8 +71,18 @@ Always verify downloads using the provided checksums:
|
||||
|
||||
```bash
|
||||
# Download checksum
|
||||
curl -LO https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64-sfx.sh.sha256
|
||||
curl -LO https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64.sha256
|
||||
|
||||
# Verify
|
||||
sha256sum -c bun-linux-x64-sfx.sh.sha256
|
||||
sha256sum -c bun-linux-x64.sha256
|
||||
```
|
||||
|
||||
## Technical Details
|
||||
|
||||
The self-extracting executables are built using:
|
||||
|
||||
- **Language**: C
|
||||
- **Compression**: zlib (gzip compatible)
|
||||
- **Executable Compression**: UPX with LZMA
|
||||
- **Linking**: Static (no shared library dependencies)
|
||||
- **Cross-compilation**: Supports x64 and aarch64 targets
|
||||
|
||||
@@ -56,14 +56,9 @@ success() {
|
||||
# Check for unzip and offer SFX alternative if not available
|
||||
use_sfx=0
|
||||
if ! command -v unzip >/dev/null 2>&1; then
|
||||
echo -e "${Dim}unzip is not available. Using self-extracting archive instead.${Color_Off}"
|
||||
echo -e "${Dim}unzip is not available. Using self-extracting executable instead.${Color_Off}"
|
||||
use_sfx=1
|
||||
|
||||
# Check for required tools for SFX
|
||||
for tool in sh tar gzip base64 awk tail; do
|
||||
command -v "$tool" >/dev/null 2>&1 ||
|
||||
error "$tool is required for self-extracting archive installation"
|
||||
done
|
||||
# No tool checks needed - SFX executables have zero dependencies!
|
||||
fi
|
||||
|
||||
if [[ $# -gt 2 ]]; then
|
||||
@@ -161,21 +156,34 @@ if [[ $use_sfx -eq 1 ]]; then
|
||||
linux-x64-musl) sfx_name="bun-linux-x64-musl" ;;
|
||||
linux-x64-musl-baseline) sfx_name="bun-linux-x64-musl-baseline" ;;
|
||||
linux-aarch64-musl) sfx_name="bun-linux-aarch64-musl" ;;
|
||||
*) error "Self-extracting archives are not available for $target. Please install unzip." ;;
|
||||
*) error "Self-extracting executables are not available for $target. Please install unzip." ;;
|
||||
esac
|
||||
|
||||
if [[ $# = 0 ]]; then
|
||||
sfx_uri=$github_repo/releases/latest/download/$sfx_name-sfx.sh
|
||||
sfx_uri=$github_repo/releases/latest/download/$sfx_name
|
||||
else
|
||||
sfx_uri=$github_repo/releases/download/$1/$sfx_name-sfx.sh
|
||||
sfx_uri=$github_repo/releases/download/$1/$sfx_name
|
||||
fi
|
||||
|
||||
info "Downloading self-extracting archive..."
|
||||
info "Downloading self-extracting executable..."
|
||||
info "This is a zero-dependency native executable."
|
||||
|
||||
# Download and run the SFX with custom install directory
|
||||
# Download the SFX executable
|
||||
sfx_temp="$exe.sfx.tmp"
|
||||
curl --fail --location --progress-bar --output "$sfx_temp" "$sfx_uri" ||
|
||||
error "Failed to download self-extracting executable from \"$sfx_uri\""
|
||||
|
||||
# Make it executable
|
||||
chmod +x "$sfx_temp" ||
|
||||
error "Failed to set permissions on self-extracting executable"
|
||||
|
||||
# Run it with custom install directory
|
||||
export BUN_INSTALL_DIR="$bin_dir"
|
||||
curl --fail --location --progress-bar "$sfx_uri" | sh ||
|
||||
error "Failed to download and run self-extracting archive from \"$sfx_uri\""
|
||||
"$sfx_temp" ||
|
||||
error "Failed to run self-extracting executable"
|
||||
|
||||
# Clean up
|
||||
rm -f "$sfx_temp"
|
||||
|
||||
# The SFX installs directly to bin_dir, so we're done with extraction
|
||||
exe=$bin_dir/bun
|
||||
|
||||
Reference in New Issue
Block a user