Compare commits

...

4 Commits

Author SHA1 Message Date
Cursor Agent
e8192578f0 Refactor Linux SFX to native zero-dependency executables 2025-06-05 22:19:12 +00:00
Cursor Agent
f7b221b3bd Add Linux self-extracting archives (SFX) for Bun installation 2025-06-05 22:13:12 +00:00
Cursor Agent
26f7fcbbb0 Checkpoint before follow-up message 2025-06-05 22:08:31 +00:00
Cursor Agent
91e3076ec7 Initial commit of modified files from installation 2025-06-05 22:01:19 +00:00
6 changed files with 819 additions and 12 deletions

View File

@@ -48,6 +48,10 @@ on:
description: "Should types be PR'd to DefinitelyTyped?"
type: boolean
default: false
use-sfx:
description: Should self-extracting archives be generated?
type: boolean
default: false
jobs:
sign:
@@ -327,6 +331,129 @@ jobs:
AWS_ENDPOINT: ${{ secrets.AWS_ENDPOINT }}
AWS_BUCKET: bun
linux-sfx:
name: Generate Linux SFX Archives
runs-on: ubuntu-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: x64
zip_name: bun-linux-x64
display: x64
- arch: x64
zip_name: bun-linux-x64-baseline
display: x64-baseline
baseline: true
- arch: aarch64
zip_name: bun-linux-aarch64
display: aarch64
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 ${{ matrix.zip_name }}.zip..."
if [[ "${{ env.BUN_VERSION }}" == "canary" ]]; then
DOWNLOAD_URL="https://github.com/oven-sh/bun/releases/download/canary/${{ matrix.zip_name }}.zip"
else
DOWNLOAD_URL="https://github.com/oven-sh/bun/releases/download/${{ env.BUN_VERSION }}/${{ matrix.zip_name }}.zip"
fi
curl -L -o "${{ matrix.zip_name }}.zip" "$DOWNLOAD_URL"
# Extract the zip file
unzip -q "${{ matrix.zip_name }}.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-linux-*/ ${{ matrix.zip_name }}.zip
- name: Create Self-Extracting Archive
run: |
cd sfx-build
# Create the self-extracting script header
cat > extract-header.sh << 'SCRIPT_EOF'
#!/bin/sh
set -e
DEFAULT_INSTALL_DIR="$HOME/.bun/bin"
INSTALL_DIR="${BUN_INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"
ARCH="$(uname -m)"
EXPECTED_ARCH="ARCH_PLACEHOLDER"
EXPECTED_DISPLAY="DISPLAY_PLACEHOLDER"
case "$ARCH" in
x86_64) ARCH_NORM="x64" ;;
aarch64|arm64) ARCH_NORM="aarch64" ;;
*) ARCH_NORM="$ARCH" ;;
esac
ARCH_MISMATCH=0
case "$EXPECTED_ARCH" in
x64) [ "$ARCH_NORM" != "x64" ] && ARCH_MISMATCH=1 ;;
aarch64) [ "$ARCH_NORM" != "aarch64" ] && ARCH_MISMATCH=1 ;;
esac
if [ "$ARCH_MISMATCH" = "1" ]; then
echo "Warning: This installer is for $EXPECTED_DISPLAY but you're running on $ARCH"
fi
mkdir -p "$INSTALL_DIR"
ARCHIVE_LINE=$(awk '/^__ARCHIVE_BELOW__/ { print NR + 1; exit }' "$0")
echo "Extracting Bun to $INSTALL_DIR..."
tail -n +"$ARCHIVE_LINE" "$0" | base64 -d | tar -xzf - -C "$INSTALL_DIR"
chmod +x "$INSTALL_DIR/bun"
BUN_VERSION=$("$INSTALL_DIR/bun" --version 2>/dev/null || echo "unknown")
echo "Bun $BUN_VERSION has been installed to $INSTALL_DIR/bun"
echo "Run 'export PATH=\"\$PATH:$INSTALL_DIR\"' to add it to your PATH"
exit 0
__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
# 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 > "${{ matrix.zip_name }}-sfx.sh"
chmod +x "${{ matrix.zip_name }}-sfx.sh"
# Generate checksum
sha256sum "${{ matrix.zip_name }}-sfx.sh" > "${{ matrix.zip_name }}-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 }}" \
"${{ matrix.zip_name }}-sfx.sh" \
"${{ matrix.zip_name }}-sfx.sh.sha256" \
--clobber \
--repo "${{ github.repository }}"
notify-sentry:
name: Notify Sentry
runs-on: ubuntu-latest

