mirror of
https://github.com/oven-sh/bun
synced 2026-02-15 05:12:29 +00:00
Add Linux self-extracting archives (SFX) for Bun installation
This commit is contained in:
125
.github/workflows/release.yml
vendored
125
.github/workflows/release.yml
vendored
@@ -49,7 +49,7 @@ on:
|
||||
type: boolean
|
||||
default: false
|
||||
use-sfx:
|
||||
description: Should macOS SFX archives be generated?
|
||||
description: Should self-extracting archives be generated?
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
@@ -440,6 +440,129 @@ jobs:
|
||||
--clobber \
|
||||
--repo "${{ github.repository }}"
|
||||
|
||||
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
|
||||
|
||||
455
.github/workflows/sfx-linux.yml
vendored
Normal file
455
.github/workflows/sfx-linux.yml
vendored
Normal file
@@ -0,0 +1,455 @@
|
||||
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
|
||||
- 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
|
||||
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 ${{ 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 using unzip (available on GitHub runners)
|
||||
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 SFX Script
|
||||
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!)
|
||||
|
||||
set -e
|
||||
|
||||
# Default installation directory
|
||||
DEFAULT_INSTALL_DIR="$HOME/.bun/bin"
|
||||
INSTALL_DIR="${BUN_INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"
|
||||
|
||||
# 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
|
||||
|
||||
error() {
|
||||
printf "${RED}error: %s${NC}\n" "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
info() {
|
||||
printf "${GREEN}%s${NC}\n" "$1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
printf "${YELLOW}warning: %s${NC}\n" "$1"
|
||||
}
|
||||
|
||||
# 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
|
||||
|
||||
# Check architecture
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
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
|
||||
|
||||
# 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
|
||||
run: |
|
||||
cd sfx-build
|
||||
|
||||
# Create a tar.gz of the bun executable
|
||||
tar -czf bun.tar.gz bun
|
||||
|
||||
# Encode it as base64 (for binary safety)
|
||||
base64 < bun.tar.gz > bun.tar.gz.b64
|
||||
|
||||
# Combine header and payload
|
||||
cat extract-header.sh bun.tar.gz.b64 > "${{ matrix.zip_name }}-sfx.sh"
|
||||
|
||||
# Make it executable
|
||||
chmod +x "${{ matrix.zip_name }}-sfx.sh"
|
||||
|
||||
# Test the SFX
|
||||
echo "Testing self-extraction..."
|
||||
TEST_DIR="$(mktemp -d)"
|
||||
BUN_INSTALL_DIR="$TEST_DIR" ./${{ matrix.zip_name }}-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 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"
|
||||
|
||||
echo "Generated files:"
|
||||
ls -la *.sh *.sha256
|
||||
|
||||
- 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
|
||||
|
||||
- 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 }}" \
|
||||
"${{ matrix.zip_name }}-sfx.sh" \
|
||||
"${{ matrix.zip_name }}-sfx.sh.sha256" \
|
||||
"${{ matrix.zip_name }}-install.sh" \
|
||||
"${{ matrix.zip_name }}-install.sh.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 }}"
|
||||
102
docs/install/sfx.md
Normal file
102
docs/install/sfx.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# Self-Extracting Archives (SFX) 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.
|
||||
|
||||
## Linux
|
||||
|
||||
### Quick Install
|
||||
|
||||
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:
|
||||
|
||||
**x64 (with AVX2 support):**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64-sfx.sh | sh
|
||||
```
|
||||
|
||||
**x64 (baseline - no AVX2):**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64-baseline-sfx.sh | sh
|
||||
```
|
||||
|
||||
**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
|
||||
```
|
||||
|
||||
### 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-sfx.sh
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
The self-extracting archives are shell scripts with these components:
|
||||
|
||||
1. **Shell Script Header**: A POSIX-compliant shell script that:
|
||||
|
||||
- Checks system compatibility
|
||||
- Creates the installation directory
|
||||
- Extracts the embedded binary
|
||||
- Sets proper permissions
|
||||
- Provides PATH setup instructions
|
||||
|
||||
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)
|
||||
|
||||
## Advantages
|
||||
|
||||
- **No `unzip` Required**: Works on minimal Linux systems
|
||||
- **Single File**: Everything in one downloadable script
|
||||
- **Secure**: Checksums provided for verification
|
||||
- **Portable**: POSIX-compliant, works on most Linux distributions
|
||||
- **Architecture Detection**: Universal installer automatically selects the right binary
|
||||
|
||||
## 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-sfx.sh.sha256
|
||||
|
||||
# Verify
|
||||
sha256sum -c bun-linux-x64-sfx.sh.sha256
|
||||
```
|
||||
@@ -53,8 +53,18 @@ 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 archive 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
|
||||
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 +150,51 @@ 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 archives are not available for $target. Please install unzip." ;;
|
||||
esac
|
||||
|
||||
if [[ $# = 0 ]]; then
|
||||
sfx_uri=$github_repo/releases/latest/download/$sfx_name-sfx.sh
|
||||
else
|
||||
sfx_uri=$github_repo/releases/download/$1/$sfx_name-sfx.sh
|
||||
fi
|
||||
|
||||
info "Downloading self-extracting archive..."
|
||||
|
||||
# Download and run the SFX 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\""
|
||||
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user