* Fix macOS install.sh: stdin consumption and Python discovery Two issues when running `curl | sh` on macOS: 1. Commands like `brew install` consume bytes from the piped stdin, causing the shell to lose its place in the script. The remaining source code gets printed as text instead of being executed, so users have to run the installer twice. Fixed by redirecting stdin from /dev/null for brew, apt-get, xcode-select, and the uv installer subprocess. 2. setup.sh searches for Python 3.11-3.13 on the system PATH via `compgen -c`. On macOS systems that only have Python 3.9 and/or 3.14, this fails with "No Python version between 3.11 and 3.13 found" even though uv already installed Python 3.13 into the venv. Fixed by adding the venv's bin/ to PATH before invoking `unsloth studio setup`. * Guard PATH export against empty VENV_ABS_BIN If cd into the venv bin/ fails, VENV_ABS_BIN would be empty and PATH would start with ":", causing the current directory to be searched for executables. Wrap the export in a non-empty check.
221 lines
7.5 KiB
Bash
Executable file
221 lines
7.5 KiB
Bash
Executable file
#!/bin/sh
|
|
# Unsloth Studio Installer
|
|
# Usage (curl): curl -fsSL https://raw.githubusercontent.com/unslothai/unsloth/main/install.sh | sh
|
|
# Usage (wget): wget -qO- https://raw.githubusercontent.com/unslothai/unsloth/main/install.sh | sh
|
|
set -e
|
|
|
|
VENV_NAME="unsloth_studio"
|
|
PYTHON_VERSION="3.13"
|
|
|
|
# ── Helper: download a URL to a file (supports curl and wget) ──
|
|
download() {
|
|
if command -v curl >/dev/null 2>&1; then
|
|
curl -LsSf "$1" -o "$2"
|
|
elif command -v wget >/dev/null 2>&1; then
|
|
wget -qO "$2" "$1"
|
|
else
|
|
echo "Error: neither curl nor wget found. Install one and re-run."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# ── Helper: check if a single package is available on the system ──
|
|
_is_pkg_installed() {
|
|
case "$1" in
|
|
build-essential) command -v gcc >/dev/null 2>&1 ;;
|
|
libcurl4-openssl-dev)
|
|
command -v dpkg >/dev/null 2>&1 && dpkg -s "$1" >/dev/null 2>&1 ;;
|
|
pciutils)
|
|
command -v lspci >/dev/null 2>&1 ;;
|
|
*) command -v "$1" >/dev/null 2>&1 ;;
|
|
esac
|
|
}
|
|
|
|
# ── Helper: install packages via apt, escalating to sudo only if needed ──
|
|
# Usage: _smart_apt_install pkg1 pkg2 pkg3 ...
|
|
_smart_apt_install() {
|
|
_PKGS="$*"
|
|
|
|
# Step 1: Try installing without sudo (works when already root)
|
|
apt-get update -y </dev/null >/dev/null 2>&1 || true
|
|
apt-get install -y $_PKGS </dev/null >/dev/null 2>&1 || true
|
|
|
|
# Step 2: Check which packages are still missing
|
|
_STILL_MISSING=""
|
|
for _pkg in $_PKGS; do
|
|
if ! _is_pkg_installed "$_pkg"; then
|
|
_STILL_MISSING="$_STILL_MISSING $_pkg"
|
|
fi
|
|
done
|
|
_STILL_MISSING=$(echo "$_STILL_MISSING" | sed 's/^ *//')
|
|
|
|
if [ -z "$_STILL_MISSING" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# Step 3: Escalate -- need elevated permissions for remaining packages
|
|
if command -v sudo >/dev/null 2>&1; then
|
|
echo ""
|
|
echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
|
echo " WARNING: We require sudo elevated permissions to install:"
|
|
echo " $_STILL_MISSING"
|
|
echo " If you accept, we'll run sudo now, and it'll prompt your password."
|
|
echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
|
echo ""
|
|
printf " Accept? [Y/n] "
|
|
if [ -r /dev/tty ]; then
|
|
read -r REPLY </dev/tty || REPLY="y"
|
|
else
|
|
REPLY="y"
|
|
fi
|
|
case "$REPLY" in
|
|
[nN]*)
|
|
echo ""
|
|
echo " Please install these packages first, then re-run Unsloth Studio setup:"
|
|
echo " sudo apt-get update -y && sudo apt-get install -y $_STILL_MISSING"
|
|
exit 1
|
|
;;
|
|
*)
|
|
sudo apt-get update -y </dev/null
|
|
sudo apt-get install -y $_STILL_MISSING </dev/null
|
|
;;
|
|
esac
|
|
else
|
|
echo ""
|
|
echo " sudo is not available on this system."
|
|
echo " Please install these packages as root, then re-run Unsloth Studio setup:"
|
|
echo " apt-get update -y && apt-get install -y $_STILL_MISSING"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
echo ""
|
|
echo "========================================="
|
|
echo " Unsloth Studio Installer"
|
|
echo "========================================="
|
|
echo ""
|
|
|
|
# ── Detect platform ──
|
|
OS="linux"
|
|
if [ "$(uname)" = "Darwin" ]; then
|
|
OS="macos"
|
|
elif grep -qi microsoft /proc/version 2>/dev/null; then
|
|
OS="wsl"
|
|
fi
|
|
echo "==> Platform: $OS"
|
|
|
|
# ── Check system dependencies ──
|
|
# cmake and git are needed by unsloth studio setup to build the GGUF inference
|
|
# engine (llama.cpp). build-essential and libcurl-dev are also needed on Linux.
|
|
MISSING=""
|
|
|
|
command -v cmake >/dev/null 2>&1 || MISSING="$MISSING cmake"
|
|
command -v git >/dev/null 2>&1 || MISSING="$MISSING git"
|
|
|
|
case "$OS" in
|
|
macos)
|
|
# Xcode Command Line Tools provide the C/C++ compiler
|
|
if ! xcode-select -p >/dev/null 2>&1; then
|
|
echo ""
|
|
echo "==> Xcode Command Line Tools are required."
|
|
echo " Installing (a system dialog will appear)..."
|
|
xcode-select --install </dev/null 2>/dev/null || true
|
|
echo " After the installation completes, please re-run this script."
|
|
exit 1
|
|
fi
|
|
;;
|
|
linux|wsl)
|
|
# curl or wget is needed for downloads; check both
|
|
if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
|
|
MISSING="$MISSING curl"
|
|
fi
|
|
command -v gcc >/dev/null 2>&1 || MISSING="$MISSING build-essential"
|
|
# libcurl dev headers for llama.cpp HTTPS support
|
|
if command -v dpkg >/dev/null 2>&1; then
|
|
dpkg -s libcurl4-openssl-dev >/dev/null 2>&1 || MISSING="$MISSING libcurl4-openssl-dev"
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
MISSING=$(echo "$MISSING" | sed 's/^ *//')
|
|
|
|
if [ -n "$MISSING" ]; then
|
|
echo ""
|
|
echo "==> Unsloth Studio needs these packages: $MISSING"
|
|
echo " These are needed to build the GGUF inference engine."
|
|
|
|
case "$OS" in
|
|
macos)
|
|
if ! command -v brew >/dev/null 2>&1; then
|
|
echo ""
|
|
echo " Homebrew is required to install them."
|
|
echo " Install Homebrew from https://brew.sh then re-run this script."
|
|
exit 1
|
|
fi
|
|
brew install $MISSING </dev/null
|
|
;;
|
|
linux|wsl)
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
_smart_apt_install $MISSING
|
|
else
|
|
echo " apt-get is not available. Please install with your package manager:"
|
|
echo " $MISSING"
|
|
echo " Then re-run Unsloth Studio setup."
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|
|
echo ""
|
|
else
|
|
echo "==> All system dependencies found."
|
|
fi
|
|
|
|
# ── Install uv ──
|
|
if ! command -v uv >/dev/null 2>&1; then
|
|
echo "==> Installing uv package manager..."
|
|
_uv_tmp=$(mktemp)
|
|
download "https://astral.sh/uv/install.sh" "$_uv_tmp"
|
|
sh "$_uv_tmp" </dev/null
|
|
rm -f "$_uv_tmp"
|
|
if [ -f "$HOME/.local/bin/env" ]; then
|
|
. "$HOME/.local/bin/env"
|
|
fi
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
fi
|
|
|
|
# ── Create venv (skip if it already exists and has a valid interpreter) ──
|
|
if [ ! -x "$VENV_NAME/bin/python" ]; then
|
|
[ -e "$VENV_NAME" ] && rm -rf "$VENV_NAME"
|
|
echo "==> Creating Python ${PYTHON_VERSION} virtual environment (${VENV_NAME})..."
|
|
uv venv "$VENV_NAME" --python "$PYTHON_VERSION"
|
|
else
|
|
echo "==> Virtual environment ${VENV_NAME} already exists, skipping creation."
|
|
fi
|
|
|
|
# ── Install unsloth directly into the venv (no activation needed) ──
|
|
echo "==> Installing unsloth (this may take a few minutes)..."
|
|
uv pip install --python "$VENV_NAME/bin/python" unsloth --torch-backend=auto
|
|
|
|
# ── Run studio setup ──
|
|
# Ensure the venv's Python is on PATH for setup.sh's Python discovery.
|
|
# On macOS the system Python may be outside the 3.11-3.13 range that
|
|
# setup.sh requires, but uv already installed a compatible interpreter
|
|
# inside the venv.
|
|
VENV_ABS_BIN="$(cd "$VENV_NAME/bin" && pwd)"
|
|
if [ -n "$VENV_ABS_BIN" ]; then
|
|
export PATH="$VENV_ABS_BIN:$PATH"
|
|
fi
|
|
|
|
echo "==> Running unsloth studio setup..."
|
|
"$VENV_NAME/bin/unsloth" studio setup </dev/null
|
|
|
|
echo ""
|
|
echo "========================================="
|
|
echo " Unsloth Studio installed!"
|
|
echo "========================================="
|
|
echo ""
|
|
echo " To launch, run:"
|
|
echo ""
|
|
echo " source ${VENV_NAME}/bin/activate"
|
|
echo " unsloth studio -H 0.0.0.0 -p 8888"
|
|
echo ""
|