mirror of
https://github.com/unslothai/unsloth
synced 2026-04-21 13:37:39 +00:00
gate on min uv version and shortcut python candidate search if known (#4489)
* gate on min uv version and shortcut python candidate search if known * fix sort -V cross compat issue, run_quiet early exit on llamacpp, autolaunch * update launch message * Fix PR comments * auto launch and find open port * remove dev install * Fix review findings: major-version guard, non-fatal port fallback, tty comment, restore local * Remove autolaunch, clean up dead state and debug noise - Remove find_open_port, TTY-gated autolaunch, and </dev/tty redirection from install.sh; just print launch instructions - Remove unused BEST_MAJOR variable from studio/setup.sh - Remove stray "finished finding best python" debug echo - Fix stale comment "below 3.12" to "below 3.11" * Reject prerelease uv at exact minimum version boundary * Remove 2>/dev/null from version_ge numeric comparisons Let non-numeric version parts surface errors on stderr instead of being silently swallowed. --------- Co-authored-by: Daniel Han <danielhanchen@gmail.com>
This commit is contained in:
parent
64f9f389a0
commit
4c1a6cb962
2 changed files with 99 additions and 30 deletions
62
install.sh
62
install.sh
|
|
@ -171,7 +171,48 @@ else
|
|||
fi
|
||||
|
||||
# ── Install uv ──
|
||||
if ! command -v uv >/dev/null 2>&1; then
|
||||
UV_MIN_VERSION="0.7.14"
|
||||
|
||||
version_ge() {
|
||||
# returns 0 if $1 >= $2
|
||||
_a=$1
|
||||
_b=$2
|
||||
|
||||
while [ -n "$_a" ] || [ -n "$_b" ]; do
|
||||
_a_part=${_a%%.*}
|
||||
_b_part=${_b%%.*}
|
||||
|
||||
[ "$_a" = "$_a_part" ] && _a="" || _a=${_a#*.}
|
||||
[ "$_b" = "$_b_part" ] && _b="" || _b=${_b#*.}
|
||||
|
||||
[ -z "$_a_part" ] && _a_part=0
|
||||
[ -z "$_b_part" ] && _b_part=0
|
||||
|
||||
if [ "$_a_part" -gt "$_b_part" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ "$_a_part" -lt "$_b_part" ]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_uv_version_ok() {
|
||||
_raw=$("$1" --version 2>/dev/null | awk '{print $2}') || return 1
|
||||
[ -n "$_raw" ] || return 1
|
||||
_ver=${_raw%%[-+]*}
|
||||
case "$_ver" in
|
||||
''|*[!0-9.]*) return 1 ;;
|
||||
esac
|
||||
version_ge "$_ver" "$UV_MIN_VERSION" || return 1
|
||||
# Prerelease of the exact minimum (e.g. 0.7.14-rc1) is still below stable 0.7.14
|
||||
[ "$_ver" = "$UV_MIN_VERSION" ] && [ "$_raw" != "$_ver" ] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
if ! command -v uv >/dev/null 2>&1 || ! _uv_version_ok uv; then
|
||||
echo "==> Installing uv package manager..."
|
||||
_uv_tmp=$(mktemp)
|
||||
download "https://astral.sh/uv/install.sh" "$_uv_tmp"
|
||||
|
|
@ -207,6 +248,7 @@ if [ -n "$VENV_ABS_BIN" ]; then
|
|||
fi
|
||||
|
||||
echo "==> Running unsloth studio setup..."
|
||||
REQUESTED_PYTHON_VERSION="$(cd "$VENV_NAME/bin" && pwd)/python" \
|
||||
"$VENV_NAME/bin/unsloth" studio setup </dev/null
|
||||
|
||||
echo ""
|
||||
|
|
@ -215,16 +257,8 @@ echo " Unsloth Studio installed!"
|
|||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
# Launch studio automatically in interactive terminals;
|
||||
# in non-interactive environments (Docker, CI, cloud-init) just print instructions.
|
||||
if [ -t 0 ]; then
|
||||
echo "==> Launching Unsloth Studio..."
|
||||
echo ""
|
||||
exec "$VENV_NAME/bin/unsloth" studio -H 0.0.0.0 -p 8888
|
||||
else
|
||||
echo " To launch, run:"
|
||||
echo ""
|
||||
echo " source ${VENV_NAME}/bin/activate"
|
||||
echo " unsloth studio -H 0.0.0.0 -p 8888"
|
||||
echo ""
|
||||
fi
|
||||
echo " To launch, run:"
|
||||
echo ""
|
||||
echo " source ${VENV_NAME}/bin/activate"
|
||||
echo " unsloth studio -H 0.0.0.0 -p 8888"
|
||||
echo ""
|
||||
|
|
|
|||
|
|
@ -8,22 +8,42 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
# ── Helper: run command quietly, show output only on failure ──
|
||||
run_quiet() {
|
||||
local label="$1"
|
||||
shift
|
||||
_run_quiet() {
|
||||
local on_fail=$1
|
||||
local label=$2
|
||||
shift 2
|
||||
|
||||
local tmplog
|
||||
tmplog=$(mktemp)
|
||||
if "$@" > "$tmplog" 2>&1; then
|
||||
tmplog=$(mktemp) || {
|
||||
printf '%s\n' "Failed to create temporary file" >&2
|
||||
[ "$on_fail" = "exit" ] && exit 1 || return 1
|
||||
}
|
||||
|
||||
if "$@" >"$tmplog" 2>&1; then
|
||||
rm -f "$tmplog"
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
echo "❌ $label failed (exit code $exit_code):"
|
||||
cat "$tmplog"
|
||||
printf 'Failed: %s (exit code %s):\n' "$label" "$exit_code" >&2
|
||||
cat "$tmplog" >&2
|
||||
rm -f "$tmplog"
|
||||
exit $exit_code
|
||||
|
||||
if [ "$on_fail" = "exit" ]; then
|
||||
exit "$exit_code"
|
||||
else
|
||||
return "$exit_code"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
run_quiet() {
|
||||
_run_quiet exit "$@"
|
||||
}
|
||||
|
||||
run_quiet_no_exit() {
|
||||
_run_quiet return "$@"
|
||||
}
|
||||
|
||||
echo "╔══════════════════════════════════════╗"
|
||||
echo "║ Unsloth Studio Setup Script ║"
|
||||
echo "╚══════════════════════════════════════╝"
|
||||
|
|
@ -187,9 +207,24 @@ fi
|
|||
MIN_PY_MINOR=11 # minimum minor version (>= 3.11)
|
||||
MAX_PY_MINOR=13 # maximum minor version (< 3.14)
|
||||
BEST_PY=""
|
||||
BEST_MAJOR=0
|
||||
BEST_MINOR=0
|
||||
|
||||
# If the caller (e.g. install.sh) already chose a Python, use it directly.
|
||||
if [ -n "${REQUESTED_PYTHON_VERSION:-}" ] && [ -x "$REQUESTED_PYTHON_VERSION" ]; then
|
||||
_req_ver=$("$REQUESTED_PYTHON_VERSION" --version 2>&1 | awk '{print $2}')
|
||||
_req_major=$(echo "$_req_ver" | cut -d. -f1)
|
||||
_req_minor=$(echo "$_req_ver" | cut -d. -f2)
|
||||
if [ "$_req_major" -eq 3 ] 2>/dev/null && \
|
||||
[ "$_req_minor" -ge "$MIN_PY_MINOR" ] 2>/dev/null && \
|
||||
[ "$_req_minor" -le "$MAX_PY_MINOR" ] 2>/dev/null; then
|
||||
BEST_PY="$REQUESTED_PYTHON_VERSION"
|
||||
echo "Using requested Python version: $BEST_PY"
|
||||
else
|
||||
echo "Ignoring requested Python $REQUESTED_PYTHON_VERSION ($_req_ver) -- outside supported range"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$BEST_PY" ]; then
|
||||
# Collect candidate python3 binaries (python3, python3.9, python3.10, …)
|
||||
for candidate in $(compgen -c python3 2>/dev/null | grep -E '^python3(\.[0-9]+)?$' | sort -u); do
|
||||
if ! command -v "$candidate" &>/dev/null; then
|
||||
|
|
@ -206,7 +241,7 @@ for candidate in $(compgen -c python3 2>/dev/null | grep -E '^python3(\.[0-9]+)?
|
|||
continue
|
||||
fi
|
||||
|
||||
# Skip versions below 3.12 (require > 3.11)
|
||||
# Skip versions below 3.11
|
||||
if [ "$py_minor" -lt "$MIN_PY_MINOR" ] 2>/dev/null; then
|
||||
continue
|
||||
fi
|
||||
|
|
@ -219,11 +254,11 @@ for candidate in $(compgen -c python3 2>/dev/null | grep -E '^python3(\.[0-9]+)?
|
|||
# Keep the highest qualifying version
|
||||
if [ "$py_minor" -gt "$BEST_MINOR" ]; then
|
||||
BEST_PY="$candidate"
|
||||
BEST_MAJOR="$py_major"
|
||||
BEST_MINOR="$py_minor"
|
||||
fi
|
||||
done
|
||||
echo "finished finding best python"
|
||||
fi
|
||||
|
||||
if [ -z "$BEST_PY" ]; then
|
||||
echo "❌ ERROR: No Python version between 3.${MIN_PY_MINOR} and 3.${MAX_PY_MINOR} found on this system."
|
||||
echo " Detected Python 3 installations:"
|
||||
|
|
@ -402,7 +437,7 @@ rm -rf "$LLAMA_CPP_DIR"
|
|||
echo "Building llama-server for GGUF inference..."
|
||||
|
||||
BUILD_OK=true
|
||||
run_quiet "clone llama.cpp" git clone --depth 1 https://github.com/ggml-org/llama.cpp.git "$LLAMA_CPP_DIR" || BUILD_OK=false
|
||||
run_quiet_no_exit "clone llama.cpp" git clone --depth 1 https://github.com/ggml-org/llama.cpp.git "$LLAMA_CPP_DIR" || BUILD_OK=false
|
||||
|
||||
if [ "$BUILD_OK" = true ]; then
|
||||
# Skip tests/examples we don't need (faster build)
|
||||
|
|
@ -474,16 +509,16 @@ rm -rf "$LLAMA_CPP_DIR"
|
|||
CMAKE_GENERATOR_ARGS="-G Ninja"
|
||||
fi
|
||||
|
||||
run_quiet "cmake llama.cpp" cmake $CMAKE_GENERATOR_ARGS -S "$LLAMA_CPP_DIR" -B "$LLAMA_CPP_DIR/build" $CMAKE_ARGS || BUILD_OK=false
|
||||
run_quiet_no_exit "cmake llama.cpp" cmake $CMAKE_GENERATOR_ARGS -S "$LLAMA_CPP_DIR" -B "$LLAMA_CPP_DIR/build" $CMAKE_ARGS || BUILD_OK=false
|
||||
fi
|
||||
|
||||
if [ "$BUILD_OK" = true ]; then
|
||||
run_quiet "build llama-server" cmake --build "$LLAMA_CPP_DIR/build" --config Release --target llama-server -j"$NCPU" || BUILD_OK=false
|
||||
run_quiet_no_exit "build llama-server" cmake --build "$LLAMA_CPP_DIR/build" --config Release --target llama-server -j"$NCPU" || BUILD_OK=false
|
||||
fi
|
||||
|
||||
# Also build llama-quantize (needed by unsloth-zoo's GGUF export pipeline)
|
||||
if [ "$BUILD_OK" = true ]; then
|
||||
run_quiet "build llama-quantize" cmake --build "$LLAMA_CPP_DIR/build" --config Release --target llama-quantize -j"$NCPU" || true
|
||||
run_quiet_no_exit "build llama-quantize" cmake --build "$LLAMA_CPP_DIR/build" --config Release --target llama-quantize -j"$NCPU" || true
|
||||
# Symlink to llama.cpp root — check_llama_cpp() looks for the binary there
|
||||
QUANTIZE_BIN="$LLAMA_CPP_DIR/build/bin/llama-quantize"
|
||||
if [ -f "$QUANTIZE_BIN" ]; then
|
||||
|
|
|
|||
Loading…
Reference in a new issue