541
.github/workflows/sfx-linux.yml vendored Normal file
View File

@@ -0,0 +1,541 @@
name: Generate Linux SFX Archives
concurrency: sfx-linux
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-linux-sfx:
name: Create Linux Self-Extracting Archives
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'oven-sh' }}
permissions:
contents: write
strategy:
matrix:
include:
- 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 Build Environment
run: |
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
- name: Download Bun Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd sfx-build
echo "Downloading ${{ matrix.zip_name }}.zip..."
if [[ "${{ env.BUN_VERSION }}" == "canary" ]]; then
DOWNLOAD_URL="https://github.com/oven-sh/bun/releases/download/canary/${{ matrix.zip_name }}.zip"
else
DOWNLOAD_URL="https://github.com/oven-sh/bun/releases/download/${{ env.BUN_VERSION }}/${{ matrix.zip_name }}.zip"
fi
curl -L -o "${{ matrix.zip_name }}.zip" "$DOWNLOAD_URL"
# Extract the zip file
unzip -q "${{ matrix.zip_name }}.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
# Compress the binary
echo "Compressing bun binary..."
gzip -9 -k ./bun
# Clean up
rm -rf bun-linux-*/ ${{ matrix.zip_name }}.zip
- name: Create SFX Source Code
run: |
cd sfx-build
# 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>
// 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"
// Embedded compressed binary data
static const unsigned char compressed_data[] = {
#include "bun_data.h"
};
static const size_t compressed_size = sizeof(compressed_data);
// Installation configuration
#ifndef DEFAULT_INSTALL_DIR
#define DEFAULT_INSTALL_DIR "/.bun/bin"
#endif
#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);
}
}
void print_success(const char* msg) {
if (isatty(STDOUT_FILENO)) {
printf(COLOR_GREEN "%s" COLOR_RESET "\n", msg);
} else {
printf("%s\n", msg);
}
}
void print_info(const char* msg) {
printf("%s\n", msg);
}
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;
}
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;
}
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;
}
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
# 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
- name: Build Self-Extracting Executable
run: |
cd sfx-build
# 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
# 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
# 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 }}"
# 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
echo "Testing self-extraction..."
TEST_DIR="$(mktemp -d)"
BUN_INSTALL_DIR="$TEST_DIR" ./${{ matrix.zip_name }}
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: Generate Checksums
run: |
cd sfx-build
# Generate SHA256 checksums
sha256sum "${{ matrix.zip_name }}" > "${{ matrix.zip_name }}.sha256"
echo "Generated files:"
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-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' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd sfx-build
# Upload the SFX to the release
gh release upload "${{ env.BUN_VERSION }}" \
"${{ matrix.zip_name }}" \
"${{ matrix.zip_name }}.sha256" \
--clobber \
--repo "${{ github.repository }}"
create-universal-linux-installer:
name: Create Universal Linux Installer
runs-on: ubuntu-latest
needs: create-linux-sfx
if: ${{ github.repository_owner == 'oven-sh' }}
permissions:
contents: write
steps:
- name: Download SFX Artifacts
uses: actions/download-artifact@v4
with:
pattern: bun-linux-*-sfx
merge-multiple: true
path: sfx-files
- name: Create Universal Installer
run: |
cd sfx-files
# Create a universal installer that detects architecture
cat > bun-linux-install.sh << 'UNIVERSAL_EOF'
#!/bin/sh
# Universal Bun installer for Linux (detects architecture automatically)
set -e
VERSION="VERSION_PLACEHOLDER"
# Detect architecture
ARCH="$(uname -m)"
case "$ARCH" in
x86_64)
# Check CPU features for baseline support
if [ -f /proc/cpuinfo ]; then
# Check for AVX2 support (non-baseline requirement)
if grep -q "avx2" /proc/cpuinfo 2>/dev/null; then
ARCHIVE_NAME="bun-linux-x64"
echo "Detected: x64 (with AVX2 support)"
else
ARCHIVE_NAME="bun-linux-x64-baseline"
echo "Detected: x64 (baseline - no AVX2)"
fi
else
# Default to baseline if we can't detect
ARCHIVE_NAME="bun-linux-x64-baseline"
echo "Detected: x64 (defaulting to baseline)"
fi
;;
aarch64|arm64)
ARCHIVE_NAME="bun-linux-aarch64"
echo "Detected: ARM64/AArch64"
;;
*)
echo "Error: Unsupported architecture: $ARCH"
echo "Bun supports x64 and aarch64 on Linux"
exit 1
;;
esac
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
UNIVERSAL_EOF
# Replace version placeholder
sed -i "s/VERSION_PLACEHOLDER/${{ env.BUN_VERSION }}/g" bun-linux-install.sh
chmod +x bun-linux-install.sh
# Generate checksum
sha256sum bun-linux-install.sh > bun-linux-install.sh.sha256
- name: Upload Universal Installer
uses: actions/upload-artifact@v4
with:
name: bun-linux-universal-sfx
path: |
sfx-files/bun-linux-install.sh
sfx-files/bun-linux-install.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-linux-install.sh" \
"bun-linux-install.sh.sha256" \
--clobber \
--repo "${{ github.repository }}"

2
.gitignore vendored
View File

@@ -183,4 +183,4 @@ codegen-for-zig-team.tar.gz
*.sock
scratch*.{js,ts,tsx,cjs,mjs}
*.bun-build
*.bun-build/bun/

1
bun Submodule

Submodule bun added at f62940bbda

88
docs/install/sfx.md Normal file
View File

@@ -0,0 +1,88 @@
# Self-Extracting Executables for Bun
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
### Download and Run
Download the appropriate executable for your system and run it directly:
**x64 (with AVX2 support):**
```bash
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 -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 -LO https://github.com/oven-sh/bun/releases/latest/download/bun-linux-aarch64
chmod +x bun-linux-aarch64
./bun-linux-aarch64
```
### Custom Installation Directory
By default, Bun installs to `$HOME/.bun/bin`. You can override this:
```bash
BUN_INSTALL_DIR=/usr/local/bin ./bun-linux-x64
```
## How It Works
The self-extracting executables are true native binaries:
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
When you run the executable, it:
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
- **Zero Dependencies**: No shell, no tar, no gzip, no base64 - nothing required
- **Single File**: One self-contained executable
- **Secure**: Checksums provided for verification
- **Universal**: Works on any Linux system with the matching architecture
- **Fast**: Native code extraction is faster than shell scripts
## Verification
Always verify downloads using the provided checksums:
```bash
# Download checksum
curl -LO https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64.sha256
# Verify
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

View File

@@ -53,8 +53,13 @@ success() {
echo -e "${Green}$@ ${Color_Off}"
}
command -v unzip >/dev/null ||
error 'unzip is required to install bun'
# 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 executable instead.${Color_Off}"
use_sfx=1
# No tool checks needed - SFX executables have zero dependencies!
fi
if [[ $# -gt 2 ]]; then
error 'Too many arguments, only 2 are allowed. The first can be a specific tag of bun to install. (e.g. "bun-v0.1.4") The second can be a build variant of bun to install. (e.g. "debug-info")'
@@ -140,19 +145,64 @@ if [[ ! -d $bin_dir ]]; then
error "Failed to create install directory \"$bin_dir\""
fi
curl --fail --location --progress-bar --output "$exe.zip" "$bun_uri" ||
error "Failed to download bun from \"$bun_uri\""
# Use SFX if unzip is not available
if [[ $use_sfx -eq 1 ]]; then
# Map target to SFX filename
sfx_name=""
case "$target" in
linux-x64) sfx_name="bun-linux-x64" ;;
linux-x64-baseline) sfx_name="bun-linux-x64-baseline" ;;
linux-aarch64) sfx_name="bun-linux-aarch64" ;;
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 executables are not available for $target. Please install unzip." ;;
esac
if [[ $# = 0 ]]; then
sfx_uri=$github_repo/releases/latest/download/$sfx_name
else
sfx_uri=$github_repo/releases/download/$1/$sfx_name
fi
info "Downloading self-extracting executable..."
info "This is a zero-dependency native executable."
# 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"
"$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
else
# Original unzip-based installation
curl --fail --location --progress-bar --output "$exe.zip" "$bun_uri" ||
error "Failed to download bun from \"$bun_uri\""
unzip -oqd "$bin_dir" "$exe.zip" ||
error 'Failed to extract bun'
unzip -oqd "$bin_dir" "$exe.zip" ||
error 'Failed to extract bun'
mv "$bin_dir/bun-$target/$exe_name" "$exe" ||
error 'Failed to move extracted bun to destination'
mv "$bin_dir/bun-$target/$exe_name" "$exe" ||
error 'Failed to move extracted bun to destination'
chmod +x "$exe" ||
error 'Failed to set permissions on bun executable'
chmod +x "$exe" ||
error 'Failed to set permissions on bun executable'
rm -r "$bin_dir/bun-$target" "$exe.zip"
rm -r "$bin_dir/bun-$target" "$exe.zip"
fi
tildify() {
if [[ $1 = $HOME/* ]]; then